Compare commits

...

289 Commits
2.64c ... 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
130 changed files with 9877 additions and 5212 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
@ -73,13 +89,23 @@ 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
@ -150,18 +202,18 @@ ifdef NO_PYTHON
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
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
ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
ASAN_LDFLAGS+=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
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)
@ -169,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
@ -214,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 "=========================================="
@ -272,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
@ -304,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!)
@ -324,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
@ -401,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
@ -430,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
@ -440,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++" > $@
@ -475,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.64c](https://github.com/AFLplusplus/AFLplusplus/releases)
Release Version: [2.65c](https://github.com/AFLplusplus/AFLplusplus/releases)
Github Version: 2.64d
Github Version: 2.65d
includes all necessary/interesting changes from Google's afl 2.56b
@ -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
@ -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
```
@ -160,7 +160,8 @@ These build targets exist:
* 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)
@ -671,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)

23
TODO.md
View File

@ -1,24 +1,22 @@
# TODO list for AFL++
## Roadmap 2.65
## Roadmap 2.65+
- AFL_MAP_SIZE for afl-llvm-pass, qemu_mode and unicorn_mode
- fix stability calculation bug
- sync_fuzzers(): only masters sync from all, slaves only sync from master
(@andrea: be careful, often people run all slaves)
- AFL_MAP_SIZE for qemu_mode and unicorn_mode
- random crc32 HASH_CONST per run? because with 65536 paths we have collisions
- namespace for targets? e.g. network
- libradamsa as a custom module?
- focal for travis
## Further down the road
afl-fuzz:
- sync_fuzzers(): only masters sync from all, slaves only sync from master
(@andrea: be careful, often people run all slaves)
- ascii_only mode 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:
@ -26,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,51 @@ 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! :)
@ -141,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
@ -2532,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

@ -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
@ -113,6 +120,9 @@ Then there are a few specific features that are only available in llvm_mode:
afl-clang-lto/afl-clang-lto++ instead of afl-clang-fast, but is only
built if LLVM 11 or newer is used.
- AFL_LLVM_INSTRUMENT=CFG will use Control Flow Graph instrumentation.
(recommended)
- AFL_LLVM_LTO_AUTODICTIONARY will generate a dictionary in the target
binary based on string compare and memory compare functions.
afl-fuzz will automatically get these transmitted when starting to
@ -123,6 +133,10 @@ Then there are a few specific features that are only available in llvm_mode:
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
@ -132,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
@ -140,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
@ -200,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
@ -290,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

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

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

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

@ -123,11 +123,17 @@ static void edit_params(u32 argc, char **argv) {
u8 *alt_cxx = getenv("AFL_CXX");
cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)AFL_GCC_CXX;
} else {
} 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 {
fprintf(stderr, "Name of the binary: %s\n", argv[0]);
FATAL(
"Name of the binary is not a known name, expected afl-(gcc|g++)-fast");
}
char *fplugin_arg = alloc_printf("-fplugin=%s/afl-gcc-pass.so", obj_path);

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>

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 */
@ -229,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,
@ -281,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;
@ -321,9 +323,8 @@ typedef struct afl_env_vars {
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;
@ -405,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) */
@ -416,7 +419,6 @@ 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? */
@ -543,11 +545,9 @@ 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 */
@ -607,23 +607,23 @@ typedef struct afl_state {
u8 * ex_buf;
size_t ex_size;
u32 custom_mutators_count;
/* 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;
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
@ -799,22 +799,31 @@ struct custom_mutator {
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 load_custom_mutator_py(afl_state_t *, char *);
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 **);
@ -956,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];
}
@ -967,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,44 +41,44 @@
// 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. */
@ -87,7 +87,7 @@ static inline void *DFL_ck_alloc_nozero(u32 size) {
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);
@ -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;
@ -184,7 +184,7 @@ static inline void *DFL_ck_memdup(void *mem, u32 size) {
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

@ -28,26 +28,27 @@
#ifdef __ANDROID__
#include <fcntl.h>
#include <linux/shm.h>
#include <linux/ashmem.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <linux/shm.h>
#include <linux/ashmem.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#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>
#if __ANDROID_API__ >= 26
#define shmat bionic_shmat
#define shmctl bionic_shmctl
#define shmdt bionic_shmdt
#define shmget bionic_shmget
#endif
#define ASHMEM_DEVICE "/dev/ashmem"
#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) {
@ -105,7 +106,7 @@ static inline void *shmat(int __shmid, const void *__shmaddr, int __shmflg) {
}
#endif /* __ANDROID__ */
#endif /* __ANDROID__ */
#endif

View File

@ -115,7 +115,7 @@ u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms);
u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms,
volatile u8 *stop_soon_p);
u32 get_map_size();
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.64c"
#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): */
@ -395,19 +395,10 @@
/* 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__ */
/* Extended forkserver option values */
#define FS_OPT_ENABLED 0x8f000001
#define FS_OPT_MAPSIZE 0x40000000
#define FS_OPT_SNAPSHOT 0x20000000
#define FS_OPT_AUTODICT 0x10000000
#define FS_OPT_GET_MAPSIZE(x) (((x & 0x00fffffe) >> 1) + 1)
#define FS_OPT_SET_MAPSIZE(x) (x <= 1 || x > 0x1000000 ? 0 : ((x - 1) << 1))
#endif /* ! _HAVE_CONFIG_H */

View File

@ -30,7 +30,7 @@
/* __FUNCTION__ is non-iso */
#ifdef __func__
#define __FUNCTION__ __func__
#define __FUNCTION__ __func__
#endif
/*******************
@ -38,82 +38,82 @@
*******************/
#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 */
@ -123,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 */
@ -176,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

@ -32,6 +32,7 @@
#include <stdbool.h>
#include "types.h"
typedef struct afl_forkserver {
/* a program that includes afl-forkserver needs to define these */
@ -42,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 */
@ -108,20 +110,20 @@ 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

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

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

@ -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)" ""
@ -68,13 +68,14 @@ endif
ifeq "$(LLVM_MAJOR)" "11"
$(info [+] llvm_mode detected llvm 11, enabling afl-clang-lto LTO implementation)
LLVM_LTO = 1
TEST_MMAP = 1
endif
ifeq "$(LLVM_LTO)" "0"
$(info [+] llvm_mode detected llvm < 11, afl-clang-lto LTO will not be build.)
endif
ifeq "$(LLVM_APPLE)" "1"
ifeq "$(LLVM_APPLE_XCODE)" "1"
$(warning llvm_mode will not compile with Xcode clang...)
endif
@ -82,30 +83,79 @@ endif
# this seems to be busted on some distros, so using the one in $PATH is
# probably better.
CC ?= $(LLVM_BINDIR)/clang
CXX ?= $(LLVM_BINDIR)/clang++
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
@ -114,13 +164,13 @@ 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
@ -141,32 +191,20 @@ 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
CLANG_BIN = $(basename $(CC))
CLANGPP_BIN = $(basename $(CXX))
ifeq "$(shell test -e $(CLANG_BIN) || echo 1 )" "1"
CLANG_BIN = $(CC)
CLANGPP_BIN = $(CXX)
endif
ifeq "$(CC)" "$(LLVM_BINDIR)/clang"
USE_BINDIR = 1
else
USE_BINDIR = 0
endif
CFLAGS ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2
override CFLAGS += -Wall \
-g -Wno-pointer-sign -I ../include/ \
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
-DLLVM_BINDIR=\"$(LLVM_BINDIR)\" -DVERSION=\"$(VERSION)\" \
-DLLVM_VERSION=\"$(LLVMVER)\" -DAFL_CLANG_FLTO=\"$(AFL_CLANG_FLTO)\" \
-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=\"$(CC)\" -DCLANGPP_BIN=\"$(CXX)\" -DUSE_BINDIR=$(USE_BINDIR) -Wno-unused-function
-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
@ -175,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"
@ -193,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-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
@ -241,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)'..."
@ -249,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
@ -261,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"
@ -270,42 +309,50 @@ ifeq "$(LLVM_LTO)" "1"
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
../afl-llvm-lto-instrumentation.so: afl-llvm-lto-instrumentation.so.cc afl-llvm-common.o
ifeq "$(LLVM_LTO)" "1"
$(CXX) $(CLANG_CFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL)
$(CC) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto.o
@$(CC) $(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
@$(CC) $(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
$(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) -Wno-unused-result -fPIC -c $< -o $@
@ -320,7 +367,7 @@ endif
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
@ -335,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 ]; 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-rt-lto*.o ../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

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

@ -6,6 +6,8 @@ This version requires a current llvm 11 compiled from the github master.
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)
2. You can use it together with llvm_mode: laf-intel and whitelisting
features and can be combined with cmplog/Redqueen
@ -14,6 +16,11 @@ This version requires a current llvm 11 compiled from the github master.
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
@ -41,7 +48,7 @@ and many dead ends until we got to this:
-fsanitize=coverage edge coverage mode :)
The result:
* 10-20% 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
@ -65,7 +72,7 @@ $ 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/llcm-config
$ export LLVM_CONFIG=`pwd`/bin/llvm-config
$ cd /path/to/AFLplusplus/
$ make
$ cd llvm_mode
@ -80,11 +87,13 @@ 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
```
@ -95,6 +104,17 @@ 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
@ -110,14 +130,36 @@ 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 ...
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.
Please report issues at:
Known issues:
* 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 instrument main,

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", ""
};
@ -169,7 +170,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
else
++name;
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 "
@ -183,6 +184,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
else
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") ||
@ -204,12 +206,18 @@ static void edit_params(u32 argc, char **argv, char **envp) {
}
/* 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
@ -226,8 +234,7 @@ 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") &&
instrument_mode != INSTRUMENT_LTO)
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 "
@ -280,7 +287,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
}
if (instrument_mode == INSTRUMENT_LTO) {
if (lto_mode) {
if (getenv("AFL_LLVM_WHITELIST") != NULL) {
@ -294,8 +301,12 @@ static void edit_params(u32 argc, char **argv, char **envp) {
cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", AFL_REAL_LD);
cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition";
cc_params[cc_par_cnt++] = alloc_printf(
"-Wl,-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", obj_path);
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 {
@ -322,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) {
@ -390,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)
@ -416,9 +443,8 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (getenv("AFL_NO_BUILTIN") || getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES") ||
getenv("LAF_TRANSFORM_COMPARES") ||
(instrument_mode == INSTRUMENT_LTO &&
(getenv("AFL_LLVM_LTO_AUTODICTIONARY") ||
getenv("AFL_LLVM_AUTODICTIONARY")))) {
(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";
@ -499,7 +525,7 @@ 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 (instrument_mode == INSTRUMENT_LTO)
if (lto_mode)
cc_params[cc_par_cnt++] =
alloc_printf("%s/afl-llvm-rt-lto.o", obj_path);
break;
@ -508,7 +534,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
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 (instrument_mode == INSTRUMENT_LTO) {
if (lto_mode) {
cc_params[cc_par_cnt++] =
alloc_printf("%s/afl-llvm-rt-lto-32.o", obj_path);
@ -523,7 +549,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
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 (instrument_mode == INSTRUMENT_LTO) {
if (lto_mode) {
cc_params[cc_par_cnt++] =
alloc_printf("%s/afl-llvm-rt-lto-64.o", obj_path);
@ -547,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")) {
@ -562,54 +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, "default", strlen("default")) == 0 ||
strncasecmp(ptr, "afl", strlen("afl")) == 0 ||
strncasecmp(ptr, "classic", strlen("classic")) == 0)
instrument_mode = INSTRUMENT_DEFAULT;
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")) {
@ -631,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
@ -726,6 +818,7 @@ int main(int argc, char **argv, char **envp) {
"AFL_HARDEN: adds code hardening to catch memory bugs\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_FLOATS: transform floating point comp. to "
"cascaded "
@ -751,14 +844,14 @@ int main(int argc, char **argv, char **envp) {
"\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"
"(INSTRIM), PCGUARD, LTO, CTX, NGRAM-2 ... NGRAM-16\n"
" You can also use the old environment variables instead:"
" 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");
"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(
@ -787,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",
@ -802,7 +895,7 @@ int main(int argc, char **argv, char **envp) {
}
u8 *ptr2;
if (!be_quiet && instrument_mode != INSTRUMENT_LTO &&
if (!be_quiet && !lto_mode &&
((ptr2 = getenv("AFL_MAP_SIZE")) || (ptr2 = getenv("AFL_MAPSIZE")))) {
u32 map_size = atoi(ptr2);

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,9 +12,7 @@
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.
*/
@ -31,11 +24,13 @@
#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"
#include "llvm/ADT/Statistic.h"
@ -55,7 +50,7 @@
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Pass.h"
#include <set>
#include "afl-llvm-common.h"
using namespace llvm;
@ -76,6 +71,8 @@ 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");
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
@ -86,74 +83,14 @@ class AFLLTOPass : public ModulePass {
}
// 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, 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;
};
@ -165,11 +102,11 @@ bool AFLLTOPass::runOnModule(Module &M) {
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);
if (getenv("AFL_DEBUG")) debug = 1;
IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
/* Show a banner */
@ -186,12 +123,65 @@ bool AFLLTOPass::runOnModule(Module &M) {
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);
@ -202,7 +192,9 @@ 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;
std::vector<BasicBlock *> InsBlocks;
@ -339,11 +331,15 @@ bool AFLLTOPass::runOnModule(Module &M) {
if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
if (auto *Array =
dyn_cast<ConstantDataArray>(Var->getInitializer())) {
if (Var->hasInitializer()) {
HasStr2 = true;
Str2 = Array->getAsString().str();
if (auto *Array = dyn_cast<ConstantDataArray>(
Var->getInitializer())) {
HasStr2 = true;
Str2 = Array->getAsString().str();
}
}
@ -411,11 +407,15 @@ bool AFLLTOPass::runOnModule(Module &M) {
if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
if (auto *Array =
dyn_cast<ConstantDataArray>(Var->getInitializer())) {
if (Var->hasInitializer()) {
HasStr1 = true;
Str1 = Array->getAsString().str();
if (auto *Array = dyn_cast<ConstantDataArray>(
Var->getInitializer())) {
HasStr1 = true;
Str1 = Array->getAsString().str();
}
}
@ -579,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 */
@ -592,9 +602,14 @@ bool AFLLTOPass::runOnModule(Module &M) {
Value *Incr = IRB.CreateAdd(Counter, One);
auto cf = IRB.CreateICmpEQ(Incr, Zero);
auto carry = IRB.CreateZExt(cf, Int8Ty);
Incr = IRB.CreateAdd(Incr, carry);
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));
@ -612,7 +627,8 @@ bool AFLLTOPass::runOnModule(Module &M) {
// save highest location ID to global variable
// do this after each function to fail faster
if (!be_quiet && afl_global_id > MAP_SIZE) {
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))
@ -627,7 +643,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
}
if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL || dictionary.size()) {
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
@ -656,24 +672,29 @@ bool AFLLTOPass::runOnModule(Module &M) {
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);
if (write_loc <= MAP_SIZE && write_loc <= 0x800000) {
GlobalVariable *AFLFinalLoc = new GlobalVariable(
M, Int32Ty, true, GlobalValue::ExternalLinkage, 0,
"__afl_final_loc", 0, GlobalVariable::GeneralDynamicTLSModel, 0,
false);
ConstantInt *const_loc = ConstantInt::get(Int32Ty, write_loc);
StoreInst * StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc);
StoreFinalLoc->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
}
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));
}
@ -718,10 +739,9 @@ bool AFLLTOPass::runOnModule(Module &M) {
}
GlobalVariable *AFLDictionaryLen = new GlobalVariable(
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0,
"__afl_dictionary_len", 0, GlobalVariable::GeneralDynamicTLSModel,
0, false);
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"),
@ -732,8 +752,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
M, ArrayTy, true, GlobalValue::ExternalLinkage,
ConstantDataArray::get(C,
*(new ArrayRef<char>((char *)ptr, offset))),
"__afl_internal_dictionary", 0,
GlobalVariable::GeneralDynamicTLSModel, 0, false);
"__afl_internal_dictionary");
AFLInternalDictionary->setInitializer(ConstantDataArray::get(
C, *(new ArrayRef<char>((char *)ptr, offset))));
AFLInternalDictionary->setConstant(true);

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,60 +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;
uint32_t map_size = MAP_SIZE;
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;
};
@ -156,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) {
@ -222,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");
@ -247,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;
@ -257,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. */
@ -281,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__
@ -336,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;
}
@ -455,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));
}
@ -562,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;
@ -586,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 */
@ -604,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));
@ -620,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
@ -630,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));
@ -713,6 +537,23 @@ 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++;
}
@ -756,8 +597,7 @@ bool AFLCoverage::runOnModule(Module &M) {
GlobalVariable *AFLFinalLoc = new GlobalVariable(
M, Int32Ty, true, GlobalValue::ExternalLinkage, 0,
"__afl_final_loc", 0, GlobalVariable::GeneralDynamicTLSModel, 0,
false);
"__afl_final_loc");
ConstantInt *const_loc = ConstantInt::get(Int32Ty, map_size);
StoreInst * StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc);
StoreFinalLoc->setMetadata(M.getMDKindID("nosanitize"),

View File

@ -10,6 +10,9 @@
*/
#include <stdio.h>
#include <stdlib.h>
// to prevent the function from being removed
unsigned char __afl_lto_mode = 0;
@ -17,6 +20,7 @@ unsigned char __afl_lto_mode = 0;
__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,7 +43,7 @@
#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.
@ -52,6 +52,10 @@
#define CONST_PRIO 5
#ifndef MAP_FIXED_NOREPLACE
#define MAP_FIXED_NOREPLACE MAP_FIXED
#endif
#include <sys/mman.h>
#include <fcntl.h>
@ -59,22 +63,27 @@
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;
u32 __afl_dictionary_len;
#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;
__thread u32 __afl_dictionary_len;
#endif
struct cmp_map *__afl_cmp_map;
@ -83,44 +92,113 @@ 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
const char * shm_file_path = id_str;
int shm_fd = -1;
unsigned char *shm_base = NULL;
unsigned int map_size = MAP_SIZE
if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE) map_size =
__afl_final_loc;
/* 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, 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);
}
@ -129,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);
@ -193,13 +293,9 @@ static void __afl_start_snapshots(void) {
static u8 tmp[4] = {0, 0, 0, 0};
s32 child_pid;
u32 status = 0;
u32 map_size = MAP_SIZE;
u32 already_read_first = 0;
u32 was_killed;
if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE)
map_size = __afl_final_loc;
u8 child_stopped = 0;
void (*old_sigchld_handler)(int) = 0; // = signal(SIGCHLD, SIG_DFL);
@ -208,8 +304,8 @@ static void __afl_start_snapshots(void) {
assume we're not running in forkserver mode and just execute program. */
status |= (FS_OPT_ENABLED | FS_OPT_SNAPSHOT);
if (map_size <= 0x800000)
status |= (FS_OPT_SET_MAPSIZE(map_size) | FS_OPT_MAPSIZE);
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);
@ -362,19 +458,15 @@ static void __afl_start_forkserver(void) {
u8 tmp[4] = {0, 0, 0, 0};
s32 child_pid;
u32 status = 0;
u32 map_size = MAP_SIZE;
u32 already_read_first = 0;
u32 was_killed;
if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE)
map_size = __afl_final_loc;
u8 child_stopped = 0;
void (*old_sigchld_handler)(int) = 0; // = signal(SIGCHLD, SIG_DFL);
if (map_size <= 0x800000)
status |= (FS_OPT_SET_MAPSIZE(map_size) | FS_OPT_MAPSIZE);
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);
@ -512,12 +604,8 @@ static void __afl_start_forkserver(void) {
int __afl_persistent_loop(unsigned int max_cnt) {
static u8 first_pass = 1;
static u32 cycle_cnt;
unsigned int map_size = MAP_SIZE;
if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE)
map_size = __afl_final_loc;
static u8 first_pass = 1;
static u32 cycle_cnt;
if (first_pass) {
@ -528,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));
@ -738,15 +826,15 @@ void __cmplog_ins_hook8(uint64_t arg1, uint64_t 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)
__attribute__((alias("__cmplog_ins_hook1")));

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,
@ -140,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;
@ -335,20 +210,24 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
}
// not literal? maybe global or local variable
if (!(HasStr1 ^ HasStr2)) {
if (!(HasStr1 || HasStr2)) {
auto *Ptr = dyn_cast<ConstantExpr>(Str2P);
if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
if (auto *Array =
dyn_cast<ConstantDataArray>(Var->getInitializer())) {
if (Var->hasInitializer()) {
HasStr2 = true;
Str2 = Array->getAsString();
valueMap[Str2P] = new std::string(Str2.str());
// fprintf(stderr, "glo2 %s\n", Str2.str().c_str());
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());
}
}
@ -363,13 +242,17 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
if (auto *Array =
dyn_cast<ConstantDataArray>(Var->getInitializer())) {
if (Var->hasInitializer()) {
HasStr1 = true;
Str1 = Array->getAsString();
valueMap[Str1P] = new std::string(Str1.str());
// fprintf(stderr, "glo1 %s\n", Str1.str().c_str());
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());
}
}
@ -384,13 +267,13 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
}
if ((HasStr1 ^ HasStr2)) indirect = true;
if ((HasStr1 || HasStr2)) indirect = true;
}
if (isIntMemcpy) continue;
if (!(HasStr1 ^ HasStr2)) {
if (!(HasStr1 || HasStr2)) {
// do we have a saved local variable initialization?
std::string *val = valueMap[Str1P];
@ -418,7 +301,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
}
/* handle cases of one string is const, one string is variable */
if (!(HasStr1 ^ HasStr2)) continue;
if (!(HasStr1 || HasStr2)) continue;
if (isMemcmp || isStrncmp || isStrncasecmp) {
@ -483,7 +366,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
}
if (!(HasStr1 ^ HasStr2)) {
if (!(HasStr1 || HasStr2)) {
// do we have a saved local or global variable initialization?
std::string *val = valueMap[Str1P];
@ -510,13 +393,13 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
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();
}
@ -524,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
@ -617,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

@ -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,7 +249,7 @@ 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
@ -269,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,20 +274,6 @@ 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) {
@ -299,7 +284,7 @@ void afl_forkserver(CPUState *cpu) {
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

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,
@ -55,11 +55,20 @@ static void afl_gen_compcov(target_ulong cur_loc, TCGv arg1, TCGv arg2,
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;
case MO_8: gen_helper_afl_cmplog_8(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;
}
@ -78,10 +87,17 @@ static void afl_gen_compcov(target_ulong cur_loc, TCGv arg1, TCGv arg2,
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

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

@ -25,10 +25,10 @@ all: $(TARGETS)
@if [ "$(AFL_NO_X86)" != "" ]; then echo "[!] Note: skipping compilation of unsigaction (AFL_NO_X86 set)."; fi
unsigaction32.so:
@$(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
@if $(CC) -m32 -fPIC -shared unsigaction.c -o unsigaction32.so 2>/dev/null ; then echo "unsigaction32 build success"; else echo "unsigaction32 build failure (that's fine)"; fi
unsigaction64.so:
$(CC) -m64 -fPIC -shared unsigaction.c -o unsigaction64.so
@if $(CC) -m64 -fPIC -shared unsigaction.c -o unsigaction64.so 2>/dev/null ; then echo "unsigaction64 build success"; else echo "unsigaction64 build failure (that's fine)"; fi
clean:
rm -f unsigaction32.so unsigaction64.so

View File

@ -27,7 +27,7 @@
#define AFL_MAIN
#ifdef __ANDROID__
#include "android-ashmem.h"
#include "android-ashmem.h"
#endif
#include "config.h"
#include "types.h"
@ -122,7 +122,7 @@ static void classify_counts(u8 *mem) {
while (i--) {
if (*mem) *mem = 1;
if (*mem) { *mem = 1; }
mem++;
}
@ -147,8 +147,11 @@ static inline u8 anything_set(void) {
u32 *ptr = (u32 *)trace_bits;
u32 i = (map_size >> 2);
while (i--)
if (*(ptr++)) return 1;
while (i--) {
if (*(ptr++)) { return 1; }
}
return 0;
@ -169,13 +172,16 @@ static void read_initial_file(void) {
struct stat st;
s32 fd = open(in_file, O_RDONLY);
if (fd < 0) PFATAL("Unable to open '%s'", in_file);
if (fd < 0) { PFATAL("Unable to open '%s'", in_file); }
if (fstat(fd, &st) || !st.st_size) FATAL("Zero-sized input file.");
if (fstat(fd, &st) || !st.st_size) { FATAL("Zero-sized input file."); }
if (st.st_size >= TMIN_MAX_FILE) {
if (st.st_size >= TMIN_MAX_FILE)
FATAL("Input file is too large (%u MB max)", TMIN_MAX_FILE / 1024 / 1024);
}
in_len = st.st_size;
in_data = ck_alloc_nozero(in_len);
@ -197,7 +203,7 @@ static s32 write_to_file(u8 *path, u8 *mem, u32 len) {
ret = open(path, O_RDWR | O_CREAT | O_EXCL, 0600);
if (ret < 0) PFATAL("Unable to create '%s'", path);
if (ret < 0) { PFATAL("Unable to create '%s'", path); }
ck_write(ret, mem, len, path);
@ -225,7 +231,7 @@ static u32 analyze_run_target(char **argv, u8 *mem, u32 len, u8 first_run) {
child_pid = fork();
if (child_pid < 0) PFATAL("fork() failed");
if (child_pid < 0) { PFATAL("fork() failed"); }
if (!child_pid) {
@ -278,7 +284,7 @@ static u32 analyze_run_target(char **argv, u8 *mem, u32 len, u8 first_run) {
setitimer(ITIMER_REAL, &it, NULL);
if (waitpid(child_pid, &status, 0) <= 0) FATAL("waitpid() failed");
if (waitpid(child_pid, &status, 0) <= 0) { FATAL("waitpid() failed"); }
child_pid = 0;
it.it_value.tv_sec = 0;
@ -290,9 +296,12 @@ static u32 analyze_run_target(char **argv, u8 *mem, u32 len, u8 first_run) {
/* Clean up bitmap, analyze exit condition, etc. */
if (*(u32 *)trace_bits == EXEC_FAIL_SIG)
if (*(u32 *)trace_bits == EXEC_FAIL_SIG) {
FATAL("Unable to execute '%s'", argv[0]);
}
classify_counts(trace_bits);
total_execs++;
@ -325,7 +334,7 @@ static u32 analyze_run_target(char **argv, u8 *mem, u32 len, u8 first_run) {
}
if (first_run) orig_cksum = cksum;
if (first_run) { orig_cksum = cksum; }
return cksum;
@ -340,9 +349,12 @@ static void show_char(u8 val) {
switch (val) {
case 0 ... 32:
case 127 ... 255: SAYF("#%02x", val); break;
case 127 ... 255:
SAYF("#%02x", val);
break;
default: SAYF(" %c ", val);
default:
SAYF(" %c ", val);
}
@ -387,7 +399,12 @@ static void dump_hex(u8 *buf, u32 len, u8 *b_data) {
while (i + rlen < len && (b_data[i] >> 7) == (b_data[i + rlen] >> 7)) {
if (rtype < (b_data[i + rlen] & 0x0f)) rtype = b_data[i + rlen] & 0x0f;
if (rtype < (b_data[i + rlen] & 0x0f)) {
rtype = b_data[i + rlen] & 0x0f;
}
rlen++;
}
@ -454,9 +471,11 @@ static void dump_hex(u8 *buf, u32 len, u8 *b_data) {
case 1:
case 3:
case 5 ... MAX_AUTO_EXTRA - 1: break;
case 5 ... MAX_AUTO_EXTRA - 1:
break;
default: rtype = RESP_SUSPECT;
default:
rtype = RESP_SUSPECT;
}
@ -472,34 +491,58 @@ static void dump_hex(u8 *buf, u32 len, u8 *b_data) {
if (!((i + off) % 16)) {
if (off) SAYF(cRST cLCY ">");
if (off) { SAYF(cRST cLCY ">"); }
if (use_hex_offsets) {
if (use_hex_offsets)
SAYF(cRST cGRA "%s[%06x] " cRST, (i + off) ? "\n" : "", i + off);
else
} else {
SAYF(cRST cGRA "%s[%06u] " cRST, (i + off) ? "\n" : "", i + off);
}
}
switch (rtype) {
case RESP_NONE: SAYF(cLGR bgGRA); break;
case RESP_MINOR: SAYF(cBRI bgGRA); break;
case RESP_VARIABLE: SAYF(cBLK bgCYA); break;
case RESP_FIXED: SAYF(cBLK bgMGN); break;
case RESP_LEN: SAYF(cBLK bgLGN); break;
case RESP_CKSUM: SAYF(cBLK bgYEL); break;
case RESP_SUSPECT: SAYF(cBLK bgLRD); break;
case RESP_NONE:
SAYF(cLGR bgGRA);
break;
case RESP_MINOR:
SAYF(cBRI bgGRA);
break;
case RESP_VARIABLE:
SAYF(cBLK bgCYA);
break;
case RESP_FIXED:
SAYF(cBLK bgMGN);
break;
case RESP_LEN:
SAYF(cBLK bgLGN);
break;
case RESP_CKSUM:
SAYF(cBLK bgYEL);
break;
case RESP_SUSPECT:
SAYF(cBLK bgLRD);
break;
}
show_char(in_data[i + off]);
if (off != rlen - 1 && (i + off + 1) % 16)
if (off != rlen - 1 && (i + off + 1) % 16) {
SAYF(" ");
else
} else {
SAYF(cRST " ");
}
}
#else
@ -511,13 +554,27 @@ static void dump_hex(u8 *buf, u32 len, u8 *b_data) {
switch (rtype) {
case RESP_NONE: SAYF("no-op block\n"); break;
case RESP_MINOR: SAYF("superficial content\n"); break;
case RESP_VARIABLE: SAYF("critical stream\n"); break;
case RESP_FIXED: SAYF("\"magic value\" section\n"); break;
case RESP_LEN: SAYF("suspected length field\n"); break;
case RESP_CKSUM: SAYF("suspected cksum or magic int\n"); break;
case RESP_SUSPECT: SAYF("suspected checksummed block\n"); break;
case RESP_NONE:
SAYF("no-op block\n");
break;
case RESP_MINOR:
SAYF("superficial content\n");
break;
case RESP_VARIABLE:
SAYF("critical stream\n");
break;
case RESP_FIXED:
SAYF("\"magic value\" section\n");
break;
case RESP_LEN:
SAYF("suspected length field\n");
break;
case RESP_CKSUM:
SAYF("suspected cksum or magic int\n");
break;
case RESP_SUSPECT:
SAYF("suspected checksummed block\n");
break;
}
@ -594,16 +651,21 @@ static void analyze(char **argv) {
b_data[i] = RESP_FIXED;
} else
} else {
b_data[i] = RESP_VARIABLE;
}
/* When all checksums change, flip most significant bit of b_data. */
if (prev_xff != xor_ff && prev_x01 != xor_01 && prev_s10 != sub_10 &&
prev_a10 != add_10)
prev_a10 != add_10) {
seq_byte ^= 0x80;
}
b_data[i] |= seq_byte;
prev_xff = xor_ff;
@ -620,10 +682,13 @@ static void analyze(char **argv) {
OKF("Analysis complete. Interesting bits: %0.02f%% of the input file.",
100.0 - ((double)boring_len * 100) / in_len);
if (exec_hangs)
if (exec_hangs) {
WARNF(cLRD "Encountered %u timeouts - results may be skewed." cRST,
exec_hangs);
}
ck_free(b_data);
}
@ -634,7 +699,7 @@ static void handle_stop_sig(int sig) {
stop_soon = 1;
if (child_pid > 0) kill(child_pid, SIGKILL);
if (child_pid > 0) { kill(child_pid, SIGKILL); }
}
@ -645,7 +710,7 @@ static void set_up_environment(void) {
u8 *x;
dev_null_fd = open("/dev/null", O_RDWR);
if (dev_null_fd < 0) PFATAL("Unable to open /dev/null");
if (dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
if (!prog_in) {
@ -654,11 +719,11 @@ static void set_up_environment(void) {
if (access(use_dir, R_OK | W_OK | X_OK)) {
use_dir = get_afl_env("TMPDIR");
if (!use_dir) use_dir = "/tmp";
if (!use_dir) { use_dir = "/tmp"; }
}
prog_in = alloc_printf("%s/.afl-analyze-temp-%u", use_dir, getpid());
prog_in = alloc_printf("%s/.afl-analyze-temp-%u", use_dir, (u32)getpid());
}
@ -668,25 +733,37 @@ static void set_up_environment(void) {
if (x) {
if (!strstr(x, "abort_on_error=1"))
if (!strstr(x, "abort_on_error=1")) {
FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!");
if (!strstr(x, "symbolize=0"))
}
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)))
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"))
}
if (!strstr(x, "symbolize=0")) {
FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!");
}
}
setenv("ASAN_OPTIONS",
@ -713,20 +790,28 @@ static void set_up_environment(void) {
s32 i, afl_preload_size = strlen(afl_preload);
for (i = 0; i < afl_preload_size; ++i) {
if (afl_preload[i] == ',')
if (afl_preload[i] == ',') {
PFATAL(
"Comma (',') is not allowed in AFL_PRELOAD when -Q is "
"specified!");
}
}
if (qemu_preload)
if (qemu_preload) {
buf = alloc_printf("%s,LD_PRELOAD=%s,DYLD_INSERT_LIBRARIES=%s",
qemu_preload, afl_preload, afl_preload);
else
} else {
buf = alloc_printf("LD_PRELOAD=%s,DYLD_INSERT_LIBRARIES=%s",
afl_preload, afl_preload);
}
setenv("QEMU_SET_ENV", buf, 1);
ck_free(buf);
@ -820,26 +905,26 @@ int main(int argc, char **argv, char **envp) {
SAYF(cCYA "afl-analyze" VERSION cRST " by Michal Zalewski\n");
while ((opt = getopt(argc, argv, "+i:f:m:t:eQUWh")) > 0)
while ((opt = getopt(argc, argv, "+i:f:m:t:eQUWh")) > 0) {
switch (opt) {
case 'i':
if (in_file) FATAL("Multiple -i options not supported");
if (in_file) { FATAL("Multiple -i options not supported"); }
in_file = optarg;
break;
case 'f':
if (prog_in) FATAL("Multiple -f options not supported");
if (prog_in) { FATAL("Multiple -f options not supported"); }
use_stdin = 0;
prog_in = optarg;
break;
case 'e':
if (edges_only) FATAL("Multiple -e options not supported");
if (edges_only) { FATAL("Multiple -e options not supported"); }
edges_only = 1;
break;
@ -847,7 +932,7 @@ int main(int argc, char **argv, char **envp) {
u8 suffix = 'M';
if (mem_limit_given) FATAL("Multiple -m options not supported");
if (mem_limit_given) { FATAL("Multiple -m options not supported"); }
mem_limit_given = 1;
if (!optarg) { FATAL("Wrong usage of -m"); }
@ -860,66 +945,83 @@ int main(int argc, char **argv, char **envp) {
}
if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 ||
optarg[0] == '-')
optarg[0] == '-') {
FATAL("Bad syntax used for -m");
switch (suffix) {
case 'T': mem_limit *= 1024 * 1024; break;
case 'G': mem_limit *= 1024; break;
case 'k': mem_limit /= 1024; break;
case 'M': break;
default: FATAL("Unsupported suffix or bad syntax for -m");
}
if (mem_limit < 5) FATAL("Dangerously low value of -m");
switch (suffix) {
case 'T':
mem_limit *= 1024 * 1024;
break;
case 'G':
mem_limit *= 1024;
break;
case 'k':
mem_limit /= 1024;
break;
case 'M':
break;
default:
FATAL("Unsupported suffix or bad syntax for -m");
}
if (mem_limit < 5) { FATAL("Dangerously low value of -m"); }
if (sizeof(rlim_t) == 4 && mem_limit > 2000) {
if (sizeof(rlim_t) == 4 && mem_limit > 2000)
FATAL("Value of -m out of range on 32-bit systems");
}
}
break;
case 't':
if (timeout_given) FATAL("Multiple -t options not supported");
if (timeout_given) { FATAL("Multiple -t options not supported"); }
timeout_given = 1;
if (!optarg) FATAL("Wrong usage of -t");
if (!optarg) { FATAL("Wrong usage of -t"); }
exec_tmout = atoi(optarg);
if (exec_tmout < 10 || optarg[0] == '-')
if (exec_tmout < 10 || optarg[0] == '-') {
FATAL("Dangerously low value of -t");
}
break;
case 'Q':
if (qemu_mode) FATAL("Multiple -Q options not supported");
if (!mem_limit_given) mem_limit = MEM_LIMIT_QEMU;
if (qemu_mode) { FATAL("Multiple -Q options not supported"); }
if (!mem_limit_given) { mem_limit = MEM_LIMIT_QEMU; }
qemu_mode = 1;
break;
case 'U':
if (unicorn_mode) FATAL("Multiple -U options not supported");
if (!mem_limit_given) mem_limit = MEM_LIMIT_UNICORN;
if (unicorn_mode) { FATAL("Multiple -U options not supported"); }
if (!mem_limit_given) { mem_limit = MEM_LIMIT_UNICORN; }
unicorn_mode = 1;
break;
case 'W': /* Wine+QEMU mode */
if (use_wine) FATAL("Multiple -W options not supported");
if (use_wine) { FATAL("Multiple -W options not supported"); }
qemu_mode = 1;
use_wine = 1;
if (!mem_limit_given) mem_limit = 0;
if (!mem_limit_given) { mem_limit = 0; }
break;
@ -928,11 +1030,14 @@ int main(int argc, char **argv, char **envp) {
return -1;
break;
default: usage(argv[0]);
default:
usage(argv[0]);
}
if (optind == argc || !in_file) usage(argv[0]);
}
if (optind == argc || !in_file) { usage(argv[0]); }
map_size = get_map_size();
@ -952,17 +1057,24 @@ int main(int argc, char **argv, char **envp) {
if (qemu_mode) {
if (use_wine)
if (use_wine) {
use_argv =
get_wine_argv(argv[0], &target_path, argc - optind, argv + optind);
else
} else {
use_argv =
get_qemu_argv(argv[0], &target_path, argc - optind, argv + optind);
} else
}
} else {
use_argv = argv + optind;
}
SAYF("\n");
read_initial_file();
@ -972,17 +1084,23 @@ int main(int argc, char **argv, char **envp) {
analyze_run_target(use_argv, in_data, in_len, 1);
if (child_timed_out)
if (child_timed_out) {
FATAL("Target binary times out (adjusting -t may help).");
if (get_afl_env("AFL_SKIP_BIN_CHECK") == NULL && !anything_set())
}
if (get_afl_env("AFL_SKIP_BIN_CHECK") == NULL && !anything_set()) {
FATAL("No instrumentation detected.");
}
analyze(use_argv);
OKF("We're done here. Have a nice day!\n");
if (target_path) ck_free(target_path);
if (target_path) { ck_free(target_path); }
afl_shm_deinit(&shm);

View File

@ -79,9 +79,9 @@ static u8 use_64bit = 1;
static u8 use_64bit = 0;
#ifdef __APPLE__
#error "Sorry, 32-bit Apple platforms are not supported."
#endif /* __APPLE__ */
#ifdef __APPLE__
#error "Sorry, 32-bit Apple platforms are not supported."
#endif /* __APPLE__ */
#endif /* ^WORD_SIZE_64 */
@ -126,9 +126,9 @@ static void edit_params(int argc, char **argv) {
is not set. We need to check these non-standard variables to properly
handle the pass_thru logic later on. */
if (!tmp_dir) tmp_dir = getenv("TEMP");
if (!tmp_dir) tmp_dir = getenv("TMP");
if (!tmp_dir) tmp_dir = "/tmp";
if (!tmp_dir) { tmp_dir = getenv("TEMP"); }
if (!tmp_dir) { tmp_dir = getenv("TMP"); }
if (!tmp_dir) { tmp_dir = "/tmp"; }
as_params = ck_alloc((argc + 32) * sizeof(u8 *));
@ -138,11 +138,16 @@ static void edit_params(int argc, char **argv) {
for (i = 1; i < argc - 1; i++) {
if (!strcmp(argv[i], "--64"))
if (!strcmp(argv[i], "--64")) {
use_64bit = 1;
else if (!strcmp(argv[i], "--32"))
} else if (!strcmp(argv[i], "--32")) {
use_64bit = 0;
}
#ifdef __APPLE__
/* The Apple case is a bit different... */
@ -195,11 +200,16 @@ static void edit_params(int argc, char **argv) {
}
if (input_file[1])
if (input_file[1]) {
FATAL("Incorrect use (not called through afl-gcc?)");
else
} else {
input_file = NULL;
}
} else {
/* Check if this looks like a standard invocation as a part of an attempt
@ -210,15 +220,20 @@ static void edit_params(int argc, char **argv) {
if (strncmp(input_file, tmp_dir, strlen(tmp_dir)) &&
strncmp(input_file, "/var/tmp/", 9) &&
strncmp(input_file, "/tmp/", 5) &&
getenv("AFL_AS_FORCE_INSTRUMENT") == NULL)
getenv("AFL_AS_FORCE_INSTRUMENT") == NULL) {
pass_thru = 1;
else if (getenv("AFL_AS_FORCE_INSTRUMENT"))
} else if (getenv("AFL_AS_FORCE_INSTRUMENT")) {
unsetenv("AFL_AS_FORCE_INSTRUMENT");
}
}
modified_file =
alloc_printf("%s/.afl-%u-%u.s", tmp_dir, getpid(), (u32)time(NULL));
alloc_printf("%s/.afl-%u-%u.s", tmp_dir, (u32)getpid(), (u32)time(NULL));
wrap_things_up:
@ -251,19 +266,21 @@ static void add_instrumentation(void) {
if (input_file) {
inf = fopen(input_file, "r");
if (!inf) PFATAL("Unable to read '%s'", input_file);
if (!inf) { PFATAL("Unable to read '%s'", input_file); }
} else
} else {
inf = stdin;
}
outfd = open(modified_file, O_WRONLY | O_EXCL | O_CREAT, 0600);
if (outfd < 0) PFATAL("Unable to write to '%s'", modified_file);
if (outfd < 0) { PFATAL("Unable to write to '%s'", modified_file); }
outf = fdopen(outfd, "w");
if (!outf) PFATAL("fdopen() failed");
if (!outf) { PFATAL("fdopen() failed"); }
while (fgets(line, MAX_LINE, inf)) {
@ -287,7 +304,7 @@ static void add_instrumentation(void) {
fputs(line, outf);
if (pass_thru) continue;
if (pass_thru) { continue; }
/* All right, this is where the actual fun begins. For one, we only want to
instrument the .text section. So, let's keep track of that in processed
@ -300,9 +317,12 @@ static void add_instrumentation(void) {
around them, so we use that as a signal. */
if (!clang_mode && instr_ok && !strncmp(line + 2, "p2align ", 8) &&
isdigit(line[10]) && line[11] == '\n')
isdigit(line[10]) && line[11] == '\n') {
skip_next_label = 1;
}
if (!strncmp(line + 2, "text\n", 5) ||
!strncmp(line + 2, "section\t.text", 13) ||
!strncmp(line + 2, "section\t__TEXT,__text", 21) ||
@ -330,23 +350,23 @@ static void add_instrumentation(void) {
if (strstr(line, ".code")) {
if (strstr(line, ".code32")) skip_csect = use_64bit;
if (strstr(line, ".code64")) skip_csect = !use_64bit;
if (strstr(line, ".code32")) { skip_csect = use_64bit; }
if (strstr(line, ".code64")) { skip_csect = !use_64bit; }
}
/* Detect syntax changes, as could happen with hand-written assembly.
Skip Intel blocks, resume instrumentation when back to AT&T. */
if (strstr(line, ".intel_syntax")) skip_intel = 1;
if (strstr(line, ".att_syntax")) skip_intel = 0;
if (strstr(line, ".intel_syntax")) { skip_intel = 1; }
if (strstr(line, ".att_syntax")) { skip_intel = 0; }
/* Detect and skip ad-hoc __asm__ blocks, likewise skipping them. */
if (line[0] == '#' || line[1] == '#') {
if (strstr(line, "#APP")) skip_app = 1;
if (strstr(line, "#NO_APP")) skip_app = 0;
if (strstr(line, "#APP")) { skip_app = 1; }
if (strstr(line, "#NO_APP")) { skip_app = 0; }
}
@ -375,9 +395,12 @@ static void add_instrumentation(void) {
*/
if (skip_intel || skip_app || skip_csect || !instr_ok || line[0] == '#' ||
line[0] == ' ')
line[0] == ' ') {
continue;
}
/* Conditional branch instruction (jnz, etc). We append the instrumentation
right after the branch (to instrument the not-taken path) and at the
branch destination label (handled later on). */
@ -449,11 +472,16 @@ static void add_instrumentation(void) {
.Lfunc_begin0-style exception handling calculations (a problem on
MacOS X). */
if (!skip_next_label)
if (!skip_next_label) {
instrument_next = 1;
else
} else {
skip_next_label = 0;
}
}
} else {
@ -468,17 +496,19 @@ static void add_instrumentation(void) {
}
if (ins_lines) fputs(use_64bit ? main_payload_64 : main_payload_32, outf);
if (ins_lines) { fputs(use_64bit ? main_payload_64 : main_payload_32, outf); }
if (input_file) fclose(inf);
if (input_file) { fclose(inf); }
fclose(outf);
if (!be_quiet) {
if (!ins_lines)
if (!ins_lines) {
WARNF("No instrumentation targets found%s.",
pass_thru ? " (pass-thru mode)" : "");
else {
} else {
char modeline[100];
snprintf(modeline, sizeof(modeline), "%s%s%s%s",
@ -514,10 +544,12 @@ int main(int argc, char **argv) {
SAYF(cCYA "afl-as" VERSION cRST " by Michal Zalewski\n");
} else
} else {
be_quiet = 1;
}
if (argc < 2 || (argc == 2 && strcmp(argv[1], "-h") == 0)) {
fprintf(
@ -565,14 +597,20 @@ int main(int argc, char **argv) {
if (inst_ratio_str) {
if (sscanf(inst_ratio_str, "%u", &inst_ratio) != 1 || inst_ratio > 100)
if (sscanf(inst_ratio_str, "%u", &inst_ratio) != 1 || inst_ratio > 100) {
FATAL("Bad value of AFL_INST_RATIO (must be between 0 and 100)");
}
}
if (getenv(AS_LOOP_ENV_VAR))
if (getenv(AS_LOOP_ENV_VAR)) {
FATAL("Endless loop when calling 'as' (remove '.' from your PATH)");
}
setenv(AS_LOOP_ENV_VAR, "1", 1);
/* When compiling with ASAN, we don't have a particularly elegant way to skip
@ -582,11 +620,11 @@ int main(int argc, char **argv) {
if (getenv("AFL_USE_ASAN") || getenv("AFL_USE_MSAN")) {
sanitizer = 1;
if (!getenv("AFL_INST_RATIO")) inst_ratio /= 3;
if (!getenv("AFL_INST_RATIO")) { inst_ratio /= 3; }
}
if (!just_version) add_instrumentation();
if (!just_version) { add_instrumentation(); }
if (!(pid = fork())) {
@ -595,11 +633,11 @@ int main(int argc, char **argv) {
}
if (pid < 0) PFATAL("fork() failed");
if (pid < 0) { PFATAL("fork() failed"); }
if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed");
if (waitpid(pid, &status, 0) <= 0) { PFATAL("waitpid() failed"); }
if (!getenv("AFL_KEEP_ASSEMBLY")) unlink(modified_file);
if (!getenv("AFL_KEEP_ASSEMBLY")) { unlink(modified_file); }
exit(WEXITSTATUS(status));

View File

@ -34,7 +34,7 @@
/* Detect @@ in args. */
#ifndef __glibc__
#include <unistd.h>
#include <unistd.h>
#endif
#include <limits.h>
#include <sys/types.h>
@ -64,17 +64,19 @@ char *afl_environment_variables[] = {
"AFL_LD_PRELOAD", "AFL_LD_VERBOSE", "AFL_LLVM_CMPLOG", "AFL_LLVM_INSTRIM",
"AFL_LLVM_CTX", "AFL_LLVM_INSTRUMENT", "AFL_LLVM_INSTRIM_LOOPHEAD",
"AFL_LLVM_LTO_AUTODICTIONARY", "AFL_LLVM_AUTODICTIONARY",
"AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK", "AFL_LLVM_LAF_SPLIT_COMPARES",
"AFL_LLVM_LAF_SPLIT_COMPARES_BITW", "AFL_LLVM_LAF_SPLIT_FLOATS",
"AFL_LLVM_LAF_SPLIT_SWITCHES", "AFL_LLVM_LAF_TRANSFORM_COMPARES",
"AFL_LLVM_NGRAM_SIZE", "AFL_NGRAM_SIZE", "AFL_LLVM_NOT_ZERO",
"AFL_LLVM_WHITELIST", "AFL_NO_AFFINITY", "AFL_LLVM_LTO_STARTID",
"AFL_LLVM_LTO_DONTWRITEID", "AFL_NO_ARITH", "AFL_NO_BUILTIN",
"AFL_NO_CPU_RED", "AFL_NO_FORKSRV", "AFL_NO_UI", "AFL_NO_PYTHON",
"AFL_LLVM_SKIPSINGLEBLOCK", "AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK",
"AFL_LLVM_LAF_SPLIT_COMPARES", "AFL_LLVM_LAF_SPLIT_COMPARES_BITW",
"AFL_LLVM_LAF_SPLIT_FLOATS", "AFL_LLVM_LAF_SPLIT_SWITCHES",
"AFL_LLVM_LAF_TRANSFORM_COMPARES", "AFL_LLVM_MAP_ADDR",
"AFL_LLVM_MAP_DYNAMIC", "AFL_LLVM_NGRAM_SIZE", "AFL_NGRAM_SIZE",
"AFL_LLVM_NOT_ZERO", "AFL_LLVM_WHITELIST", "AFL_LLVM_SKIP_NEVERZERO",
"AFL_NO_AFFINITY", "AFL_LLVM_LTO_STARTID", "AFL_LLVM_LTO_DONTWRITEID",
"AFL_NO_ARITH", "AFL_NO_BUILTIN", "AFL_NO_CPU_RED", "AFL_NO_FORKSRV",
"AFL_NO_UI", "AFL_NO_PYTHON", "AFL_UNTRACER_FILE", "AFL_LLVM_USE_TRACE_PC",
"AFL_NO_X86", // not really an env but we dont want to warn on it
"AFL_MAP_SIZE", "AFL_MAPSIZE", "AFL_PATH", "AFL_PERFORMANCE_FILE",
//"AFL_PERSISTENT", // not implemented anymore, so warn additionally
"AFL_POST_LIBRARY", "AFL_PRELOAD", "AFL_PYTHON_MODULE", "AFL_QEMU_COMPCOV",
"AFL_PRELOAD", "AFL_PYTHON_MODULE", "AFL_QEMU_COMPCOV",
"AFL_QEMU_COMPCOV_DEBUG", "AFL_QEMU_DEBUG_MAPS", "AFL_QEMU_DISABLE_CACHE",
"AFL_QEMU_PERSISTENT_ADDR", "AFL_QEMU_PERSISTENT_CNT",
"AFL_QEMU_PERSISTENT_GPR", "AFL_QEMU_PERSISTENT_HOOK",
@ -101,7 +103,7 @@ void detect_file_args(char **argv, u8 *prog_in, u8 *use_stdin) {
if (aa_loc) {
if (!prog_in) FATAL("@@ syntax is not supported by this tool.");
if (!prog_in) { FATAL("@@ syntax is not supported by this tool."); }
*use_stdin = 0;
@ -198,7 +200,7 @@ char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
cp = alloc_printf("%s/afl-qemu-trace", tmp);
if (access(cp, X_OK)) FATAL("Unable to find '%s'", tmp);
if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); }
*target_path_p = new_argv[0] = cp;
return new_argv;
@ -230,7 +232,7 @@ char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) {
if (cp) ck_free(cp);
if (cp) { ck_free(cp); }
*target_path_p = new_argv[0] = ck_strdup(BIN_PATH "/afl-qemu-trace");
return new_argv;
@ -277,13 +279,13 @@ char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
cp = alloc_printf("%s/afl-qemu-trace", tmp);
if (access(cp, X_OK)) FATAL("Unable to find '%s'", tmp);
if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); }
ck_free(cp);
cp = alloc_printf("%s/afl-wine-trace", tmp);
if (access(cp, X_OK)) FATAL("Unable to find '%s'", tmp);
if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); }
*target_path_p = new_argv[0] = cp;
return new_argv;
@ -416,15 +418,22 @@ u8 *find_binary(u8 *fname) {
ck_free(cur_elem);
if (!stat(target_path, &st) && S_ISREG(st.st_mode) &&
(st.st_mode & 0111) && st.st_size >= 4)
(st.st_mode & 0111) && st.st_size >= 4) {
break;
}
ck_free(target_path);
target_path = NULL;
}
if (!target_path) FATAL("Program '%s' not found or not executable", fname);
if (!target_path) {
FATAL("Program '%s' not found or not executable", fname);
}
}
@ -434,7 +443,7 @@ u8 *find_binary(u8 *fname) {
void check_environment_vars(char **envp) {
if (be_quiet) return;
if (be_quiet) { return; }
int index = 0, found = 0;
char *env, *val;
@ -448,24 +457,30 @@ void check_environment_vars(char **envp) {
} else if (strncmp(env, "AFL_", 4) == 0) {
int i = 0, match = 0;
while (match == 0 && afl_environment_variables[i] != NULL)
while (match == 0 && afl_environment_variables[i] != NULL) {
if (strncmp(env, afl_environment_variables[i],
strlen(afl_environment_variables[i])) == 0 &&
env[strlen(afl_environment_variables[i])] == '=') {
match = 1;
if ((val = getenv(afl_environment_variables[i])) && !*val)
if ((val = getenv(afl_environment_variables[i])) && !*val) {
WARNF(
"AFL environment variable %s defined but is empty, this can "
"lead to unexpected consequences",
afl_environment_variables[i]);
}
} else {
i++;
}
}
if (match == 0) {
WARNF("Mistyped AFL environment variable: %s", env);
@ -477,7 +492,7 @@ void check_environment_vars(char **envp) {
}
if (found) sleep(2);
if (found) { sleep(2); }
}
@ -485,10 +500,16 @@ char *get_afl_env(char *env) {
char *val;
if ((val = getenv(env)) != NULL)
if (!be_quiet)
if ((val = getenv(env)) != NULL) {
if (!be_quiet) {
OKF("Loaded environment variable %s with value %s", env, val);
}
}
return val;
}
@ -499,7 +520,7 @@ void read_bitmap(u8 *fname, u8 *map, size_t len) {
s32 fd = open(fname, O_RDONLY);
if (fd < 0) PFATAL("Unable to open '%s'", fname);
if (fd < 0) { PFATAL("Unable to open '%s'", fname); }
ck_read(fd, map, len, fname);
@ -898,7 +919,7 @@ u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms,
}
u32 get_map_size() {
u32 get_map_size(void) {
uint32_t map_size = MAP_SIZE;
char * ptr;
@ -906,9 +927,14 @@ u32 get_map_size() {
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);
if (map_size < 8 || map_size > (1 << 29)) {
FATAL("illegal AFL_MAP_SIZE %u, must be between %u and %u", map_size, 8,
1 << 29);
}
if (map_size % 8) { map_size = (((map_size >> 3) + 1) << 3); }
}

View File

@ -53,7 +53,7 @@
/* Describe integer as memory size. */
list_t fsrv_list = {.element_prealloc_count = 0};
static list_t fsrv_list = {.element_prealloc_count = 0};
static void fsrv_exec_child(afl_forkserver_t *fsrv, char **argv) {
@ -67,7 +67,6 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
// this structure needs default so we initialize it if this was not done
// already
fsrv->out_fd = -1;
fsrv->out_dir_fd = -1;
fsrv->dev_null_fd = -1;
@ -83,7 +82,7 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
/* exec related stuff */
fsrv->child_pid = -1;
fsrv->map_size = MAP_SIZE;
fsrv->map_size = get_map_size();
fsrv->use_fauxsrv = 0;
fsrv->last_run_timed_out = 0;
@ -128,12 +127,16 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) {
unsigned char tmp[4] = {0, 0, 0, 0};
pid_t child_pid = -1;
if (!be_quiet) ACTF("Using Fauxserver:");
if (!be_quiet) { ACTF("Using Fauxserver:"); }
/* 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) abort(); // TODO: Abort?
if (write(FORKSRV_FD + 1, tmp, 4) != 4) {
abort(); // TODO: Abort?
}
void (*old_sigchld_handler)(int) = signal(SIGCHLD, SIG_DFL);
@ -144,13 +147,13 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) {
/* Wait for parent by reading from the pipe. Exit if read fails. */
if (read(FORKSRV_FD, &was_killed, 4) != 4) exit(0);
if (read(FORKSRV_FD, &was_killed, 4) != 4) { exit(0); }
/* Create a clone of our process. */
child_pid = fork();
if (child_pid < 0) PFATAL("Fork failed");
if (child_pid < 0) { PFATAL("Fork failed"); }
/* In child process: close fds, resume execution. */
@ -177,7 +180,7 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) {
/* In parent process: write PID to AFL. */
if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) exit(0);
if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) { exit(0); }
/* after child exited, get and relay exit status to parent through waitpid.
*/
@ -191,7 +194,45 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) {
/* Relay wait status to AFL pipe, then loop back. */
if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(0);
if (write(FORKSRV_FD + 1, &status, 4) != 4) { exit(0); }
}
}
/* Report on the error received via the forkserver controller and exit */
static void report_error_and_exit(int error) {
switch (error) {
case FS_ERROR_MAP_SIZE:
FATAL(
"AFL_MAP_SIZE is not set and fuzzing target reports that the "
"required size is very large. Solution: Run the fuzzing target "
"stand-alone with the environment variable AFL_DEBUG=1 set and set "
"the value for __afl_final_loc in the AFL_MAP_SIZE environment "
"variable for afl-fuzz.");
break;
case FS_ERROR_MAP_ADDR:
FATAL(
"the fuzzing target reports that hardcoded map address might be the "
"reason the mmap of the shared memory failed. Solution: recompile "
"the target with either afl-clang-lto and the environment variable "
"AFL_LLVM_MAP_DYNAMIC set or recompile with afl-clang-fast.");
break;
case FS_ERROR_SHM_OPEN:
FATAL("the fuzzing target reports that the shm_open() call failed.");
break;
case FS_ERROR_SHMAT:
FATAL("the fuzzing target reports that the shmat() call failed.");
break;
case FS_ERROR_MMAP:
FATAL(
"the fuzzing target reports that the mmap() call to the share memory "
"failed.");
break;
default:
FATAL("unknown error code %u from fuzzing target!", error);
}
@ -212,25 +253,28 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
int status;
s32 rlen;
if (!be_quiet) ACTF("Spinning up the fork server...");
if (!be_quiet) { ACTF("Spinning up the fork server..."); }
if (fsrv->use_fauxsrv) {
/* TODO: Come up with sone nice way to initalize this all */
if (fsrv->init_child_func != fsrv_exec_child)
if (fsrv->init_child_func != fsrv_exec_child) {
FATAL("Different forkserver not compatible with fauxserver");
}
fsrv->init_child_func = afl_fauxsrv_execv;
}
if (pipe(st_pipe) || pipe(ctl_pipe)) PFATAL("pipe() failed");
if (pipe(st_pipe) || pipe(ctl_pipe)) { PFATAL("pipe() failed"); }
fsrv->last_run_timed_out = 0;
fsrv->fsrv_pid = fork();
if (fsrv->fsrv_pid < 0) PFATAL("fork() failed");
if (fsrv->fsrv_pid < 0) { PFATAL("fork() failed"); }
if (!fsrv->fsrv_pid) {
@ -295,8 +339,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
/* Set up control and status pipes, close the unneeded original fds. */
if (dup2(ctl_pipe[0], FORKSRV_FD) < 0) PFATAL("dup2() failed");
if (dup2(st_pipe[1], FORKSRV_FD + 1) < 0) PFATAL("dup2() failed");
if (dup2(ctl_pipe[0], FORKSRV_FD) < 0) { PFATAL("dup2() failed"); }
if (dup2(st_pipe[1], FORKSRV_FD + 1) < 0) { PFATAL("dup2() failed"); }
close(ctl_pipe[0]);
close(ctl_pipe[1]);
@ -308,12 +352,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
#ifndef HAVE_ARC4RANDOM
close(fsrv->dev_urandom_fd);
#endif
if (fsrv->plot_file != NULL) fclose(fsrv->plot_file);
if (fsrv->plot_file != NULL) { fclose(fsrv->plot_file); }
/* This should improve performance a bit, since it stops the linker from
doing extra work post-fork(). */
if (!getenv("LD_BIND_LAZY")) setenv("LD_BIND_NOW", "1", 0);
if (!getenv("LD_BIND_LAZY")) { setenv("LD_BIND_NOW", "1", 0); }
/* Set sane defaults for ASAN if nothing else specified. */
@ -391,17 +435,23 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
if (rlen == 4) {
if (!be_quiet) OKF("All right - fork server is up.");
if (!be_quiet) { OKF("All right - fork server is up."); }
if ((status & FS_OPT_ERROR) == FS_OPT_ERROR)
report_error_and_exit(FS_OPT_GET_ERROR(status));
if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) {
if (!be_quiet && getenv("AFL_DEBUG"))
if (!be_quiet && getenv("AFL_DEBUG")) {
ACTF("Extended forkserver functions received (%08x).", status);
}
if ((status & FS_OPT_SNAPSHOT) == FS_OPT_SNAPSHOT) {
fsrv->snapshot = 1;
if (!be_quiet) ACTF("Using SNAPSHOT feature.");
if (!be_quiet) { ACTF("Using SNAPSHOT feature."); }
}
@ -409,7 +459,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
u32 tmp_map_size = FS_OPT_GET_MAPSIZE(status);
if (!fsrv->map_size) fsrv->map_size = MAP_SIZE;
if (!fsrv->map_size) { fsrv->map_size = MAP_SIZE; }
if (unlikely(tmp_map_size % 8)) {
@ -419,13 +469,18 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
}
if (!be_quiet) ACTF("Target map size: %u", tmp_map_size);
if (tmp_map_size > fsrv->map_size)
if (!be_quiet) { ACTF("Target map size: %u", tmp_map_size); }
if (tmp_map_size > fsrv->map_size) {
FATAL(
"Target's coverage map size of %u is larger than the one this "
"afl++ is set with (%u) (change MAP_SIZE_POW2 in config.h and "
"recompile or set AFL_MAP_SIZE)\n",
tmp_map_size, fsrv->map_size);
"afl++ is set with (%u). Either set AFL_MAP_SIZE=%u and restart "
" afl-fuzz, or change MAP_SIZE_POW2 in config.h and recompile "
"afl-fuzz",
tmp_map_size, fsrv->map_size, tmp_map_size);
}
fsrv->map_size = tmp_map_size;
}
@ -436,27 +491,44 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
// this is not afl-fuzz - we deny and return
status = (0xffffffff ^ (FS_OPT_ENABLED | FS_OPT_AUTODICT));
if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4)
if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
FATAL("Writing to forkserver failed.");
}
return;
}
if (!be_quiet) ACTF("Using AUTODICT feature.");
if (!be_quiet) { ACTF("Using AUTODICT feature."); }
status = (FS_OPT_ENABLED | FS_OPT_AUTODICT);
if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4)
if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
FATAL("Writing to forkserver failed.");
if (read(fsrv->fsrv_st_fd, &status, 4) != 4)
}
if (read(fsrv->fsrv_st_fd, &status, 4) != 4) {
FATAL("Reading from forkserver failed.");
if (status < 2 || (u32)status > 0xffffff)
}
if (status < 2 || (u32)status > 0xffffff) {
FATAL("Dictionary has an illegal size: %d", status);
}
u32 len = status, offset = 0, count = 0;
u8 *dict = ck_alloc(len);
if (dict == NULL)
if (dict == NULL) {
FATAL("Could not allocate %u bytes of autodictionary memory", len);
}
while (len != 0) {
rlen = read(fsrv->fsrv_st_fd, dict + offset, len);
@ -486,7 +558,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
}
if (!be_quiet) ACTF("Loaded %u autodictionary entries", count);
if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); }
ck_free(dict);
}
@ -497,10 +569,13 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
}
if (fsrv->last_run_timed_out)
if (fsrv->last_run_timed_out) {
FATAL("Timeout while initializing fork server (adjusting -t may help)");
if (waitpid(fsrv->fsrv_pid, &status, 0) <= 0) PFATAL("waitpid() failed");
}
if (waitpid(fsrv->fsrv_pid, &status, 0) <= 0) { PFATAL("waitpid() failed"); }
if (WIFSIGNALED(status)) {
@ -580,9 +655,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
}
if (*(u32 *)fsrv->trace_bits == EXEC_FAIL_SIG)
if (*(u32 *)fsrv->trace_bits == EXEC_FAIL_SIG) {
FATAL("Unable to execute target application ('%s')", argv[0]);
}
if (fsrv->mem_limit && fsrv->mem_limit < 500 && fsrv->uses_asan) {
SAYF("\n" cLRD "[-] " cRST
@ -598,12 +676,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
} else if (!fsrv->mem_limit) {
SAYF("\n" cLRD "[-] " cRST
"Hmm, looks like the target binary terminated "
"before we could complete a\n"
" handshake with the injected code. Perhaps there is a horrible "
"bug in the\n"
" fuzzer. Poke <afl-users@googlegroups.com> for troubleshooting "
"tips.\n");
"Hmm, looks like the target binary terminated before we could"
"complete a handshake with the injected code.\n"
"If the target was compiled with afl-clang-lto then recompiling with"
"AFL_LLVM_MAP_DYNAMIC might solve your problem.\n"
"Otherwise there is a horrible bug in the fuzzer.\n"
"Poke <afl-users@googlegroups.com> for troubleshooting tips.\n");
} else {
@ -630,6 +708,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
" estimate the required amount of virtual memory for the "
"binary.\n\n"
" - the target was compiled with afl-clang-lto and a constructor "
"was\n"
" instrumented, recompiling with AFL_LLVM_MAP_DYNAMIC might solve "
"your\n"
" problem\n\n"
" - Less likely, there is a horrible bug in the fuzzer. If other "
"options\n"
" fail, poke <afl-users@googlegroups.com> for troubleshooting "
@ -651,7 +735,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
static void afl_fsrv_kill(afl_forkserver_t *fsrv) {
if (fsrv->child_pid > 0) kill(fsrv->child_pid, SIGKILL);
if (fsrv->child_pid > 0) { kill(fsrv->child_pid, SIGKILL); }
if (fsrv->fsrv_pid > 0) {
kill(fsrv->fsrv_pid, SIGKILL);
@ -680,7 +764,7 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) {
}
if (fd < 0) PFATAL("Unable to create '%s'", fsrv->out_file);
if (fd < 0) { PFATAL("Unable to create '%s'", fsrv->out_file); }
} else {
@ -692,7 +776,7 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) {
if (!fsrv->out_file) {
if (ftruncate(fd, len)) PFATAL("ftruncate() failed");
if (ftruncate(fd, len)) { PFATAL("ftruncate() failed"); }
lseek(fd, 0, SEEK_SET);
} else {
@ -712,8 +796,6 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
s32 res;
u32 exec_ms;
int status = 0;
/* After this memset, fsrv->trace_bits[] are effectively volatile, so we
must prevent any earlier operations from venturing into that
territory. */
@ -727,7 +809,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
if ((res = write(fsrv->fsrv_ctl_fd, &fsrv->last_run_timed_out, 4)) != 4) {
if (*stop_soon_p) return 0;
if (*stop_soon_p) { return 0; }
RPFATAL(res, "Unable to request new process from fork server (OOM?)");
}
@ -736,14 +818,15 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
if ((res = read(fsrv->fsrv_st_fd, &fsrv->child_pid, 4)) != 4) {
if (*stop_soon_p) return 0;
if (*stop_soon_p) { return 0; }
RPFATAL(res, "Unable to request new process from fork server (OOM?)");
}
if (fsrv->child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)");
if (fsrv->child_pid <= 0) { FATAL("Fork server is misbehaving (OOM?)"); }
exec_ms = read_timed(fsrv->fsrv_st_fd, &status, 4, timeout, stop_soon_p);
exec_ms = read_timed(fsrv->fsrv_st_fd, &fsrv->child_status, 4, timeout,
stop_soon_p);
if (exec_ms > timeout) {
@ -752,13 +835,13 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
kill(fsrv->child_pid, SIGKILL);
fsrv->last_run_timed_out = 1;
if (read(fsrv->fsrv_st_fd, &status, 4) < 4) exec_ms = 0;
if (read(fsrv->fsrv_st_fd, &fsrv->child_status, 4) < 4) { exec_ms = 0; }
}
if (!exec_ms) {
if (*stop_soon_p) return 0;
if (*stop_soon_p) { return 0; }
SAYF("\n" cLRD "[-] " cRST
"Unable to communicate with fork server. Some possible reasons:\n\n"
" - You've run out of memory. Use -m to increase the the memory "
@ -784,7 +867,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
}
if (!WIFSTOPPED(status)) fsrv->child_pid = 0;
if (!WIFSTOPPED(fsrv->child_status)) { fsrv->child_pid = 0; }
fsrv->total_execs++;
@ -796,13 +879,16 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
/* Report outcome to caller. */
if (WIFSIGNALED(status) && !*stop_soon_p) {
if (WIFSIGNALED(fsrv->child_status) && !*stop_soon_p) {
fsrv->last_kill_signal = WTERMSIG(status);
fsrv->last_kill_signal = WTERMSIG(fsrv->child_status);
if (fsrv->last_run_timed_out && fsrv->last_kill_signal == SIGKILL) {
if (fsrv->last_run_timed_out && fsrv->last_kill_signal == SIGKILL)
return FSRV_RUN_TMOUT;
}
return FSRV_RUN_CRASH;
}
@ -810,7 +896,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
/* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and
must use a special exit code. */
if (fsrv->uses_asan && WEXITSTATUS(status) == MSAN_ERROR) {
if (fsrv->uses_asan && WEXITSTATUS(fsrv->child_status) == MSAN_ERROR) {
fsrv->last_kill_signal = 0;
return FSRV_RUN_CRASH;

View File

@ -35,13 +35,13 @@ void write_bitmap(afl_state_t *afl) {
u8 fname[PATH_MAX];
s32 fd;
if (!afl->bitmap_changed) return;
if (!afl->bitmap_changed) { return; }
afl->bitmap_changed = 0;
snprintf(fname, PATH_MAX, "%s/fuzz_bitmap", afl->out_dir);
fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd < 0) PFATAL("Unable to open '%s'", fname);
if (fd < 0) { PFATAL("Unable to open '%s'", fname); }
ck_write(fd, afl->virgin_bits, afl->fsrv.map_size, fname);
@ -102,11 +102,16 @@ u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) {
(cur[1] && vir[1] == 0xff) || (cur[2] && vir[2] == 0xff) ||
(cur[3] && vir[3] == 0xff) || (cur[4] && vir[4] == 0xff) ||
(cur[5] && vir[5] == 0xff) || (cur[6] && vir[6] == 0xff) ||
(cur[7] && vir[7] == 0xff))
(cur[7] && vir[7] == 0xff)) {
ret = 2;
else
} else {
ret = 1;
}
#else
if (*virgin == 0xffffffff || (cur[0] && vir[0] == 0xff) ||
@ -129,9 +134,12 @@ u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) {
}
if (unlikely(ret) && likely(virgin_map == afl->virgin_bits))
if (unlikely(ret) && likely(virgin_map == afl->virgin_bits)) {
afl->bitmap_changed = 1;
}
return ret;
}
@ -183,11 +191,11 @@ u32 count_bytes(afl_state_t *afl, u8 *mem) {
u32 v = *(ptr++);
if (!v) continue;
if (v & 0x000000ff) ++ret;
if (v & 0x0000ff00) ++ret;
if (v & 0x00ff0000) ++ret;
if (v & 0xff000000) ++ret;
if (!v) { continue; }
if (v & 0x000000ff) { ++ret; }
if (v & 0x0000ff00) { ++ret; }
if (v & 0x00ff0000) { ++ret; }
if (v & 0xff000000) { ++ret; }
}
@ -211,11 +219,11 @@ u32 count_non_255_bytes(afl_state_t *afl, u8 *mem) {
/* This is called on the virgin bitmap, so optimize for the most likely
case. */
if (v == 0xffffffff) continue;
if ((v & 0x000000ff) != 0x000000ff) ++ret;
if ((v & 0x0000ff00) != 0x0000ff00) ++ret;
if ((v & 0x00ff0000) != 0x00ff0000) ++ret;
if ((v & 0xff000000) != 0xff000000) ++ret;
if (v == 0xffffffff) { continue; }
if ((v & 0x000000ff) != 0x000000ff) { ++ret; }
if ((v & 0x0000ff00) != 0x0000ff00) { ++ret; }
if ((v & 0x00ff0000) != 0x00ff0000) { ++ret; }
if ((v & 0xff000000) != 0xff000000) { ++ret; }
}
@ -257,10 +265,12 @@ void simplify_trace(afl_state_t *afl, u64 *mem) {
mem8[6] = simplify_lookup[mem8[6]];
mem8[7] = simplify_lookup[mem8[7]];
} else
} else {
*mem = 0x0101010101010101ULL;
}
++mem;
}
@ -322,11 +332,17 @@ void init_count_class16(void) {
u32 b1, b2;
for (b1 = 0; b1 < 256; b1++)
for (b2 = 0; b2 < 256; b2++)
for (b1 = 0; b1 < 256; b1++) {
for (b2 = 0; b2 < 256; b2++) {
count_class_lookup16[(b1 << 8) + b2] =
(count_class_lookup8[b1] << 8) | count_class_lookup8[b2];
}
}
}
#ifdef WORD_SIZE_64
@ -397,7 +413,7 @@ void minimize_bits(afl_state_t *afl, u8 *dst, u8 *src) {
while (i < afl->fsrv.map_size) {
if (*(src++)) dst[i >> 3] |= 1 << (i & 7);
if (*(src++)) { dst[i >> 3] |= 1 << (i & 7); }
++i;
}
@ -421,29 +437,37 @@ u8 *describe_op(afl_state_t *afl, u8 hnb) {
sprintf(ret, "src:%06u", afl->current_entry);
sprintf(ret + strlen(ret), ",time:%llu", get_cur_time() - afl->start_time);
if (afl->splicing_with >= 0) {
if (afl->splicing_with >= 0)
sprintf(ret + strlen(ret), "+%06d", afl->splicing_with);
}
sprintf(ret + strlen(ret), ",time:%llu", get_cur_time() - afl->start_time);
sprintf(ret + strlen(ret), ",op:%s", afl->stage_short);
if (afl->stage_cur_byte >= 0) {
sprintf(ret + strlen(ret), ",pos:%d", afl->stage_cur_byte);
if (afl->stage_val_type != STAGE_VAL_NONE)
if (afl->stage_val_type != STAGE_VAL_NONE) {
sprintf(ret + strlen(ret), ",val:%s%+d",
(afl->stage_val_type == STAGE_VAL_BE) ? "be:" : "",
afl->stage_cur_val);
} else
}
} else {
sprintf(ret + strlen(ret), ",rep:%d", afl->stage_cur_val);
}
}
if (hnb == 2) strcat(ret, ",+cov");
if (hnb == 2) { strcat(ret, ",+cov"); }
return ret;
@ -467,7 +491,7 @@ static void write_crash_readme(afl_state_t *afl) {
/* Do not die on errors here - that would be impolite. */
if (unlikely(fd < 0)) return;
if (unlikely(fd < 0)) { return; }
f = fdopen(fd, "w");
@ -512,7 +536,7 @@ static void write_crash_readme(afl_state_t *afl) {
u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
if (unlikely(len == 0)) return 0;
if (unlikely(len == 0)) { return 0; }
u8 *queue_fn = "";
u8 hnb = '\0';
@ -545,7 +569,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
if (!(hnb = has_new_bits(afl, afl->virgin_bits))) {
if (unlikely(afl->crash_mode)) ++afl->total_crashes;
if (unlikely(afl->crash_mode)) { ++afl->total_crashes; }
return 0;
}
@ -578,11 +602,14 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
res = calibrate_case(afl, afl->queue_top, mem, afl->queue_cycle - 1, 0);
if (unlikely(res == FSRV_RUN_ERROR))
if (unlikely(res == FSRV_RUN_ERROR)) {
FATAL("Unable to execute target application");
}
fd = open(queue_fn, O_WRONLY | O_CREAT | O_EXCL, 0600);
if (unlikely(fd < 0)) PFATAL("Unable to create '%s'", queue_fn);
if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", queue_fn); }
ck_write(fd, mem, len, queue_fn);
close(fd);
@ -601,7 +628,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
++afl->total_tmouts;
if (afl->unique_hangs >= KEEP_UNIQUE_HANG) return keeping;
if (afl->unique_hangs >= KEEP_UNIQUE_HANG) { return keeping; }
if (likely(!afl->dumb_mode)) {
@ -611,7 +638,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
simplify_trace(afl, (u32 *)afl->fsrv.trace_bits);
#endif /* ^WORD_SIZE_64 */
if (!has_new_bits(afl, afl->virgin_tmout)) return keeping;
if (!has_new_bits(afl, afl->virgin_tmout)) { return keeping; }
}
@ -631,9 +658,13 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
timeout actually uncovers a crash. Make sure we don't discard it if
so. */
if (!afl->stop_soon && new_fault == FSRV_RUN_CRASH) goto keep_as_crash;
if (!afl->stop_soon && new_fault == FSRV_RUN_CRASH) {
if (afl->stop_soon || new_fault != FSRV_RUN_TMOUT) return keeping;
goto keep_as_crash;
}
if (afl->stop_soon || new_fault != FSRV_RUN_TMOUT) { return keeping; }
}
@ -665,7 +696,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
++afl->total_crashes;
if (afl->unique_crashes >= KEEP_UNIQUE_CRASH) return keeping;
if (afl->unique_crashes >= KEEP_UNIQUE_CRASH) { return keeping; }
if (likely(!afl->dumb_mode)) {
@ -675,11 +706,11 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
simplify_trace(afl, (u32 *)afl->fsrv.trace_bits);
#endif /* ^WORD_SIZE_64 */
if (!has_new_bits(afl, afl->virgin_crash)) return keeping;
if (!has_new_bits(afl, afl->virgin_crash)) { return keeping; }
}
if (unlikely(!afl->unique_crashes)) write_crash_readme(afl);
if (unlikely(!afl->unique_crashes)) { write_crash_readme(afl); }
#ifndef SIMPLE_FILES
@ -690,7 +721,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
#else
snprintf(fn, PATH_MAX, "%s/crashes/id_%06llu_%02u", afl->out_dir,
afl->unique_crashes, afl->kill_signal);
afl->unique_crashes, afl->last_kill_signal);
#endif /* ^!SIMPLE_FILES */
@ -715,9 +746,11 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
break;
case FSRV_RUN_ERROR: FATAL("Unable to execute target application");
case FSRV_RUN_ERROR:
FATAL("Unable to execute target application");
default: return keeping;
default:
return keeping;
}
@ -725,7 +758,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
test case, too. */
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600);
if (unlikely(fd < 0)) PFATAL("Unable to create '%s'", fn);
if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", fn); }
ck_write(fd, mem, len, fn);
close(fd);

View File

@ -37,9 +37,12 @@ void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) {
setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1);
if (!fsrv->qemu_mode && argv[0] != fsrv->cmplog_binary)
if (!fsrv->qemu_mode && argv[0] != fsrv->cmplog_binary) {
argv[0] = fsrv->cmplog_binary;
}
execv(argv[0], argv);
}
@ -48,23 +51,11 @@ u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
u8 fault;
if (afl->post_handler) {
u8 *post_buf = NULL;
size_t post_len =
afl->post_handler(afl->post_data, out_buf, len, &post_buf);
if (!post_buf || !post_len) return 0;
out_buf = post_buf;
len = post_len;
}
write_to_testcase(afl, out_buf, len);
fault = fuzz_run_target(afl, &afl->cmplog_fsrv, afl->fsrv.exec_tmout);
if (afl->stop_soon) return 1;
if (afl->stop_soon) { return 1; }
if (fault == FSRV_RUN_TMOUT) {
@ -75,10 +66,12 @@ u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
}
} else
} else {
afl->subseq_tmouts = 0;
}
/* Users can hit us with SIGUSR1 to request the current input
to be abandoned. */

View File

@ -59,7 +59,7 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len,
f = fopen(fname, "r");
if (!f) PFATAL("Unable to open '%s'", fname);
if (!f) { PFATAL("Unable to open '%s'", fname); }
while ((lptr = fgets(buf, MAX_LINE, f))) {
@ -70,57 +70,79 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len,
/* Trim on left and right. */
while (isspace(*lptr))
while (isspace(*lptr)) {
++lptr;
}
rptr = lptr + strlen(lptr) - 1;
while (rptr >= lptr && isspace(*rptr))
while (rptr >= lptr && isspace(*rptr)) {
--rptr;
}
++rptr;
*rptr = 0;
/* Skip empty lines and comments. */
if (!*lptr || *lptr == '#') continue;
if (!*lptr || *lptr == '#') { continue; }
/* All other lines must end with '"', which we can consume. */
--rptr;
if (rptr < lptr || *rptr != '"')
if (rptr < lptr || *rptr != '"') {
FATAL("Malformed name=\"value\" pair in line %u.", cur_line);
}
*rptr = 0;
/* Skip alphanumerics and dashes (label). */
while (isalnum(*lptr) || *lptr == '_')
while (isalnum(*lptr) || *lptr == '_') {
++lptr;
}
/* If @number follows, parse that. */
if (*lptr == '@') {
++lptr;
if (atoi(lptr) > dict_level) continue;
while (isdigit(*lptr))
if (atoi(lptr) > dict_level) { continue; }
while (isdigit(*lptr)) {
++lptr;
}
}
/* Skip whitespace and = signs. */
while (isspace(*lptr) || *lptr == '=')
while (isspace(*lptr) || *lptr == '=') {
++lptr;
}
/* Consume opening '"'. */
if (*lptr != '"')
if (*lptr != '"') {
FATAL("Malformed name=\"keyword\" pair in line %u.", cur_line);
}
++lptr;
if (!*lptr) FATAL("Empty keyword in line %u.", cur_line);
if (!*lptr) { FATAL("Empty keyword in line %u.", cur_line); }
/* Okay, let's allocate memory and copy data between "...", handling
\xNN escaping, \\, and \". */
@ -130,7 +152,7 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len,
wptr = afl->extras[afl->extras_cnt].data = ck_alloc(rptr - lptr);
if (!wptr) PFATAL("no mem for data");
if (!wptr) { PFATAL("no mem for data"); }
while (*lptr) {
@ -154,9 +176,12 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len,
}
if (*lptr != 'x' || !isxdigit(lptr[1]) || !isxdigit(lptr[2]))
if (*lptr != 'x' || !isxdigit(lptr[1]) || !isxdigit(lptr[2])) {
FATAL("Invalid escaping (not \\xNN) in line %u.", cur_line);
}
*(wptr++) = ((strchr(hexdigits, tolower(lptr[1])) - hexdigits) << 4) |
(strchr(hexdigits, tolower(lptr[2])) - hexdigits);
@ -165,7 +190,9 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len,
break;
default: *(wptr++) = *(lptr++); ++klen;
default:
*(wptr++) = *(lptr++);
++klen;
}
@ -173,14 +200,17 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len,
afl->extras[afl->extras_cnt].len = klen;
if (afl->extras[afl->extras_cnt].len > MAX_DICT_FILE)
if (afl->extras[afl->extras_cnt].len > MAX_DICT_FILE) {
FATAL(
"Keyword too big in line %u (%s, limit is %s)", cur_line,
stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), klen),
stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), MAX_DICT_FILE));
if (*min_len > klen) *min_len = klen;
if (*max_len < klen) *max_len = klen;
}
if (*min_len > klen) { *min_len = klen; }
if (*max_len < klen) { *max_len = klen; }
++afl->extras_cnt;
@ -227,7 +257,7 @@ void load_extras(afl_state_t *afl, u8 *dir) {
}
if (x) FATAL("Dictionary levels not supported for directories.");
if (x) { FATAL("Dictionary levels not supported for directories."); }
while ((de = readdir(d))) {
@ -235,7 +265,11 @@ void load_extras(afl_state_t *afl, u8 *dir) {
u8 * fn = alloc_printf("%s/%s", dir, de->d_name);
s32 fd;
if (lstat(fn, &st) || access(fn, R_OK)) PFATAL("Unable to access '%s'", fn);
if (lstat(fn, &st) || access(fn, R_OK)) {
PFATAL("Unable to access '%s'", fn);
}
/* This also takes care of . and .. */
if (!S_ISREG(st.st_mode) || !st.st_size) {
@ -245,14 +279,17 @@ void load_extras(afl_state_t *afl, u8 *dir) {
}
if (st.st_size > MAX_DICT_FILE)
if (st.st_size > MAX_DICT_FILE) {
FATAL(
"Extra '%s' is too big (%s, limit is %s)", fn,
stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), st.st_size),
stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), MAX_DICT_FILE));
if (min_len > st.st_size) min_len = st.st_size;
if (max_len < st.st_size) max_len = st.st_size;
}
if (min_len > st.st_size) { min_len = st.st_size; }
if (max_len < st.st_size) { max_len = st.st_size; }
afl->extras = ck_realloc_block(
afl->extras, (afl->extras_cnt + 1) * sizeof(struct extra_data));
@ -262,7 +299,7 @@ void load_extras(afl_state_t *afl, u8 *dir) {
fd = open(fn, O_RDONLY);
if (fd < 0) PFATAL("Unable to open '%s'", fn);
if (fd < 0) { PFATAL("Unable to open '%s'", fn); }
ck_read(fd, afl->extras[afl->extras_cnt].data, st.st_size, fn);
@ -277,7 +314,7 @@ void load_extras(afl_state_t *afl, u8 *dir) {
check_and_sort:
if (!afl->extras_cnt) FATAL("No usable files in '%s'", dir);
if (!afl->extras_cnt) { FATAL("No usable files in '%s'", dir); }
qsort(afl->extras, afl->extras_cnt, sizeof(struct extra_data),
compare_extras_len);
@ -286,22 +323,32 @@ check_and_sort:
stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), min_len),
stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), max_len));
if (max_len > 32)
if (max_len > 32) {
WARNF("Some tokens are relatively large (%s) - consider trimming.",
stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), max_len));
if (afl->extras_cnt > MAX_DET_EXTRAS)
}
if (afl->extras_cnt > MAX_DET_EXTRAS) {
WARNF("More than %d tokens - will use them probabilistically.",
MAX_DET_EXTRAS);
}
}
/* Helper function for maybe_add_auto(afl, ) */
static inline u8 memcmp_nocase(u8 *m1, u8 *m2, u32 len) {
while (len--)
if (tolower(*(m1++)) ^ tolower(*(m2++))) return 1;
while (len--) {
if (tolower(*(m1++)) ^ tolower(*(m2++))) { return 1; }
}
return 0;
}
@ -318,14 +365,17 @@ void maybe_add_auto(void *afl_tmp, u8 *mem, u32 len) {
/* Allow users to specify that they don't want auto dictionaries. */
if (!MAX_AUTO_EXTRAS || !USE_AUTO_EXTRAS) return;
if (!MAX_AUTO_EXTRAS || !USE_AUTO_EXTRAS) { return; }
/* Skip runs of identical bytes. */
for (i = 1; i < len; ++i)
if (mem[0] ^ mem[i]) break;
for (i = 1; i < len; ++i) {
if (i == len) return;
if (mem[0] ^ mem[i]) { break; }
}
if (i == len) { return; }
/* Reject builtin interesting values. */
@ -333,33 +383,51 @@ void maybe_add_auto(void *afl_tmp, u8 *mem, u32 len) {
i = sizeof(interesting_16) >> 1;
while (i--)
while (i--) {
if (*((u16 *)mem) == interesting_16[i] ||
*((u16 *)mem) == SWAP16(interesting_16[i]))
*((u16 *)mem) == SWAP16(interesting_16[i])) {
return;
}
}
}
if (len == 4) {
i = sizeof(interesting_32) >> 2;
while (i--)
while (i--) {
if (*((u32 *)mem) == interesting_32[i] ||
*((u32 *)mem) == SWAP32(interesting_32[i]))
*((u32 *)mem) == SWAP32(interesting_32[i])) {
return;
}
}
}
/* Reject anything that matches existing extras. Do a case-insensitive
match. We optimize by exploiting the fact that extras[] are sorted
by size. */
for (i = 0; i < afl->extras_cnt; ++i)
if (afl->extras[i].len >= len) break;
for (i = 0; i < afl->extras_cnt; ++i) {
for (; i < afl->extras_cnt && afl->extras[i].len == len; ++i)
if (!memcmp_nocase(afl->extras[i].data, mem, len)) return;
if (afl->extras[i].len >= len) { break; }
}
for (; i < afl->extras_cnt && afl->extras[i].len == len; ++i) {
if (!memcmp_nocase(afl->extras[i].data, mem, len)) { return; }
}
/* Last but not least, check afl->a_extras[] for matches. There are no
guarantees of a particular sort order. */
@ -423,7 +491,7 @@ void save_auto(afl_state_t *afl) {
u32 i;
if (!afl->auto_changed) return;
if (!afl->auto_changed) { return; }
afl->auto_changed = 0;
for (i = 0; i < MIN(USE_AUTO_EXTRAS, afl->a_extras_cnt); ++i) {
@ -434,7 +502,7 @@ void save_auto(afl_state_t *afl) {
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd < 0) PFATAL("Unable to create '%s'", fn);
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
ck_write(fd, afl->a_extras[i].data, afl->a_extras[i].len, fn);
@ -461,7 +529,7 @@ void load_auto(afl_state_t *afl) {
if (fd < 0) {
if (errno != ENOENT) PFATAL("Unable to open '%s'", fn);
if (errno != ENOENT) { PFATAL("Unable to open '%s'", fn); }
ck_free(fn);
break;
@ -472,21 +540,29 @@ void load_auto(afl_state_t *afl) {
len = read(fd, tmp, MAX_AUTO_EXTRA + 1);
if (len < 0) PFATAL("Unable to read from '%s'", fn);
if (len < 0) { PFATAL("Unable to read from '%s'", fn); }
if (len >= MIN_AUTO_EXTRA && len <= MAX_AUTO_EXTRA) {
if (len >= MIN_AUTO_EXTRA && len <= MAX_AUTO_EXTRA)
maybe_add_auto((u8 *)afl, tmp, len);
}
close(fd);
ck_free(fn);
}
if (i)
if (i) {
OKF("Loaded %u auto-discovered dictionary tokens.", i);
else
} else {
OKF("No auto-generated dictionary tokens to reuse.");
}
}
/* Destroy extras. */
@ -495,14 +571,20 @@ void destroy_extras(afl_state_t *afl) {
u32 i;
for (i = 0; i < afl->extras_cnt; ++i)
for (i = 0; i < afl->extras_cnt; ++i) {
ck_free(afl->extras[i].data);
}
ck_free(afl->extras);
for (i = 0; i < afl->a_extras_cnt; ++i)
for (i = 0; i < afl->a_extras_cnt; ++i) {
ck_free(afl->a_extras[i].data);
}
ck_free(afl->a_extras);
}

File diff suppressed because it is too large Load Diff

View File

@ -26,12 +26,17 @@
#include "afl-fuzz.h"
void load_custom_mutator(afl_state_t *, const char *);
struct custom_mutator *load_custom_mutator(afl_state_t *, const char *);
#ifdef USE_PYTHON
struct custom_mutator *load_custom_mutator_py(afl_state_t *, char *);
#endif
void setup_custom_mutator(afl_state_t *afl) {
void setup_custom_mutators(afl_state_t *afl) {
/* Try mutator library first */
u8 *fn = afl->afl_env.afl_custom_mutator_library;
struct custom_mutator *mutator;
u8 * fn = afl->afl_env.afl_custom_mutator_library;
u32 prev_mutator_count = 0;
if (fn) {
@ -39,11 +44,37 @@ void setup_custom_mutator(afl_state_t *afl) {
FATAL(
"MOpt and custom mutator are mutually exclusive. We accept pull "
"requests that integrates MOpt with the optional mutators "
"(custom/radamsa/redquenn/...).");
"(custom/radamsa/redqueen/...).");
load_custom_mutator(afl, fn);
u8 *fn_token = (u8 *)strsep((char **)&fn, ";:,");
return;
if (likely(!fn_token)) {
mutator = load_custom_mutator(afl, fn);
list_append(&afl->custom_mutator_list, mutator);
afl->custom_mutators_count++;
} else {
while (fn_token) {
if (*fn_token) { // strsep can be empty if ";;"
if (afl->not_on_tty && afl->debug)
SAYF("[Custom] Processing: %s\n", fn_token);
prev_mutator_count = afl->custom_mutators_count;
mutator = load_custom_mutator(afl, fn_token);
list_append(&afl->custom_mutator_list, mutator);
afl->custom_mutators_count++;
if (prev_mutator_count > afl->custom_mutators_count)
FATAL("Maximum Custom Mutator count reached.");
fn_token = (u8 *)strsep((char **)&fn, ";:,");
}
}
}
}
@ -53,149 +84,164 @@ void setup_custom_mutator(afl_state_t *afl) {
if (module_name) {
if (afl->limit_time_sig)
if (afl->limit_time_sig) {
FATAL(
"MOpt and Python mutator are mutually exclusive. We accept pull "
"requests that integrates MOpt with the optional mutators "
"(custom/radamsa/redqueen/...).");
load_custom_mutator_py(afl, module_name);
}
struct custom_mutator *mutator = load_custom_mutator_py(afl, module_name);
afl->custom_mutators_count++;
list_append(&afl->custom_mutator_list, mutator);
}
#else
if (afl->afl_env.afl_python_module)
if (afl->afl_env.afl_python_module) {
FATAL("Your AFL binary was built without Python support");
}
#endif
if (afl->post_library_mutator)
list_append(&afl->custom_mutator_list, afl->post_library_mutator);
}
void destroy_custom_mutator(afl_state_t *afl) {
void destroy_custom_mutators(afl_state_t *afl) {
if (afl->mutator) {
if (afl->custom_mutators_count) {
afl->mutator->afl_custom_deinit(afl->mutator->data);
LIST_FOREACH_CLEAR(&afl->custom_mutator_list, struct custom_mutator, {
if (afl->mutator->dh) dlclose(afl->mutator->dh);
if (!el->data) { FATAL("Deintializing NULL mutator"); }
if (el->afl_custom_deinit) el->afl_custom_deinit(el->data);
if (el->dh) dlclose(el->dh);
if (afl->mutator->pre_save_buf) {
if (el->post_process_buf) {
ck_free(afl->mutator->pre_save_buf);
afl->mutator->pre_save_buf = NULL;
afl->mutator->pre_save_size = 0;
ck_free(el->post_process_buf);
el->post_process_buf = NULL;
el->post_process_size = 0;
}
}
ck_free(afl->mutator);
afl->mutator = NULL;
ck_free(el);
});
}
}
void load_custom_mutator(afl_state_t *afl, const char *fn) {
struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
void *dh;
afl->mutator = ck_alloc(sizeof(struct custom_mutator));
afl->mutator->pre_save_buf = NULL;
afl->mutator->pre_save_size = 0;
void * dh;
struct custom_mutator *mutator = ck_alloc(sizeof(struct custom_mutator));
afl->mutator->name = fn;
mutator->name = fn;
ACTF("Loading custom mutator library from '%s'...", fn);
dh = dlopen(fn, RTLD_NOW);
if (!dh) FATAL("%s", dlerror());
afl->mutator->dh = dh;
mutator->dh = dh;
/* Mutator */
/* "afl_custom_init", required */
afl->mutator->afl_custom_init = dlsym(dh, "afl_custom_init");
if (!afl->mutator->afl_custom_init)
FATAL("Symbol 'afl_custom_init' not found.");
/* "afl_custom_deinit", required */
afl->mutator->afl_custom_deinit = dlsym(dh, "afl_custom_deinit");
if (!afl->mutator->afl_custom_deinit)
FATAL("Symbol 'afl_custom_deinit' not found.");
/* "afl_custom_init", optional for backward compatibility */
mutator->afl_custom_init = dlsym(dh, "afl_custom_init");
if (!mutator->afl_custom_init) FATAL("Symbol 'afl_custom_init' not found.");
/* "afl_custom_fuzz" or "afl_custom_mutator", required */
afl->mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_fuzz");
if (!afl->mutator->afl_custom_fuzz) {
mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_fuzz");
if (!mutator->afl_custom_fuzz) {
/* Try "afl_custom_mutator" for backward compatibility */
WARNF("Symbol 'afl_custom_fuzz' not found. Try 'afl_custom_mutator'.");
afl->mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_mutator");
if (!afl->mutator->afl_custom_fuzz)
FATAL("Symbol 'afl_custom_mutator' not found.");
mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_mutator");
if (!mutator->afl_custom_fuzz)
WARNF("Symbol 'afl_custom_mutator' not found.");
}
/* "afl_custom_pre_save", optional */
afl->mutator->afl_custom_pre_save = dlsym(dh, "afl_custom_pre_save");
if (!afl->mutator->afl_custom_pre_save)
WARNF("Symbol 'afl_custom_pre_save' not found.");
/* "afl_custom_deinit", optional for backward compatibility */
mutator->afl_custom_deinit = dlsym(dh, "afl_custom_deinit");
if (!mutator->afl_custom_deinit) FATAL("Symbol 'afl_custom_init' not found.");
/* "afl_custom_post_process", optional */
mutator->afl_custom_post_process = dlsym(dh, "afl_custom_post_process");
if (!mutator->afl_custom_post_process)
ACTF("optional symbol 'afl_custom_post_process' not found.");
u8 notrim = 0;
/* "afl_custom_init_trim", optional */
afl->mutator->afl_custom_init_trim = dlsym(dh, "afl_custom_init_trim");
if (!afl->mutator->afl_custom_init_trim)
WARNF("Symbol 'afl_custom_init_trim' not found.");
mutator->afl_custom_init_trim = dlsym(dh, "afl_custom_init_trim");
if (!mutator->afl_custom_init_trim)
ACTF("optional symbol 'afl_custom_init_trim' not found.");
/* "afl_custom_trim", optional */
afl->mutator->afl_custom_trim = dlsym(dh, "afl_custom_trim");
if (!afl->mutator->afl_custom_trim)
WARNF("Symbol 'afl_custom_trim' not found.");
mutator->afl_custom_trim = dlsym(dh, "afl_custom_trim");
if (!mutator->afl_custom_trim)
ACTF("optional symbol 'afl_custom_trim' not found.");
/* "afl_custom_post_trim", optional */
afl->mutator->afl_custom_post_trim = dlsym(dh, "afl_custom_post_trim");
if (!afl->mutator->afl_custom_post_trim)
WARNF("Symbol 'afl_custom_post_trim' not found.");
mutator->afl_custom_post_trim = dlsym(dh, "afl_custom_post_trim");
if (!mutator->afl_custom_post_trim)
ACTF("optional symbol 'afl_custom_post_trim' not found.");
if (notrim) {
afl->mutator->afl_custom_init_trim = NULL;
afl->mutator->afl_custom_trim = NULL;
afl->mutator->afl_custom_post_trim = NULL;
WARNF(
mutator->afl_custom_init_trim = NULL;
mutator->afl_custom_trim = NULL;
mutator->afl_custom_post_trim = NULL;
ACTF(
"Custom mutator does not implement all three trim APIs, standard "
"trimming will be used.");
}
/* "afl_custom_havoc_mutation", optional */
afl->mutator->afl_custom_havoc_mutation =
dlsym(dh, "afl_custom_havoc_mutation");
if (!afl->mutator->afl_custom_havoc_mutation)
WARNF("Symbol 'afl_custom_havoc_mutation' not found.");
mutator->afl_custom_havoc_mutation = dlsym(dh, "afl_custom_havoc_mutation");
if (!mutator->afl_custom_havoc_mutation)
ACTF("optional symbol 'afl_custom_havoc_mutation' not found.");
/* "afl_custom_havoc_mutation", optional */
afl->mutator->afl_custom_havoc_mutation_probability =
mutator->afl_custom_havoc_mutation_probability =
dlsym(dh, "afl_custom_havoc_mutation_probability");
if (!afl->mutator->afl_custom_havoc_mutation_probability)
WARNF("Symbol 'afl_custom_havoc_mutation_probability' not found.");
if (!mutator->afl_custom_havoc_mutation_probability)
ACTF("optional symbol 'afl_custom_havoc_mutation_probability' not found.");
/* "afl_custom_queue_get", optional */
afl->mutator->afl_custom_queue_get = dlsym(dh, "afl_custom_queue_get");
if (!afl->mutator->afl_custom_queue_get)
WARNF("Symbol 'afl_custom_queue_get' not found.");
mutator->afl_custom_queue_get = dlsym(dh, "afl_custom_queue_get");
if (!mutator->afl_custom_queue_get)
ACTF("optional symbol 'afl_custom_queue_get' not found.");
/* "afl_custom_queue_new_entry", optional */
afl->mutator->afl_custom_queue_new_entry =
dlsym(dh, "afl_custom_queue_new_entry");
if (!afl->mutator->afl_custom_queue_new_entry)
WARNF("Symbol 'afl_custom_queue_new_entry' not found");
mutator->afl_custom_queue_new_entry = dlsym(dh, "afl_custom_queue_new_entry");
if (!mutator->afl_custom_queue_new_entry)
ACTF("optional symbol 'afl_custom_queue_new_entry' not found");
OKF("Custom mutator '%s' installed successfully.", fn);
/* Initialize the custom mutator */
if (afl->mutator->afl_custom_init)
afl->mutator->data =
afl->mutator->afl_custom_init(afl, rand_below(afl, 0xFFFFFFFF));
if (mutator->afl_custom_init)
mutator->data = mutator->afl_custom_init(afl, rand_below(afl, 0xFFFFFFFF));
mutator->stacked_custom = (mutator && mutator->afl_custom_havoc_mutation);
mutator->stacked_custom_prob =
6; // like one of the default mutations in havoc
return mutator;
}
u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
struct custom_mutator *mutator) {
u8 needs_write = 0, fault = 0;
u32 trim_exec = 0;
@ -208,14 +254,20 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
/* Initialize trimming in the custom mutator */
afl->stage_cur = 0;
afl->stage_max =
afl->mutator->afl_custom_init_trim(afl->mutator->data, in_buf, q->len);
if (unlikely(afl->stage_max) < 0)
afl->stage_max = mutator->afl_custom_init_trim(mutator->data, in_buf, q->len);
if (unlikely(afl->stage_max) < 0) {
FATAL("custom_init_trim error ret: %d", afl->stage_max);
if (afl->not_on_tty && afl->debug)
}
if (afl->not_on_tty && afl->debug) {
SAYF("[Custom Trimming] START: Max %d iterations, %u bytes", afl->stage_max,
q->len);
}
while (afl->stage_cur < afl->stage_max) {
u8 *retbuf = NULL;
@ -225,15 +277,20 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
u32 cksum;
size_t retlen = afl->mutator->afl_custom_trim(afl->mutator->data, &retbuf);
size_t retlen = mutator->afl_custom_trim(mutator->data, &retbuf);
if (unlikely(!retbuf)) {
if (unlikely(!retbuf))
FATAL("custom_trim failed (ret %zd)", retlen);
else if (unlikely(retlen > orig_len))
} else if (unlikely(retlen > orig_len)) {
FATAL(
"Trimmed data returned by custom mutator is larger than original "
"data");
}
write_to_testcase(afl, retbuf, retlen);
fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
@ -260,35 +317,46 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
}
/* Tell the custom mutator that the trimming was successful */
afl->stage_cur =
afl->mutator->afl_custom_post_trim(afl->mutator->data, 1);
afl->stage_cur = mutator->afl_custom_post_trim(mutator->data, 1);
if (afl->not_on_tty && afl->debug) {
if (afl->not_on_tty && afl->debug)
SAYF("[Custom Trimming] SUCCESS: %d/%d iterations (now at %u bytes)",
afl->stage_cur, afl->stage_max, q->len);
}
} else {
/* Tell the custom mutator that the trimming was unsuccessful */
afl->stage_cur =
afl->mutator->afl_custom_post_trim(afl->mutator->data, 0);
if (unlikely(afl->stage_cur < 0))
afl->stage_cur = mutator->afl_custom_post_trim(mutator->data, 0);
if (unlikely(afl->stage_cur < 0)) {
FATAL("Error ret in custom_post_trim: %d", afl->stage_cur);
if (afl->not_on_tty && afl->debug)
}
if (afl->not_on_tty && afl->debug) {
SAYF("[Custom Trimming] FAILURE: %d/%d iterations", afl->stage_cur,
afl->stage_max);
}
}
/* Since this can be slow, update the screen every now and then. */
if (!(trim_exec++ % afl->stats_update_freq)) show_stats(afl);
if (!(trim_exec++ % afl->stats_update_freq)) { show_stats(afl); }
}
if (afl->not_on_tty && afl->debug)
if (afl->not_on_tty && afl->debug) {
SAYF("[Custom Trimming] DONE: %u bytes -> %u bytes", orig_len, q->len);
}
/* If we have made changes to in_buf, we also need to update the on-disk
version of the test case. */
@ -300,7 +368,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, 0600);
if (fd < 0) PFATAL("Unable to create '%s'", q->fname);
if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); }
ck_write(fd, in_buf, q->len, q->fname);
close(fd);

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