Compare commits

...

184 Commits
3.10c ... 3.12c

Author SHA1 Message Date
2dac4e785f Merge pull request #837 from AFLplusplus/dev
final pull to stable
2021-03-24 11:23:01 +01:00
2b3642aa39 v3.12c ready to go 2021-03-24 11:13:16 +01:00
d68bd656fe fix counting favorites 2021-03-24 11:12:44 +01:00
8bd5d7676e 3.12c 2021-03-24 11:12:44 +01:00
70c1de5d64 better forkserver error help and code format 2021-03-24 11:12:44 +01:00
2fef89950f v3.12c release 2021-03-24 11:12:44 +01:00
a908a98225 update qemuafl 2021-03-24 11:06:02 +01:00
82554677a8 update qemuafl 2021-03-24 11:00:13 +01:00
dfe6f7f8c9 make setting different file permissions easy via config.h 2021-03-23 20:21:08 +01:00
5fcd634f05 fixed tiny nitpicks 2021-03-23 18:47:07 +01:00
28f1e94ab9 fix our PCGUARD for llvm 10.0.1 2021-03-23 15:33:27 +01:00
e1d37a802b Merge pull request #836 from jtpereyda/doc-update-missing-crashes
add details to AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES doc
2021-03-22 21:44:12 +01:00
0f9dceff3d add details to AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES doc 2021-03-22 12:06:52 -07:00
8868648f76 fix LTO selective instrumentation 2021-03-22 10:45:39 +01:00
72a70423c2 show afl-cc NATIVE when auto used 2021-03-22 09:24:36 +01:00
84534ae2e8 format 2021-03-21 16:23:08 +01:00
687dd9cb67 add missing links for afl-clang-fast*.8 man pages 2021-03-20 13:15:56 +01:00
ede03a96ed IDA script for loading unicorn AFL context dumps (#812)
* IDA script for loading unicorn AFL context dumps

This script can be used to load context dumps into an IDA database for
analysis. It requires that you first open the main executable into IDA
directly. Then, you can run the script and select the _index.json file.
From there, the script will rebase the main executable and map in all
the other dumped vmem from the context dump directory

* Modified ida_context_loader.py header comment

No specifies the full URL for the unicon_dumper_gdb.py script
2021-03-20 09:36:25 +01:00
33dd2ce021 close fds when executing one by one. (#835)
* closes fd when executing one by one.

* clean aflpp_driver
2021-03-20 09:34:40 +01:00
bc0ff559f5 Merge pull request #824 from fuzzah/dev
add AFL_TARGET_ENV to afl-fuzz
2021-03-19 23:55:32 +01:00
090128b3f8 Merge branch 'dev' into dev 2021-03-19 23:54:36 +01:00
d7e121e2c9 add AFL_TARGET_ENV to afl-fuzz 2021-03-20 01:32:28 +03:00
749b03d812 Merge pull request #830 from richinseattle/dev
preserve plot_data for in-place resume
2021-03-19 23:26:34 +01:00
fc73a18e9a Merge pull request #834 from devnexen/libdislocator_fbsd_13_upd
libdislocator freebsd 13 update to amke it works
2021-03-19 23:23:25 +01:00
7e67a735e6 update plot_data timestamps to be relative 2021-03-19 14:25:55 -07:00
14e1b0ffba libdislocator freebsd 13 update to amke it works
with vm.imply_prot_max set.
2021-03-19 21:19:22 +00:00
e98cd00822 Merge pull request #831 from AFLplusplus/dev
Push to stable
2021-03-19 19:04:59 +01:00
2102264acf fix for new llvm 13 change 2021-03-19 16:06:06 +01:00
e73c7c59c1 refactor finding binaries 2021-03-19 14:55:25 +01:00
99525dee38 remove unneeded code 2021-03-19 10:57:18 +01:00
848ea17154 add header to PCGUARD 2021-03-19 10:42:23 +01:00
1cdf0a898c update test-dlopen tuples number 2021-03-19 09:58:27 +01:00
00913bce81 update dynamic list with cmplog 2021-03-19 09:56:00 +01:00
5be7d9c1cc fix dynamic list usage error in afl-cc 2021-03-19 09:44:04 +01:00
44347beff0 check test-dlopen return code 2021-03-18 21:44:20 +01:00
166c8f93b5 test-dlopen llvm test 2021-03-18 21:34:12 +01:00
9393452d1c The official casing is AFLplusplus 2021-03-18 18:42:33 +01:00
66fa76a061 typo 2021-03-18 16:41:02 +01:00
d2e7c4ec05 better installation example 2021-03-18 14:04:18 +01:00
10fb46301c afl-fuzz cleanup 2021-03-18 11:05:53 +01:00
c397becd81 Merge branch 'dev' of https://github.com/AFLplusplus/AFLplusplus into dev 2021-03-18 01:37:40 -07:00
62508c3b44 preserve plot_data for in-place resume 2021-03-18 01:34:05 -07:00
94312796f9 better map variability 2021-03-17 13:16:02 +01:00
adeeed9e43 fix dynamic list 2021-03-17 12:48:30 +01:00
513bd70384 shared linking fix 2021-03-17 12:44:07 +01:00
cdd30c766b fix m32/m64 2021-03-17 11:25:14 +01:00
5e2a5f1110 shmem map size in config.h 2021-03-17 10:27:23 +01:00
a7797f0cb9 fix is now closer to original statement 2021-03-17 08:04:29 +01:00
b715050de9 deepclean no longer removes submodules 2021-03-17 05:13:34 +01:00
da5a32792d bring back unicornafl 2021-03-17 04:56:24 +01:00
f36341b3b4 when you think you work on a debug branch but it is dev. git sucks so much ... 2021-03-17 02:00:14 +01:00
dda4757b35 debug 2021-03-17 01:40:27 +01:00
c6f1c56c15 fix 2021-03-17 01:27:01 +01:00
413807db01 lto test 2021-03-17 01:25:21 +01:00
f59ef29c26 fix attempt 2021-03-17 01:08:10 +01:00
65b90001f6 debug 2021-03-16 23:24:34 +01:00
6840e8fd2a fix two bugs in error message
$1 and $2 have been modified here by two previous shift commands.
2021-03-16 22:58:10 +01:00
7c2436c711 no runtime for shared linking 2021-03-16 19:34:34 +01:00
c2df65a0af Merge branch 'dev' of github.com:AFLplusplus/AFLplusplus into dev 2021-03-16 17:04:59 +01:00
175a275a3d changelog 2021-03-16 17:04:52 +01:00
bd64315395 blacklist sanitize and debug in c++ 2021-03-16 16:54:48 +01:00
65e3770bad qemuafl 2021-03-16 16:32:35 +01:00
f5420e737a rtn fix 2021-03-16 16:15:29 +01:00
4e567d3f5d update qemuafl 2021-03-16 15:38:45 +01:00
1227776251 fix cmplog 2021-03-16 14:39:48 +01:00
862cb3217f fix cmplog rtn 2021-03-16 14:38:13 +01:00
8e11546536 Merge pull request #816 from realmadsci/add-more-qasan-checks
Add more qasan checks
2021-03-16 09:10:42 +01:00
73641be796 Merge pull request #819 from realmadsci/qemu-consistent-preload
Remove AFL_PRELOAD and AFL_USE_QASAN handlers
2021-03-16 09:08:23 +01:00
ff9f3fbe96 Merge pull request #818 from realmadsci/add-qemu-custom-bin
Add AFL_QEMU_CUSTOM_BIN environment flag
2021-03-16 09:01:13 +01:00
1dcc3549b6 v3.12a init 2021-03-15 23:21:03 +01:00
23f7bee81c Merge pull request #820 from AFLplusplus/dev
push to stable
2021-03-15 23:14:07 +01:00
ac795ae1e1 v3.11c release 2021-03-15 23:08:28 +01:00
aa6a50c2b4 fix test 2021-03-15 23:01:07 +01:00
01ad7610be Remove AFL_PRELOAD and AFL_USE_QASAN handlers
These are now processed in afl-qemu-trace so that the "copy+paste" code
that is in all of the other AFL tools can be removed.

This also allows the AFL_USE_QASAN flag to work the same when used
with tools like afl-fuzz as it does with afl-qemu-trace. This is
important in situations where loading the QASAN library changes
the address of your desired entrypoint, or for crash validation
using the same environment that afl-fuzz was using.

With this change, the same set of environment variables can be used
in exactly the same way between afl-fuzz, afl-showmap, and
afl-qemu-trace, and you will get exactly the same guest environment.
2021-03-15 13:03:16 -07:00
d4fb7f8b40 Add AFL_QEMU_CUSTOM_BIN environment flag
In QEMU mode (-Q), setting AFL_QEMU_CUSTOM_BIN cause afl-fuzz to skip
prepending afl-qemu-trace to your command line. Use this if you wish to use a
custom afl-qemu-trace or if you need to modify the afl-qemu-trace arguments.
2021-03-15 12:57:06 -07:00
61c8304f24 fixes 2021-03-15 20:32:01 +01:00
96574854b3 libqasan/malloc: Additional pointer checks
Add checks to free() and malloc_usable_size() to
verify (sort of) that the pointers are actually
pointing at valid allocated memory before dereferencing
them and using the chunk_begin struct info.

This will catch use-after-free and wildly bad pointers
a little bit earlier.
2021-03-15 12:07:22 -07:00
281cd47c15 libqasan: Add checks for read() and write() 2021-03-15 12:07:22 -07:00
01ad0f3c6a Merge pull request #813 from MarcoFalke/patch-1
doc: Clarify default value of N iterations in aflpp_driver
2021-03-13 13:08:58 +01:00
db342c9c81 doc: Clarify default value of N iterations in aflpp_driver 2021-03-13 11:03:08 +01:00
f1d8a01047 added ui change to changelog 2021-03-12 03:55:18 +01:00
3753f56c25 make get_offsets executable 2021-03-12 03:47:12 +01:00
d32b1d6b0c unique crashes yellow on resume (#801) 2021-03-12 03:46:50 +01:00
e5bdba4b9f Merge pull request #807 from AFLplusplus/dev
push to stable
2021-03-11 19:13:53 +01:00
c725cb71de more time for fp split 2021-03-11 19:12:21 +01:00
8ff5063545 fix 2021-03-11 18:03:18 +01:00
e549102563 Merge pull request #806 from AFLplusplus/dev
Dev
2021-03-11 09:43:27 +01:00
b7d90a9e31 new auto map 2021-03-11 09:32:22 +01:00
adeb0d18b1 fix the auto map fix 2021-03-11 08:59:34 +01:00
16e3e2a7f7 implemented #801 2021-03-11 01:39:21 +01:00
0484d9b024 more time for float split test 2021-03-11 00:49:23 +01:00
d60bbff0d9 more time for tests 2021-03-11 00:17:52 +01:00
966eba50a6 Revert "PFATAL for libdislocator"
This reverts commit ffd8fae22a.
2021-03-10 22:51:05 +01:00
ffd8fae22a PFATAL for libdislocator 2021-03-10 22:46:38 +01:00
cb0fe044dd Merge pull request #802 from MarcoFalke/patch-1
doc: Clarify memory limits in Readme
2021-03-10 22:39:05 +01:00
4f3b5f8adc doc: Clarify memory limits in Readme 2021-03-10 20:59:30 +01:00
3bb12b456f Merge pull request #800 from AFLplusplus/dev
push to stable
2021-03-10 19:33:50 +01:00
a10a627622 fix auto map discovery 2021-03-10 19:22:57 +01:00
2777784f4f fix man path 2021-03-10 18:43:30 +01:00
4bd0d4cbaf cmplog finetuning 2021-03-10 15:52:27 +01:00
2d92bb483e Merge pull request #786 from AFLplusplus/dev
push to stable
2021-03-10 15:45:14 +01:00
071edb1a2d brackets make dominik happy 2021-03-10 15:44:54 +01:00
7f36290703 Merge pull request #790 from rchildre3/qemu-deps
Remove QEMU dependency checks
2021-03-10 15:42:32 +01:00
6cc59a38be gsoc2021 clarification 2021-03-10 15:37:28 +01:00
87eb44abe4 Remove QEMU dependency checks
Most of these packages (bison, flex, pixman (in non-system mode)) are no
longer dependencies of QEMU and regardless, QEMU's build system is quite
capable of finding dependencies by itself and will error out
accordingly.  This prevents having to further change this code as QEMU's
dependencies inevitably change.
2021-03-10 09:12:41 -05:00
a0c3011673 change map_size tests 2021-03-10 11:08:03 +01:00
69f3095045 correct debug 2021-03-10 10:40:52 +01:00
d678d59372 fix 2021-03-10 10:07:54 +01:00
b2feada293 rt debug 2021-03-10 10:04:45 +01:00
bff02dae0d cmplog rtn rt fix 2021-03-10 09:32:54 +01:00
851231c846 fixed scan-build warnings 2021-03-10 01:15:38 +01:00
f21a5c42c1 tiny typo fixed 2021-03-10 00:55:26 +01:00
d471fc9509 add version dependency 2021-03-10 00:07:33 +01:00
9f22a151f3 mention added support for gcc_plugin mode 2021-03-09 23:55:22 +01:00
0c2478cae6 typos, small additions 2021-03-09 23:27:14 +01:00
b865fc6080 typos, rewording 2021-03-09 23:04:53 +01:00
d44b650cd4 typo 2021-03-09 22:14:34 +01:00
aa12e46013 formatting and RedQueen reference added 2021-03-09 22:09:58 +01:00
2c18fbbb2e Merge pull request #787 from devnexen/mac_m1_thr_priority
setting general schedule priority for performance on Mac.
2021-03-09 22:05:53 +01:00
4131965d48 md formatting 2021-03-09 21:59:31 +01:00
5fab0fa51f setting general schedule priority for performance on Mac. 2021-03-09 20:27:48 +00:00
9c9232b4e8 Merge pull request #789 from wyattearp/dev
documentation correction & formatting
2021-03-09 21:13:41 +01:00
0d6e571237 better CROSS detection 2021-03-09 21:11:44 +01:00
40ba8814b3 better CROSS detection 2021-03-09 21:05:58 +01:00
a0a917ad87 better CROSS detection 2021-03-09 21:03:18 +01:00
8628839c55 relsolving merge 2021-03-09 15:03:05 -05:00
5001779984 documentation correction & formatting
* fixed up manual define for `__AFL_LOOP()`
* added the code language formaters to the various blocks
* fixed a couple of missing backticks
2021-03-09 15:01:52 -05:00
93d91dd7a1 documentation correction & formatting
* fixed up manual define for `__AFL_LOOP()`
* added the code language formaters to the various blocks
* fixed a couple of missing backticks
2021-03-09 14:57:40 -05:00
791c5c171d fix ctx-1 2021-03-09 18:44:42 +01:00
a723156740 Merge pull request #785 from MarcoFalke/patch-1
doc: Add lld to required dependencies
2021-03-09 17:22:13 +01:00
0868ea8348 fix compiler rt on -c 2021-03-09 17:15:19 +01:00
5a6ad71f3f doc: Add lld to required dependencies 2021-03-09 17:08:55 +01:00
47f2650a32 add AFL_NOOPT 2021-03-09 16:53:56 +01:00
74a6044b3f fix sanitizer settings 2021-03-09 14:11:52 +01:00
e82ce95251 remove duplicate 2021-03-08 18:12:18 +01:00
e226d1bbb3 update changelog 2021-03-08 15:16:43 +01:00
54c1087340 more system speed in afl-system-config 2021-03-08 15:12:54 +01:00
eb1e8619eb fix handling of test case file names with spaces 2021-03-08 14:55:48 +01:00
c96fca6833 Merge pull request #779 from AFLplusplus/top-k-ctx
Restore correct CTX behaviour and enable K-CTX coverage for LLVM Classic
2021-03-08 09:50:18 +01:00
976cb3e36c Merge pull request #778 from AFLplusplus/dev
This fixes 3 different crash issues
2021-03-06 18:47:58 +01:00
9b3d8c327d fix for asan compile rt 2021-03-06 10:20:01 +01:00
7b907e45ad we do not support 80 + 128 bit FP in laf 2021-03-05 19:55:29 +01:00
e8d580f54d rust mutator changes added to changelog 2021-03-05 19:45:48 +01:00
2dd5a02061 Ergonomic Improvements for Rust Custom Mutators (#772)
* allow returning of str instead of CStr in rust custom mutator

* use OsStr instead of CStr for file paths

* fix cfg and compiler errors

* custom mutator default descriptions

* fix usage of afl_internal feature flag

* fix example mutator cfg

* fix lain mutator

* Revert "fix lain mutator"

This reverts commit adf7001808.

* actually fix lain mutator

* resolve question around utf-8 null bytes

* change from OsStr to Path to be even more ergonomic

* add rust custom mutator ci

* fix github action

* again

* separate compilation check
2021-03-05 19:40:59 +01:00
9844e1a856 fix 2021-03-05 19:32:27 +01:00
44be521ab8 fix 2021-03-05 19:19:43 +01:00
c9819e3b94 reduce github action minutes 2021-03-05 18:24:41 +01:00
16d6f35aa6 typos 2021-03-05 18:11:05 +01:00
c9854ec8cb typo 2021-03-05 18:07:16 +01:00
c429021de1 fix typos and format 2021-03-05 15:27:10 +01:00
41ad23041b remove warnings 2021-03-05 14:58:37 +01:00
3e5ac0af52 no static for rt initialized markers 2021-03-05 10:21:28 +01:00
f848562732 point explicitly to AFL_MAP_SIZE on problems 2021-03-05 10:15:38 +01:00
3342aa751d fix laf string transform crash 2021-03-05 10:05:43 +01:00
a2f40aa285 disable corpus introspection, potentially creates huge data 2021-03-04 22:10:32 +01:00
f34a860d5f NO_ARCH_OPT was removed due many issues 2021-03-04 20:14:47 +01:00
af9aeb89d4 afl-cc code for k-ctx 2021-03-04 15:26:15 +01:00
be5274d4a9 fix kctx compilation hang 2021-03-04 15:12:08 +01:00
b6dc529bc3 no ASAN odr violations by default 2021-03-04 14:55:57 +01:00
0aa93afeb8 vectorial top-k CTX first implementation 2021-03-04 14:50:26 +01:00
79d75d8e42 even support dlopen instrumented libs after the forkserver 2021-03-04 14:19:00 +01:00
96c526cb78 fix caller/ctx change, support dlopen in afl-compiler-rt 2021-03-04 14:04:40 +01:00
02f3319256 only initialize afl-compiler-rt once 2021-03-04 12:23:27 +01:00
8f538e77ed code format 2021-03-04 11:33:51 +01:00
1e76079e93 llvm mode CALLER mode 2021-03-04 11:32:32 +01:00
0e736276e6 restore correct CTX behaviour in llvm mode 2021-03-04 11:00:54 +01:00
08ef8d6b78 NO_CHECKOUT=1 ./build_qemu_support.sh 2021-03-04 10:57:00 +01:00
3977d50b55 update qemuafl and remove git stas 2021-03-04 10:52:22 +01:00
3bcfbf5038 Merge pull request #776 from realmadsci/afl-exclude-ranges
Add AFL_QEMU_EXCLUDE_RANGES
2021-03-04 10:33:16 +01:00
f0c7967fbf add new tutorial 2021-03-03 08:58:09 +01:00
8bdb40b763 cpu-exec: Add AFL_QEMU_EXCLUDE_RANGES
This environment variable allows rejection of
specific regions from instrumentation.

It takes priority over AFL_INST_LIBS and AFL_QEMU_INST_RANGES,
so it can be used to poke a "hole" in previously included sections.
2021-03-02 12:55:44 -08:00
f0bc2e0e8b docu 2021-03-02 18:45:41 +01:00
108e588e88 add de-unicoded dictionary entries 2021-03-02 17:46:43 +01:00
333509bb0a better unicode support 2021-03-02 16:24:43 +01:00
c269c3977c fix llvm for unicode strings (hopefully) 2021-03-02 11:38:12 +01:00
c3a8052a16 update changelog 2021-03-01 19:30:39 +01:00
d0a61279b8 write to correct pipe end 2021-03-01 19:15:58 +01:00
7259075b71 len for cmplog rtn 2021-03-01 19:13:29 +01:00
14fd477147 better fix for asan? 2021-03-01 19:03:25 +01:00
05e2f577f6 fix area_is_valid with write 2021-03-01 17:21:27 +01:00
a29b360d55 area_is_valid with write 2021-03-01 17:16:34 +01:00
75d6a8b701 fix last commit 2021-03-01 15:33:28 +01:00
ad7a7fcf07 ASan-compatible area_is_mapped() 2021-03-01 15:30:55 +01:00
82c05630ba 3.11a init 2021-03-01 10:12:42 +01:00
79 changed files with 2298 additions and 1468 deletions

View File

@ -0,0 +1,30 @@
name: Rust Custom Mutators
on:
push:
branches: [ stable, dev ]
pull_request:
branches: [ stable, dev ]
jobs:
test:
name: Test Rust Custom Mutator Support
runs-on: '${{ matrix.os }}'
defaults:
run:
working-directory: custom_mutators/rust
strategy:
matrix:
os: [ubuntu-20.04]
steps:
- uses: actions/checkout@v2
- name: Install Rust Toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Check Code Compiles
run: cargo check
- name: Run General Tests
run: cargo test
- name: Run Tests for afl_internals feature flag
run: cd custom_mutator && cargo test --features=afl_internals

1
.gitignore vendored
View File

@ -65,7 +65,6 @@ qemu_mode/qemu-*
qemu_mode/qemuafl
unicorn_mode/samples/*/\.test-*
unicorn_mode/samples/*/output/
unicorn_mode/unicornafl
test/unittests/unit_maybe_alloc
test/unittests/unit_preallocable
test/unittests/unit_list

View File

@ -24,7 +24,7 @@ BIN_PATH = $(PREFIX)/bin
HELPER_PATH = $(PREFIX)/lib/afl
DOC_PATH = $(PREFIX)/share/doc/afl
MISC_PATH = $(PREFIX)/share/afl
MAN_PATH = $(PREFIX)/man/man8
MAN_PATH = $(PREFIX)/share/man/man8
PROGNAME = afl
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
@ -364,7 +364,6 @@ help:
@echo NO_PYTHON - disable python support
@echo NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
@echo AFL_NO_X86 - if compiling on non-intel/amd platforms
@echo NO_ARCH_OPT - builds afl++ without machine architecture optimizations
@echo "LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g. Debian)"
@echo "=========================================="
@echo e.g.: make ASAN_BUILD=1
@ -559,6 +558,7 @@ clean:
-$(MAKE) -f GNUmakefile.gcc_plugin clean
$(MAKE) -C utils/libdislocator clean
$(MAKE) -C utils/libtokencap clean
$(MAKE) -C utils/aflpp_driver clean
$(MAKE) -C utils/afl_network_proxy clean
$(MAKE) -C utils/socket_fuzzing clean
$(MAKE) -C utils/argv_fuzzing clean
@ -577,7 +577,11 @@ endif
deepclean: clean
rm -rf unicorn_mode/unicornafl
rm -rf qemu_mode/qemuafl
ifeq "$(IN_REPO)" "1"
# NEVER EVER ACTIVATE THAT!!!!! git reset --hard >/dev/null 2>&1 || true
git checkout unicorn_mode/unicornafl
git checkout qemu_mode/qemuafl
endif
.PHONY: distrib
distrib: all

View File

@ -507,6 +507,8 @@ install: all
@echo .SH LICENSE >> ./$@
@echo Apache License Version 2.0, January 2004 >> ./$@
@ln -sf afl-cc.8 ./afl-c++.8
@ln -sf afl-cc.8 ./afl-clang-fast.8
@ln -sf afl-cc.8 ./afl-clang-fast++.8
ifneq "$(AFL_CLANG_FLTO)" ""
ifeq "$(LLVM_LTO)" "1"
@ln -sf afl-cc.8 ./afl-clang-lto.8

View File

@ -2,9 +2,9 @@
<img align="right" src="https://raw.githubusercontent.com/andreafioraldi/AFLplusplus-website/master/static/logo_256x256.png" alt="AFL++ Logo">
Release Version: [3.10c](https://github.com/AFLplusplus/AFLplusplus/releases)
Release Version: [3.12c](https://github.com/AFLplusplus/AFLplusplus/releases)
Github Version: 3.11a
Github Version: 3.13a
Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
@ -175,7 +175,13 @@ If you want to build afl++ yourself you have many options.
The easiest choice is to build and install everything:
```shell
sudo apt install build-essential python3-dev automake flex bison libglib2.0-dev libpixman-1-dev clang python3-setuptools clang llvm llvm-dev libstdc++-dev
sudo apt-get update
sudo apt-get install -y build-essential python3-dev automake git flex bison libglib2.0-dev libpixman-1-dev python3-setuptools
# try to install llvm 11 and install the distro default if that fails
sudo apt-get install -y lld-11 llvm-11 llvm-11-dev clang-11 || sudo apt-get install -y lld llvm llvm-dev clang
sudo apt-get install -y gcc-$(gcc --version|head -n1|sed 's/.* //'|sed 's/\..*//')-plugin-dev libstdc++-$(gcc --version|head -n1|sed 's/.* //'|sed 's/\..*//')-dev
git clone https://github.com/AFLplusplus/AFLplusplus && cd AFLplusplus
cd AFLplusplus
make distrib
sudo make install
```
@ -224,10 +230,9 @@ These build options exist:
* NO_PYTHON - disable python support
* NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
* AFL_NO_X86 - if compiling on non-intel/amd platforms
* NO_ARCH_OPT - builds afl++ without machine architecture optimizations
* LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g. Debian)
e.g.: make ASAN_BUILD=1
e.g.: `make ASAN_BUILD=1`
## Good examples and writeups
@ -239,6 +244,7 @@ Here are some good writeups to show how to effectively use AFL++:
* [https://securitylab.github.com/research/fuzzing-software-2](https://securitylab.github.com/research/fuzzing-software-2)
* [https://securitylab.github.com/research/fuzzing-sockets-FTP](https://securitylab.github.com/research/fuzzing-sockets-FTP)
* [https://securitylab.github.com/research/fuzzing-sockets-FreeRDP](https://securitylab.github.com/research/fuzzing-sockets-FreeRDP)
* [https://securitylab.github.com/research/fuzzing-apache-1](https://securitylab.github.com/research/fuzzing-apache-1)
If you are interested in fuzzing structured data (where you define what the
structure is), these links have you covered:
@ -304,7 +310,7 @@ Clickable README links for the chosen compiler:
* [LTO mode - afl-clang-lto](instrumentation/README.lto.md)
* [LLVM mode - afl-clang-fast](instrumentation/README.llvm.md)
* [GCC_PLUGIN mode - afl-gcc-fast](instrumentation/README.gcc_plugin.md)
* GCC/CLANG mode (afl-gcc/afl-clang) have no README as they have no own features
* GCC/CLANG modes (afl-gcc/afl-clang) have no README as they have no own features
You can select the mode for the afl-cc compiler by:
1. use a symlink to afl-cc: afl-gcc, afl-g++, afl-clang, afl-clang++,
@ -399,10 +405,19 @@ How to do this is described below.
Then build the target. (Usually with `make`)
**NOTE**: sometimes configure and build systems are fickle and do not like
stderr output (and think this means a test failure) - which is something
afl++ like to do to show statistics. It is recommended to disable them via
`export AFL_QUIET=1`.
**NOTES**
1. sometimes configure and build systems are fickle and do not like
stderr output (and think this means a test failure) - which is something
afl++ likes to do to show statistics. It is recommended to disable them via
`export AFL_QUIET=1`.
2. sometimes configure and build systems error on warnings - these should be
disabled (e.g. `--disable-werror` for some configure scripts).
3. in case the configure/build system complains about afl++'s compiler and
aborts then set `export AFL_NOOPT=1` which will then just behave like the
real compiler. This option has to be unset again before building the target!
##### configure
@ -484,8 +499,9 @@ default.
#### c) Minimizing all corpus files
The shorter the input files that still traverse the same path
within the target, the better the fuzzing will be. This is done with `afl-tmin`
however it is a long process as this has to be done for every file:
within the target, the better the fuzzing will be. This minimization
is done with `afl-tmin` however it is a long process as this has to
be done for every file:
```
mkdir input
@ -536,12 +552,10 @@ If you need to stop and re-start the fuzzing, use the same command line options
mutation mode!) and switch the input directory with a dash (`-`):
`afl-fuzz -i - -o output -- bin/target -d @@`
Note that afl-fuzz enforces memory limits to prevent the system to run out
of memory. By default this is 50MB for a process. If this is too little for
the target (which you can usually see by afl-fuzz bailing with the message
that it could not connect to the forkserver), then you can increase this
with the `-m` option, the value is in MB. To disable any memory limits
(beware!) set `-m none` - which is usually required for ASAN compiled targets.
Memory limits are not enforced by afl-fuzz by default and the system may run
out of memory. You can decrease the memory with the `-m` option, the value is
in MB. If this is too small for the target, you can usually see this by
afl-fuzz bailing with the message that it could not connect to the forkserver.
Adding a dictionary is helpful. See the directory [dictionaries/](dictionaries/) if
something is already included for your data format, and tell afl-fuzz to load
@ -554,7 +568,9 @@ afl-fuzz has a variety of options that help to workaround target quirks like
specific locations for the input file (`-f`), not performing deterministic
fuzzing (`-d`) and many more. Check out `afl-fuzz -h`.
afl-fuzz never stops fuzzing. To terminate afl++ simply press Control-C.
By default afl-fuzz never stops fuzzing. To terminate afl++ simply press Control-C
or send a signal SIGINT. You can limit the number of executions or approximate runtime
in seconds with options also.
When you start afl-fuzz you will see a user interface that shows what the status
is:
@ -1168,6 +1184,7 @@ without feedback, bug reports, or patches from:
Josephine Calliotte Konrad Welc
Thomas Rooijakkers David Carlier
Ruben ten Hove Joey Jiao
fuzzah
```
Thank you!

View File

@ -2,12 +2,16 @@
## Roadmap 3.00+
- AFL_MAP_SIZE for qemu_mode and unicorn_mode
- Update afl->pending_not_fuzzed for MOpt
- CPU affinity for many cores? There seems to be an issue > 96 cores
- afl-plot to support multiple plot_data
- afl_custom_fuzz_splice_optin()
- afl_custom_splice()
- intel-pt tracer
- better autodetection of shifting runtime timeout values
- cmplog: use colorization input for havoc?
- cmplog: too much tainted bytes, directly add to dict and skip?
## Further down the road
@ -23,9 +27,12 @@ qemu_mode:
- add/implement AFL_QEMU_INST_LIBLIST and AFL_QEMU_NOINST_PROGRAM
- add/implement AFL_QEMU_INST_REGIONS as a list of _START/_END addresses
## Ideas
- LTO/sancov: write current edge to prev_loc and use that information when
using cmplog or __sanitizer_cov_trace_cmp*. maybe we can deduct by follow
up edge numbers that both following cmp paths have been found and then
disable working on this edge id -> cmplog_intelligence branch
- use cmplog colorization taint result for havoc locations?

View File

@ -287,6 +287,10 @@ BEGIN {
exit 1
}
if (0 == system( "test -d "in_dir"/default" )) {
in_dir = in_dir "/default"
}
if (0 == system( "test -d "in_dir"/queue" )) {
in_dir = in_dir "/queue"
}
@ -342,8 +346,10 @@ BEGIN {
} else {
stat_format = "-f '%z %N'" # *BSD, MacOS
}
cmdline = "cd "in_dir" && find . \\( ! -name . -a -type d -prune \\) -o -type f -exec stat "stat_format" \\{\\} \\; | sort -k1n -k2r"
cmdline = "ls "in_dir" | (cd "in_dir" && xargs stat "stat_format" 2>/dev/null) | sort -k1n -k2r"
cmdline = "(cd "in_dir" && find . \\( ! -name . -a -type d -prune \\) -o -type f -exec stat "stat_format" \\{\\} + | sort -k1n -k2r)"
#cmdline = "ls "in_dir" | (cd "in_dir" && xargs stat "stat_format" 2>/dev/null) | sort -k1n -k2r"
#cmdline = "(cd "in_dir" && stat "stat_format" *) | sort -k1n -k2r"
#cmdline = "(cd "in_dir" && ls | xargs stat "stat_format" ) | sort -k1n -k2r"
while (cmdline | getline) {
sub(/^[0-9]+ (\.\/)?/,"",$0)
infilesSmallToBig[i++] = $0
@ -354,12 +360,12 @@ BEGIN {
# Make sure that we're not dealing with a directory.
if (0 == system("test -d "in_dir"/"first_file)) {
if (0 == system("test -d ""\""in_dir"/"first_file"\"")) {
print "[-] Error: The input directory is empty or contains subdirectories - please fix." > "/dev/stderr"
exit 1
}
if (0 == system("ln "in_dir"/"first_file" "trace_dir"/.link_test")) {
if (0 == system("ln \""in_dir"/"first_file"\" "trace_dir"/.link_test")) {
cp_tool = "ln"
} else {
cp_tool = "cp"
@ -374,7 +380,7 @@ BEGIN {
if (!stdin_file) {
system( "AFL_CMIN_ALLOW_ANY=1 "AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/.run_test\" -Z "extra_par" -- \""target_bin"\" "prog_args_string" <\""in_dir"/"first_file"\"")
} else {
system("cp "in_dir"/"first_file" "stdin_file)
system("cp \""in_dir"/"first_file"\" "stdin_file)
system( "AFL_CMIN_ALLOW_ANY=1 "AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/.run_test\" -Z "extra_par" -A \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null")
}
@ -496,7 +502,7 @@ BEGIN {
# copy file unless already done
if (! (fn in file_already_copied)) {
system(cp_tool" "in_dir"/"fn" "out_dir"/"fn)
system(cp_tool" \""in_dir"/"fn"\" \""out_dir"/"fn"\"")
file_already_copied[fn] = ""
++out_count
#printf "tuple nr %d (%d cnt=%d) -> %s\n",tcnt,key,key_count[key],fn > trace_dir"/.log"

View File

@ -223,6 +223,7 @@ if [ ! -d "$IN_DIR" ]; then
exit 1
fi
test -d "$IN_DIR/default" && IN_DIR="$IN_DIR/default"
test -d "$IN_DIR/queue" && IN_DIR="$IN_DIR/queue"
find "$OUT_DIR" -name 'id[:_]*' -maxdepth 1 -exec rm -- {} \; 2>/dev/null

View File

@ -39,7 +39,7 @@ if [ "$PLATFORM" = "Linux" ] ; then
echo Settings applied.
dmesg | egrep -q 'nospectre_v2|spectre_v2=off' || {
echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this:
echo ' /etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off"'
echo ' /etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=0 l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx_async_abort=off arm64.nopauth audit=0 hardened_usercopy=off ssbd=force-off"'
}
DONE=1
fi

View File

@ -1,3 +1,4 @@
#![cfg(unix)]
//! Somewhat safe and somewhat ergonomic bindings for creating [AFL++](https://github.com/AFLplusplus/AFLplusplus) [custom mutators](https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/custom_mutators.md) in Rust.
//!
//! # Usage
@ -23,7 +24,7 @@
//! The state is passed to [`CustomMutator::init`], when the feature is activated.
//!
//! _This is completely unsafe and uses automatically generated types extracted from the AFL++ source._
use std::{ffi::CStr, fmt::Debug};
use std::{fmt::Debug, path::Path};
#[cfg(feature = "afl_internals")]
#[doc(hidden)]
@ -33,7 +34,7 @@ pub use custom_mutator_sys::afl_state;
#[doc(hidden)]
pub trait RawCustomMutator {
#[cfg(feature = "afl_internals")]
fn init(afl: &'static afl_state, seed: c_uint) -> Self
fn init(afl: &'static afl_state, seed: u32) -> Self
where
Self: Sized;
#[cfg(not(feature = "afl_internals"))]
@ -52,17 +53,17 @@ pub trait RawCustomMutator {
1
}
fn queue_new_entry(&mut self, filename_new_queue: &CStr, _filename_orig_queue: Option<&CStr>) {}
fn queue_new_entry(&mut self, filename_new_queue: &Path, _filename_orig_queue: Option<&Path>) {}
fn queue_get(&mut self, filename: &CStr) -> bool {
fn queue_get(&mut self, filename: &Path) -> bool {
true
}
fn describe(&mut self, max_description: usize) -> Option<&CStr> {
None
fn describe(&mut self, max_description: usize) -> Option<&str> {
Some(default_mutator_describe::<Self>(max_description))
}
fn introspection(&mut self) -> Option<&CStr> {
fn introspection(&mut self) -> Option<&str> {
None
}
@ -81,16 +82,17 @@ pub mod wrappers {
#[cfg(feature = "afl_internals")]
use custom_mutator_sys::afl_state;
use core::slice;
use std::{
any::Any,
convert::TryInto,
ffi::{c_void, CStr},
ffi::{c_void, CStr, OsStr},
mem::ManuallyDrop,
os::raw::c_char,
os::{raw::c_char, unix::ffi::OsStrExt},
panic::catch_unwind,
path::Path,
process::abort,
ptr::null,
slice,
};
use crate::RawCustomMutator;
@ -99,6 +101,10 @@ pub mod wrappers {
/// Also has some convenience functions for FFI conversions (from and to ptr) and tries to make misuse hard (see [`FFIContext::from`]).
struct FFIContext<M: RawCustomMutator> {
mutator: M,
/// buffer for storing the description returned by [`RawCustomMutator::describe`] as a CString
description_buffer: Vec<u8>,
/// buffer for storing the introspection returned by [`RawCustomMutator::introspect`] as a CString
introspection_buffer: Vec<u8>,
}
impl<M: RawCustomMutator> FFIContext<M> {
@ -115,12 +121,16 @@ pub mod wrappers {
fn new(afl: &'static afl_state, seed: u32) -> Box<Self> {
Box::new(Self {
mutator: M::init(afl, seed),
description_buffer: Vec::new(),
introspection_buffer: Vec::new(),
})
}
#[cfg(not(feature = "afl_internals"))]
fn new(seed: u32) -> Box<Self> {
Box::new(Self {
mutator: M::init(seed),
description_buffer: Vec::new(),
introspection_buffer: Vec::new(),
})
}
}
@ -242,9 +252,13 @@ pub mod wrappers {
if filename_new_queue.is_null() {
panic!("received null filename_new_queue in afl_custom_queue_new_entry");
}
let filename_new_queue = unsafe { CStr::from_ptr(filename_new_queue) };
let filename_new_queue = Path::new(OsStr::from_bytes(
unsafe { CStr::from_ptr(filename_new_queue) }.to_bytes(),
));
let filename_orig_queue = if !filename_orig_queue.is_null() {
Some(unsafe { CStr::from_ptr(filename_orig_queue) })
Some(Path::new(OsStr::from_bytes(
unsafe { CStr::from_ptr(filename_orig_queue) }.to_bytes(),
)))
} else {
None
};
@ -271,9 +285,14 @@ pub mod wrappers {
/// Internal function used in the macro
pub fn afl_custom_introspection_<M: RawCustomMutator>(data: *mut c_void) -> *const c_char {
match catch_unwind(|| {
let mut context = FFIContext::<M>::from(data);
let context = &mut *FFIContext::<M>::from(data);
if let Some(res) = context.mutator.introspection() {
res.as_ptr()
let buf = &mut context.introspection_buffer;
buf.clear();
buf.extend_from_slice(res.as_bytes());
buf.push(0);
// unwrapping here, as the error case should be extremely rare
CStr::from_bytes_with_nul(&buf).unwrap().as_ptr()
} else {
null()
}
@ -289,9 +308,14 @@ pub mod wrappers {
max_description_len: usize,
) -> *const c_char {
match catch_unwind(|| {
let mut context = FFIContext::<M>::from(data);
let context = &mut *FFIContext::<M>::from(data);
if let Some(res) = context.mutator.describe(max_description_len) {
res.as_ptr()
let buf = &mut context.description_buffer;
buf.clear();
buf.extend_from_slice(res.as_bytes());
buf.push(0);
// unwrapping here, as the error case should be extremely rare
CStr::from_bytes_with_nul(&buf).unwrap().as_ptr()
} else {
null()
}
@ -310,9 +334,9 @@ pub mod wrappers {
let mut context = FFIContext::<M>::from(data);
assert!(!filename.is_null());
context
.mutator
.queue_get(unsafe { CStr::from_ptr(filename) }) as u8
context.mutator.queue_get(Path::new(OsStr::from_bytes(
unsafe { CStr::from_ptr(filename) }.to_bytes(),
))) as u8
}) {
Ok(ret) => ret,
Err(err) => panic_handler("afl_custom_queue_get", err),
@ -516,21 +540,21 @@ pub trait CustomMutator {
fn queue_new_entry(
&mut self,
filename_new_queue: &CStr,
filename_orig_queue: Option<&CStr>,
filename_new_queue: &Path,
filename_orig_queue: Option<&Path>,
) -> Result<(), Self::Error> {
Ok(())
}
fn queue_get(&mut self, filename: &CStr) -> Result<bool, Self::Error> {
fn queue_get(&mut self, filename: &Path) -> Result<bool, Self::Error> {
Ok(true)
}
fn describe(&mut self, max_description: usize) -> Result<Option<&CStr>, Self::Error> {
Ok(None)
fn describe(&mut self, max_description: usize) -> Result<Option<&str>, Self::Error> {
Ok(Some(default_mutator_describe::<Self>(max_description)))
}
fn introspection(&mut self) -> Result<Option<&CStr>, Self::Error> {
fn introspection(&mut self) -> Result<Option<&str>, Self::Error> {
Ok(None)
}
}
@ -593,7 +617,7 @@ where
}
}
fn queue_new_entry(&mut self, filename_new_queue: &CStr, filename_orig_queue: Option<&CStr>) {
fn queue_new_entry(&mut self, filename_new_queue: &Path, filename_orig_queue: Option<&Path>) {
match self.queue_new_entry(filename_new_queue, filename_orig_queue) {
Ok(r) => r,
Err(e) => {
@ -602,7 +626,7 @@ where
}
}
fn queue_get(&mut self, filename: &CStr) -> bool {
fn queue_get(&mut self, filename: &Path) -> bool {
match self.queue_get(filename) {
Ok(r) => r,
Err(e) => {
@ -612,7 +636,7 @@ where
}
}
fn describe(&mut self, max_description: usize) -> Option<&CStr> {
fn describe(&mut self, max_description: usize) -> Option<&str> {
match self.describe(max_description) {
Ok(r) => r,
Err(e) => {
@ -622,7 +646,7 @@ where
}
}
fn introspection(&mut self) -> Option<&CStr> {
fn introspection(&mut self) -> Option<&str> {
match self.introspection() {
Ok(r) => r,
Err(e) => {
@ -632,3 +656,85 @@ where
}
}
}
/// the default value to return from [`CustomMutator::describe`].
fn default_mutator_describe<T: ?Sized>(max_len: usize) -> &'static str {
truncate_str_unicode_safe(std::any::type_name::<T>(), max_len)
}
#[cfg(all(test, not(feature = "afl_internals")))]
mod default_mutator_describe {
struct MyMutator;
use super::CustomMutator;
impl CustomMutator for MyMutator {
type Error = ();
fn init(_: u32) -> Result<Self, Self::Error> {
Ok(Self)
}
fn fuzz<'b, 's: 'b>(
&'s mut self,
_: &'b mut [u8],
_: Option<&[u8]>,
_: usize,
) -> Result<Option<&'b [u8]>, Self::Error> {
unimplemented!()
}
}
#[test]
fn test_default_describe() {
assert_eq!(
MyMutator::init(0).unwrap().describe(64).unwrap().unwrap(),
"custom_mutator::default_mutator_describe::MyMutator"
);
}
}
/// little helper function to truncate a `str` to a maximum of bytes while retaining unicode safety
fn truncate_str_unicode_safe(s: &str, max_len: usize) -> &str {
if s.len() <= max_len {
s
} else {
if let Some((last_index, _)) = s
.char_indices()
.take_while(|(index, _)| *index <= max_len)
.last()
{
&s[..last_index]
} else {
""
}
}
}
#[cfg(test)]
mod truncate_test {
use super::truncate_str_unicode_safe;
#[test]
fn test_truncate() {
for (max_len, input, expected_output) in &[
(0usize, "a", ""),
(1, "a", "a"),
(1, "ä", ""),
(2, "ä", "ä"),
(3, "äa", "äa"),
(4, "äa", "äa"),
(1, "👎", ""),
(2, "👎", ""),
(3, "👎", ""),
(4, "👎", "👎"),
(1, "abc", "a"),
(2, "abc", "ab"),
] {
let actual_output = truncate_str_unicode_safe(input, *max_len);
assert_eq!(
&actual_output, expected_output,
"{:#?} truncated to {} bytes should be {:#?}, but is {:#?}",
input, max_len, expected_output, actual_output
);
}
}
}

View File

@ -1,3 +1,4 @@
#![cfg(unix)]
#![allow(unused_variables)]
use custom_mutator::{export_mutator, CustomMutator};

View File

@ -1,3 +1,5 @@
#![cfg(unix)]
use custom_mutator::{export_mutator, CustomMutator};
use lain::{
mutator::Mutator,

View File

@ -8,6 +8,58 @@
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 ++3.12c (release)
- afl-fuzz:
- added AFL_TARGET_ENV variable to pass extra env vars to the target
(for things like LD_LIBRARY_PATH)
- fix map detection, AFL_MAP_SIZE not needed anymore for most cases
- fix counting favorites (just a display thing)
- afl-cc:
- fix cmplog rtn (rare crash and not being able to gather ptr data)
- fix our own PCGUARD implementation to compile with llvm 10.0.1
- link runtime not to shared libs
- ensure shared libraries are properly built and instrumented
- AFL_LLVM_INSTRUMENT_ALLOW/DENY were not implemented for LTO, added
- show correct LLVM PCGUARD NATIVE mode when auto switching to it
and keep fsanitize-coverage-*list=...
Short mnemnonic NATIVE is now also accepted.
- qemu_mode (thanks @realmadsci):
- move AFL_PRELOAD and AFL_USE_QASAN logic inside afl-qemu-trace
- add AFL_QEMU_CUSTOM_BIN
- unicorn_mode
- accidently removed the subfolder from github, re-added
- added DEFAULT_PERMISSION to config.h for all files created, default
to 0600
### Version ++3.11c (release)
- afl-fuzz:
- better auto detection of map size
- fix sanitizer settings (bug since 3.10c)
- fix an off-by-one overwrite in cmplog
- add non-unicode variants from unicode-looking dictionary entries
- Rust custom mutator API improvements
- Imported crash stats painted yellow on resume (only new ones are red)
- afl-cc:
- added AFL_NOOPT that will just pass everything to the normal
gcc/clang compiler without any changes - to pass weird configure
scripts
- fixed a crash that can occur with ASAN + CMPLOG together plus
better support for unicode (thanks to @stbergmann for reporting!)
- fixed a crash in LAF transform for empty strings
- handle erroneous setups in which multiple afl-compiler-rt are
compiled into the target. This now also supports dlopen()
instrumented libs loaded before the forkserver and even after the
forkserver is started (then with collisions though)
- the compiler rt was added also in object building (-c) which
should have been fixed years ago but somewhere got lost :(
- Renamed CTX to CALLER, added correct/real CTX implementation to
CLASSIC
- qemu_mode:
- added AFL_QEMU_EXCLUDE_RANGES env by @realmadsci, thanks!
- if no new/updated checkout is wanted, build with:
NO_CHECKOUT=1 ./build_qemu_support.sh
- we no longer perform a "git drop"
- afl-cmin: support filenames with spaces
### Version ++3.10c (release)
- Mac OS ARM64 support

View File

@ -26,6 +26,17 @@ Because (with the exception of the --afl-MODE command line option) the
compile-time tools do not accept afl specific command-line options, they
make fairly broad use of environmental variables instead:
- Some build/configure scripts break with afl++ compilers. To be able to
pass them, do:
```
export CC=afl-cc
export CXX=afl-c++
export AFL_NOOPT=1
./configure --disable-shared --disabler-werror
unset AFL_NOOPT
make
```
- Most afl tools do not print any output if stdout/stderr are redirected.
If you want to get the output into a file then set the `AFL_DEBUG`
environment variable.
@ -382,6 +393,10 @@ checks or alter some of the more exotic semantics of the tool:
- In QEMU mode (-Q), `AFL_PATH` will be searched for afl-qemu-trace.
- In QEMU mode (-Q), setting `AFL_QEMU_CUSTOM_BIN` cause afl-fuzz to skip
prepending `afl-qemu-trace` to your command line. Use this if you wish to use a
custom afl-qemu-trace or if you need to modify the afl-qemu-trace arguments.
- Setting `AFL_CYCLE_SCHEDULES` will switch to a different schedule everytime
a cycle is finished.
@ -393,6 +408,12 @@ checks or alter some of the more exotic semantics of the tool:
without disrupting the afl-fuzz process itself. This is useful, among other
things, for bootstrapping libdislocator.so.
- Setting `AFL_TARGET_ENV` causes AFL++ to set extra environment variables
for the target binary. Example: `AFL_TARGET_ENV="VAR1=1 VAR2='a b c'" afl-fuzz ... `
This exists mostly for things like `LD_LIBRARY_PATH` but it would theoretically
allow fuzzing of AFL++ itself (with 'target' AFL++ using some AFL_ vars that
would disrupt work of 'fuzzer' AFL++).
- Setting `AFL_NO_UI` inhibits the UI altogether, and just periodically prints
some basic stats. This behavior is also automatically triggered when the
output from afl-fuzz is redirected to a file or to a pipe.
@ -404,7 +425,8 @@ checks or alter some of the more exotic semantics of the tool:
no valid terminal was detected (for virtual consoles)
- If you are Jakub, you may need `AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES`.
Others need not apply.
Others need not apply, unless they also want to disable the
`/proc/sys/kernel/core_pattern` check.
- Benchmarking only: `AFL_BENCH_JUST_ONE` causes the fuzzer to exit after
processing the first queue entry; and `AFL_BENCH_UNTIL_CRASH` causes it to

View File

@ -35,7 +35,9 @@ and documents something about it. In traditional fuzzing this is the coverage
in the target, however we want to add various more observers, e.g. stack depth,
heap usage, etc. - this is a topic for an experienced Rust developer.
# Generic ideas and wishlist
# Generic ideas and wishlist - NOT PART OF GSoC 2021 !
The below list is not part of GSoC 2021.
## Analysis software

View File

@ -5,6 +5,43 @@
"__afl_auto_init";
"__afl_area_initial";
"__afl_prev_loc";
"__afl_prev_caller";
"__afl_prev_ctx";
"__afl_final_loc";
"__afl_map_addr";
"__afl_dictionary";
"__afl_dictionary_len";
"__afl_selective_coverage";
"__afl_selective_coverage_start_off";
"__afl_selective_coverage_temp";
"__afl_coverage_discard";
"__afl_coverage_skip";
"__afl_coverage_on";
"__afl_coverage_off";
"__afl_coverage_interesting";
"__afl_fuzz_len";
"__afl_fuzz_ptr";
"__sanitizer_cov_trace_pc_guard";
"__sanitizer_cov_trace_pc_guard_init";
"__cmplog_ins_hook1";
"__cmplog_ins_hook2";
"__cmplog_ins_hook4";
"__cmplog_ins_hookN";
"__cmplog_ins_hook16";
"__sanitizer_cov_trace_cmp1";
"__sanitizer_cov_trace_const_cmp1";
"__sanitizer_cov_trace_cmp2";
"__sanitizer_cov_trace_const_cmp2";
"__sanitizer_cov_trace_cmp4";
"__sanitizer_cov_trace_const_cmp4";
"__sanitizer_cov_trace_cmp8";
"__sanitizer_cov_trace_const_cmp8";
"__sanitizer_cov_trace_cmp16";
"__sanitizer_cov_trace_const_cmp16";
"__sanitizer_cov_trace_switch";
"__cmplog_rtn_hook";
"__cmplog_rtn_gcc_stdstring_cstring";
"__cmplog_rtn_gcc_stdstring_stdstring";
"__cmplog_rtn_llvm_stdstring_cstring";
"__cmplog_rtn_llvm_stdstring_stdstring";
};

View File

@ -390,7 +390,7 @@ typedef struct afl_env_vars {
*afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload,
*afl_max_det_extras, *afl_statsd_host, *afl_statsd_port,
*afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size,
*afl_testcache_entries, *afl_kill_signal;
*afl_testcache_entries, *afl_kill_signal, *afl_target_env;
} afl_env_vars_t;
@ -1062,6 +1062,7 @@ u8 has_new_bits_unclassified(afl_state_t *, u8 *);
void load_extras_file(afl_state_t *, u8 *, u32 *, u32 *, u32);
void load_extras(afl_state_t *, u8 *);
void dedup_extras(afl_state_t *);
void deunicode_extras(afl_state_t *);
void add_extra(afl_state_t *afl, u8 *mem, u32 len);
void maybe_add_auto(afl_state_t *, u8 *, u32);
void save_auto(afl_state_t *);

View File

@ -48,7 +48,10 @@ void argv_cpy_free(char **argv);
char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv);
char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv);
char * get_afl_env(char *env);
u8 * get_libqasan_path(u8 *own_loc);
/* Extract env vars from input string and set them using setenv()
For use with AFL_TARGET_ENV, ... */
bool extract_and_set_env(u8 *env_str);
extern u8 be_quiet;
extern u8 *doc_path; /* path to documentation dir */
@ -58,6 +61,10 @@ extern u8 *doc_path; /* path to documentation dir */
u8 *find_binary(u8 *fname);
/* find an afl binary */
u8 *find_afl_binary(u8 *own_loc, u8 *fname);
/* Parses the kill signal environment variable, FATALs on error.
If the env is not set, sets the env to default_signal for the signal handlers
and returns the default_signal. */

View File

@ -26,7 +26,7 @@
/* Version string: */
// c = release, a = volatile github dev, e = experimental branch
#define VERSION "++3.10c"
#define VERSION "++3.12c"
/******************************************************
* *
@ -34,6 +34,18 @@
* *
******************************************************/
/* Default shared memory map size. Most targets just need a coverage map
between 20-250kb. Plus there is an auto-detection feature in afl-fuzz.
However if a target has problematic constructors and init arrays then
this can fail. Hence afl-fuzz deploys a larger default map. The largest
map seen so far is the xlsx fuzzer for libreoffice which is 5MB.
At runtime this value can be overriden via AFL_MAP_SIZE.
Default: 8MB (defined in bytes) */
#define DEFAULT_SHMEM_SIZE (8 * 1024 * 1024)
/* Default file permission umode when creating files (default: 0600) */
#define DEFAULT_PERMISSION 0600
/* CMPLOG/REDQUEEN TUNING
*
* Here you can modify tuning and solving options for CMPLOG.
@ -54,10 +66,10 @@
/* Number of potential positions from which we decide if cmplog becomes
useless, default 8096 */
#define CMPLOG_POSITIONS_MAX 8096U
#define CMPLOG_POSITIONS_MAX (12 * 1024)
/* Maximum allowed fails per CMP value. Default: 128 */
#define CMPLOG_FAIL_MAX 128
#define CMPLOG_FAIL_MAX 96
/* Now non-cmplog configuration options */

View File

@ -42,6 +42,7 @@ static char *afl_environment_variables[] = {
"AFL_DEBUG_CHILD",
"AFL_DEBUG_GDB",
"AFL_DISABLE_TRIM",
"AFL_DISABLE_LLVM_INSTRUMENTATION",
"AFL_DONT_OPTIMIZE",
"AFL_DRIVER_STDERR_DUPLICATE_FILENAME",
"AFL_DUMB_FORKSRV",
@ -50,6 +51,7 @@ static char *afl_environment_variables[] = {
"AFL_FAST_CAL",
"AFL_FORCE_UI",
"AFL_FUZZER_ARGS", // oss-fuzz
"AFL_GDB",
"AFL_GCC_ALLOWLIST",
"AFL_GCC_DENYLIST",
"AFL_GCC_BLOCKLIST",
@ -80,7 +82,9 @@ static char *afl_environment_variables[] = {
"AFL_LLVM_BLOCKLIST",
"AFL_LLVM_CMPLOG",
"AFL_LLVM_INSTRIM",
"AFL_LLVM_CALLER",
"AFL_LLVM_CTX",
"AFL_LLVM_CTX_K",
"AFL_LLVM_DICT2FILE",
"AFL_LLVM_DOCUMENT_IDS",
"AFL_LLVM_INSTRIM_LOOPHEAD",
@ -118,14 +122,18 @@ static char *afl_environment_variables[] = {
"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_MAX_DET_EXTRAS",
"AFL_NO_X86", // not really an env but we dont want to warn on it
"AFL_NOOPT",
"AFL_PASSTHROUGH",
"AFL_PATH",
"AFL_PERFORMANCE_FILE",
"AFL_PRELOAD",
"AFL_TARGET_ENV",
"AFL_PYTHON_MODULE",
"AFL_QEMU_CUSTOM_BIN",
"AFL_QEMU_COMPCOV",
"AFL_QEMU_COMPCOV_DEBUG",
"AFL_QEMU_DEBUG_MAPS",
@ -141,6 +149,7 @@ static char *afl_environment_variables[] = {
"AFL_QEMU_PERSISTENT_RETADDR_OFFSET",
"AFL_QEMU_PERSISTENT_EXITS",
"AFL_QEMU_INST_RANGES",
"AFL_QEMU_EXCLUDE_RANGES",
"AFL_QEMU_SNAPSHOT",
"AFL_QUIET",
"AFL_RANDOM_ALLOC_CANARY",

View File

@ -38,7 +38,7 @@ typedef long double max_align_t;
#include "MarkNodes.h"
#include "afl-llvm-common.h"
#include "llvm-ngram-coverage.h"
#include "llvm-alternative-coverage.h"
#include "config.h"
#include "debug.h"
@ -135,7 +135,7 @@ struct InsTrim : public ModulePass {
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");
char *caller_str = getenv("AFL_LLVM_CALLER");
#ifdef AFL_HAVE_VECTOR_INTRINSICS
unsigned int ngram_size = 0;
@ -197,9 +197,9 @@ struct InsTrim : public ModulePass {
GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
GlobalVariable *AFLPrevLoc;
GlobalVariable *AFLContext = NULL;
LoadInst * PrevCtx = NULL; // for CTX sensitive coverage
LoadInst * PrevCaller = NULL; // for CALLER sensitive coverage
if (ctx_str)
if (caller_str)
#if defined(__ANDROID__) || defined(__HAIKU__)
AFLContext = new GlobalVariable(
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx");
@ -398,11 +398,11 @@ struct InsTrim : public ModulePass {
unsigned int cur_loc;
// Context sensitive coverage
if (ctx_str && &BB == &F.getEntryBlock()) {
if (caller_str && &BB == &F.getEntryBlock()) {
PrevCtx = IRB.CreateLoad(AFLContext);
PrevCtx->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
PrevCaller = IRB.CreateLoad(AFLContext);
PrevCaller->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
// does the function have calls? and is any of the calls larger than
// one basic block?
@ -441,7 +441,7 @@ struct InsTrim : public ModulePass {
}
} // END of ctx_str
} // END of caller_str
if (MarkSetOpt && MS.find(&BB) == MS.end()) { continue; }
@ -485,9 +485,9 @@ struct InsTrim : public ModulePass {
#endif
PrevLocTrans = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty());
if (ctx_str)
if (caller_str)
PrevLocTrans =
IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, PrevCtx), Int32Ty);
IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, PrevCaller), Int32Ty);
/* Load SHM pointer */
LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr);
@ -535,16 +535,17 @@ struct InsTrim : public ModulePass {
IRB.CreateStore(Incr, MapPtrIdx)
->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
if (ctx_str && has_calls) {
if (caller_str && has_calls) {
// in CTX mode we have to restore the original context for the
// in CALLER mode we have to restore the original context for the
// caller - she might be calling other functions which need the
// correct CTX
// correct CALLER
Instruction *Inst = BB.getTerminator();
if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst)) {
IRBuilder<> Post_IRB(Inst);
StoreInst * RestoreCtx = Post_IRB.CreateStore(PrevCtx, AFLContext);
StoreInst * RestoreCtx =
Post_IRB.CreateStore(PrevCaller, AFLContext);
RestoreCtx->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));

View File

@ -1,10 +1,11 @@
# CmpLog instrumentation
The CmpLog instrumentation enables the logging of the comparisons operands in a
The CmpLog instrumentation enables logging of comparison operands in a
shared memory.
These values can be used by various mutators built on top of it.
At the moment we support the RedQueen mutator (input-2-state instructions only).
At the moment we support the RedQueen mutator (input-2-state instructions only),
for details see [the RedQueen paper](https://www.syssec.ruhr-uni-bochum.de/media/emma/veroeffentlichungen/2018/12/17/NDSS19-Redqueen.pdf).
## Build
@ -13,7 +14,7 @@ program.
The first version is built using the regular AFL++ instrumentation.
The second one, the CmpLog binary, with setting AFL_LLVM_CMPLOG during the compilation.
The second one, the CmpLog binary, is built with setting AFL_LLVM_CMPLOG during the compilation.
For example:
@ -26,11 +27,12 @@ export AFL_LLVM_CMPLOG=1
./configure --cc=~/path/to/afl-clang-fast
make
cp ./program ./program.cmplog
unset AFL_LLVM_CMPLOG
```
## Use
AFL++ has the new -c option that needs to be used to specify the CmpLog binary (the second
AFL++ has the new `-c` option that needs to be used to specify the CmpLog binary (the second
build).
For example:

View File

@ -4,14 +4,19 @@
This is an LLVM-based implementation of the context sensitive branch coverage.
Basically every function gets its own ID and that ID is combined with the
edges of the called functions.
Basically every function gets its own ID and, every time when an edge is logged,
all the IDs in the callstack are hashed and combined with the edge transition
hash to augment the classic edge coverage with the information about the
calling context.
So if both function A and function B call a function C, the coverage
collected in C will be different.
In math the coverage is collected as follows:
`map[current_location_ID ^ previous_location_ID >> 1 ^ previous_callee_ID] += 1`
`map[current_location_ID ^ previous_location_ID >> 1 ^ hash_callstack_IDs] += 1`
The callstack hash is produced XOR-ing the function IDs to avoid explosion with
recursive functions.
## Usage
@ -20,3 +25,14 @@ Set the `AFL_LLVM_INSTRUMENT=CTX` or `AFL_LLVM_CTX=1` environment variable.
It is highly recommended to increase the MAP_SIZE_POW2 definition in
config.h to at least 18 and maybe up to 20 for this as otherwise too
many map collisions occur.
## Caller Branch Coverage
If the context sensitive coverage introduces too may collisions and becoming
detrimental, the user can choose to augment edge coverage with just the
called function ID, instead of the entire callstack hash.
In math the coverage is collected as follows:
`map[current_location_ID ^ previous_location_ID >> 1 ^ previous_callee_ID] += 1`
Set the `AFL_LLVM_INSTRUMENT=CALLER` or `AFL_LLVM_CALLER=1` environment variable.

View File

@ -3,16 +3,20 @@
See [../README.md](../README.md) for the general instruction manual.
See [README.llvm.md](README.llvm.md) for the LLVM-based instrumentation.
This document describes how to build and use `afl-gcc-fast` and `afl-g++-fast`,
which instrument the target with the help of gcc plugins.
TLDR:
* `apt-get install gcc-VERSION-plugin-dev`
* `make`
* gcc and g++ must point to the gcc-VERSION you you have to set AFL_CC/AFL_CXX
* check the version of your gcc compiler: `gcc --version`
* `apt-get install gcc-VERSION-plugin-dev` or similar to install headers for gcc plugins
* `gcc` and `g++` must match the gcc-VERSION you installed headers for. You can set `AFL_CC`/`AFL_CXX`
to point to these!
* just use afl-gcc-fast/afl-g++-fast normally like you would afl-clang-fast
* `make`
* just use `afl-gcc-fast`/`afl-g++-fast` normally like you would do with `afl-clang-fast`
## 1) Introduction
The code in this directory allows you to instrument programs for AFL using
The code in this directory allows to instrument programs for AFL using
true compiler-level instrumentation, instead of the more crude
assembly-level rewriting approach taken by afl-gcc and afl-clang. This has
several interesting properties:
@ -27,10 +31,10 @@ several interesting properties:
- The instrumentation is CPU-independent. At least in principle, you should
be able to rely on it to fuzz programs on non-x86 architectures (after
building afl-fuzz with AFL_NOX86=1).
building `afl-fuzz` with `AFL_NOX86=1`).
- Because the feature relies on the internals of GCC, it is gcc-specific
and will *not* work with LLVM (see ../llvm_mode for an alternative).
and will *not* work with LLVM (see [README.llvm.md](README.llvm.md) for an alternative).
Once this implementation is shown to be sufficiently robust and portable, it
will probably replace afl-gcc. For now, it can be built separately and
@ -41,29 +45,32 @@ The idea and much of the implementation comes from Laszlo Szekeres.
## 2) How to use
In order to leverage this mechanism, you need to have modern enough GCC
(>= version 4.5.0) and the plugin headers installed on your system. That
(>= version 4.5.0) and the plugin development headers installed on your system. That
should be all you need. On Debian machines, these headers can be acquired by
installing the `gcc-VERSION-plugin-dev` packages.
To build the instrumentation itself, type 'make'. This will generate binaries
called afl-gcc-fast and afl-g++-fast in the parent directory.
To build the instrumentation itself, type `make`. This will generate binaries
called `afl-gcc-fast` and `afl-g++-fast` in the parent directory.
The gcc and g++ compiler links have to point to gcc-VERSION - or set these
by pointing the environment variables AFL_CC/AFL_CXX to them.
If the CC/CXX have been overridden, those compilers will be used from
those wrappers without using AFL_CXX/AFL_CC settings.
by pointing the environment variables `AFL_CC`/`AFL_CXX` to them.
If the `CC`/`CXX` environment variables have been set, those compilers will be
preferred over those from the `AFL_CC`/`AFL_CXX` settings.
Once this is done, you can instrument third-party code in a way similar to the
standard operating mode of AFL, e.g.:
CC=/path/to/afl/afl-gcc-fast ./configure [...options...]
```
CC=/path/to/afl/afl-gcc-fast
CXX=/path/to/afl/afl-g++-fast
export CC CXX
./configure [...options...]
make
```
Note: We also used `CXX` to set the C++ compiler to `afl-g++-fast` for C++ code.
Be sure to also include CXX set to afl-g++-fast for C++ code.
The tool honors roughly the same environmental variables as afl-gcc (see
[env_variables.md](../docs/env_variables.md). This includes AFL_INST_RATIO,
AFL_USE_ASAN, AFL_HARDEN, and AFL_DONT_OPTIMIZE.
The tool honors roughly the same environmental variables as `afl-gcc` (see
[env_variables.md](../docs/env_variables.md). This includes `AFL_INST_RATIO`,
`AFL_USE_ASAN`, `AFL_HARDEN`, and `AFL_DONT_OPTIMIZE`.
Note: if you want the GCC plugin to be installed on your system for all
users, you need to build it before issuing 'make install' in the parent
@ -72,7 +79,7 @@ directory.
## 3) Gotchas, feedback, bugs
This is an early-stage mechanism, so field reports are welcome. You can send bug
reports to afl@aflplus.plus
reports to afl@aflplus.plus.
## 4) Bonus feature #1: deferred initialization
@ -88,7 +95,7 @@ file before getting to the fuzzed data.
In such cases, it's beneficial to initialize the forkserver a bit later, once
most of the initialization work is already done, but before the binary attempts
to read the fuzzed input and parse it; in some cases, this can offer a 10x+
performance gain. You can implement delayed initialization in LLVM mode in a
performance gain. You can implement delayed initialization in GCC mode in a
fairly simple way.
First, locate a suitable location in the code where the delayed cloning can
@ -117,7 +124,7 @@ With the location selected, add this code in the appropriate spot:
```
You don't need the #ifdef guards, but they will make the program still work as
usual when compiled with a tool other than afl-gcc-fast/afl-clang-fast.
usual when compiled with a compiler other than afl-gcc-fast/afl-clang-fast.
Finally, recompile the program with afl-gcc-fast (afl-gcc or afl-clang will
*not* generate a deferred-initialization binary) - and you should be all set!
@ -127,7 +134,7 @@ Finally, recompile the program with afl-gcc-fast (afl-gcc or afl-clang will
Some libraries provide APIs that are stateless, or whose state can be reset in
between processing different input files. When such a reset is performed, a
single long-lived process can be reused to try out multiple test cases,
eliminating the need for repeated fork() calls and the associated OS overhead.
eliminating the need for repeated `fork()` calls and the associated OS overhead.
The basic structure of the program that does this would be:
@ -160,5 +167,9 @@ wary of memory leaks and the state of file descriptors.
When running in this mode, the execution paths will inherently vary a bit
depending on whether the input loop is being entered for the first time or
executed again. To avoid spurious warnings, the feature implies
AFL_NO_VAR_CHECK and hides the "variable path" warnings in the UI.
`AFL_NO_VAR_CHECK` and hides the "variable path" warnings in the UI.
## 6) Bonus feature #3: selective instrumentation
It can be more effective to fuzzing to only instrument parts of the code.
For details see [README.instrument_list.md](README.instrument_list.md).

View File

@ -113,7 +113,7 @@ cmake \
-DLLVM_LINK_LLVM_DYLIB="ON" \
-DLLVM_TARGETS_TO_BUILD="host" \
../llvm/
cmake --build . --parallel
cmake --build . -j4
export PATH="$(pwd)/bin:$PATH"
export LLVM_CONFIG="$(pwd)/bin/llvm-config"
export LD_LIBRARY_PATH="$(llvm-config --libdir)${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"

View File

@ -16,7 +16,7 @@ at a very little cost (one instruction per edge).
(The alternative of saturated counters has been tested also and proved to be
inferior in terms of path discovery.)
This is implemented in afl-gcc, however for llvm_mode this is optional if
This is implemented in afl-gcc and afl-gcc-fast, 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.

View File

@ -10,8 +10,8 @@ by Jinghan Wang, et. al.
Note that the original implementation (available
[here](https://github.com/bitsecurerlab/afl-sensitive))
is built on top of AFL's QEMU mode.
This is essentially a port that uses LLVM vectorized instructions to achieve
the same results when compiling source code.
This is essentially a port that uses LLVM vectorized instructions (available from
llvm versions 4.0.1 and higher) to achieve the same results when compiling source code.
In math the branch coverage is performed as follows:
`map[current_location ^ prev_location[0] >> 1 ^ prev_location[1] >> 1 ^ ... up to n-1`] += 1`

View File

@ -1,18 +1,16 @@
===========================================
Using afl++ without inlined instrumentation
===========================================
## Using afl++ without inlined instrumentation
This file describes how you can disable inlining of instrumentation.
By default, the GCC plugin will duplicate the effects of calling
__afl_trace (see afl-gcc-rt.o.c) in instrumented code, instead of
`__afl_trace` (see `afl-gcc-rt.o.c`) in instrumented code, instead of
issuing function calls.
The calls are presumed to be slower, more so because the rt file
itself is not optimized by the compiler.
Setting AFL_GCC_OUT_OF_LINE=1 in the environment while compiling code
Setting `AFL_GCC_OUT_OF_LINE=1` in the environment while compiling code
with the plugin will disable this inlining, issuing calls to the
unoptimized runtime instead.

View File

@ -16,7 +16,7 @@ Examples can be found in [utils/persistent_mode](../utils/persistent_mode).
## 2) TLDR;
Example `fuzz_target.c`:
```
```c
#include "what_you_need_for_your_target.h"
__AFL_FUZZ_INIT();
@ -60,14 +60,14 @@ The speed increase is usually x10 to x20.
If you want to be able to compile the target without afl-clang-fast/lto then
add this just after the includes:
```
```c
#ifndef __AFL_FUZZ_TESTCASE_LEN
ssize_t fuzz_len;
#define __AFL_FUZZ_TESTCASE_LEN fuzz_len
unsigned char fuzz_buf[1024000];
#define __AFL_FUZZ_TESTCASE_BUF fuzz_buf
#define __AFL_FUZZ_INIT() void sync(void);
#define __AFL_LOOP(x) ((fuzz_len = read(0, fuzz_buf, sizeof(fuzz_buf))) > 0 ?
#define __AFL_LOOP(x) ((fuzz_len = read(0, fuzz_buf, sizeof(fuzz_buf))) > 0 ? 1 : 0)
#define __AFL_INIT() sync()
#endif
```
@ -75,7 +75,7 @@ add this just after the includes:
## 3) Deferred initialization
AFL tries to optimize performance by executing the targeted binary just once,
stopping it just before main(), and then cloning this "main" process to get
stopping it just before `main()`, and then cloning this "main" process to get
a steady supply of targets to fuzz.
Although this approach eliminates much of the OS-, linker- and libc-level
@ -97,7 +97,7 @@ a location after:
- The creation of any vital threads or child processes - since the forkserver
can't clone them easily.
- The initialization of timers via setitimer() or equivalent calls.
- The initialization of timers via `setitimer()` or equivalent calls.
- The creation of temporary files, network sockets, offset-sensitive file
descriptors, and similar shared-state resources - but only provided that
@ -150,9 +150,9 @@ the impact of memory leaks and similar glitches; 1000 is a good starting point,
and going much higher increases the likelihood of hiccups without giving you
any real performance benefits.
A more detailed template is shown in ../utils/persistent_mode/.
Similarly to the previous mode, the feature works only with afl-clang-fast; #ifdef
guards can be used to suppress it when using other compilers.
A more detailed template is shown in `../utils/persistent_mode/.`
Similarly to the previous mode, the feature works only with afl-clang-fast;
`#ifdef` guards can be used to suppress it when using other compilers.
Note that as with the previous mode, the feature is easy to misuse; if you
do not fully reset the critical state, you may end up with false positives or
@ -161,7 +161,7 @@ wary of memory leaks and of the state of file descriptors.
PS. Because there are task switches still involved, the mode isn't as fast as
"pure" in-process fuzzing offered, say, by LLVM's LibFuzzer; but it is a lot
faster than the normal fork() model, and compared to in-process fuzzing,
faster than the normal `fork()` model, and compared to in-process fuzzing,
should be a lot more robust.
## 5) Shared memory fuzzing
@ -174,17 +174,17 @@ Setting this up is very easy:
After the includes set the following macro:
```
```c
__AFL_FUZZ_INIT();
```
Directly at the start of main - or if you are using the deferred forkserver
with `__AFL_INIT()` then *after* `__AFL_INIT? :
```
with `__AFL_INIT()` then *after* `__AFL_INIT()` :
```c
unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF;
```
Then as first line after the `__AFL_LOOP` while loop:
```
```c
int len = __AFL_FUZZ_TESTCASE_LEN;
```
and that is all!

View File

@ -507,6 +507,7 @@ bool ModuleSanitizerCoverage::instrumentModule(
Zero = ConstantInt::get(Int8Tyi, 0);
One = ConstantInt::get(Int8Tyi, 1);
initInstrumentList();
scanForDangerousFunctions(&M);
Mo = &M;
@ -733,7 +734,7 @@ bool ModuleSanitizerCoverage::instrumentModule(
Var->getInitializer())) {
HasStr2 = true;
Str2 = Array->getAsString().str();
Str2 = Array->getRawDataValues().str();
}
@ -809,7 +810,7 @@ bool ModuleSanitizerCoverage::instrumentModule(
Var->getInitializer())) {
HasStr1 = true;
Str1 = Array->getAsString().str();
Str1 = Array->getRawDataValues().str();
}
@ -849,15 +850,18 @@ bool ModuleSanitizerCoverage::instrumentModule(
thestring = Str2;
optLen = thestring.length();
if (optLen < 2 || (optLen == 2 && !thestring[1])) { continue; }
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 (optLen < 2) { continue; }
if (literalLength + 1 == optLen) { // add null byte
thestring.append("\0", 1);
addedNull = true;
@ -872,17 +876,21 @@ bool ModuleSanitizerCoverage::instrumentModule(
// was not already added
if (!isMemcmp) {
if (addedNull == false) {
if (addedNull == false && thestring[optLen - 1] != '\0') {
thestring.append("\0", 1); // add null byte
optLen++;
}
// ensure we do not have garbage
size_t offset = thestring.find('\0', 0);
if (offset + 1 < optLen) optLen = offset + 1;
thestring = thestring.substr(0, optLen);
if (!isStdString) {
// ensure we do not have garbage
size_t offset = thestring.find('\0', 0);
if (offset + 1 < optLen) optLen = offset + 1;
thestring = thestring.substr(0, optLen);
}
}
@ -1222,7 +1230,7 @@ void ModuleSanitizerCoverage::instrumentFunction(
// afl++ START
if (!F.size()) return;
if (isIgnoreFunction(&F)) return;
if (!isInInstrumentList(&F)) return;
// afl++ END
if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge)
@ -1284,10 +1292,17 @@ GlobalVariable *ModuleSanitizerCoverage::CreateFunctionLocalArrayInSection(
*CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage,
Constant::getNullValue(ArrayTy), "__sancov_gen_");
#if LLVM_VERSION_MAJOR > 12
if (TargetTriple.supportsCOMDAT() &&
(TargetTriple.isOSBinFormatELF() || !F.isInterposable()))
if (auto Comdat = getOrCreateFunctionComdat(F, TargetTriple))
Array->setComdat(Comdat);
#else
if (TargetTriple.supportsCOMDAT() && !F.isInterposable())
if (auto Comdat =
GetOrCreateFunctionComdat(F, TargetTriple, CurModuleUniqueId))
Array->setComdat(Comdat);
#endif
Array->setSection(getSectionName(Section));
Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedSize()));
GlobalsToAppendToUsed.push_back(Array);

View File

@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/EHPersonalities.h"
@ -34,11 +35,11 @@
#include "llvm/InitializePasses.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/SpecialCaseList.h"
#if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0)
#include "llvm/Support/VirtualFileSystem.h"
#endif
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Instrumentation.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
@ -47,65 +48,6 @@
#include "debug.h"
#include "afl-llvm-common.h"
namespace llvm {
/// This is the ModuleSanitizerCoverage pass used in the new pass manager. The
/// pass instruments functions for coverage, adds initialization calls to the
/// module for trace PC guards and 8bit counters if they are requested, and
/// appends globals to llvm.compiler.used.
class ModuleSanitizerCoveragePass
: public PassInfoMixin<ModuleSanitizerCoveragePass> {
public:
explicit ModuleSanitizerCoveragePass(
SanitizerCoverageOptions Options = SanitizerCoverageOptions(),
const std::vector<std::string> &AllowlistFiles =
std::vector<std::string>(),
const std::vector<std::string> &BlocklistFiles =
std::vector<std::string>())
: Options(Options) {
if (AllowlistFiles.size() > 0)
Allowlist = SpecialCaseList::createOrDie(AllowlistFiles
#if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0)
,
*vfs::getRealFileSystem()
#endif
);
if (BlocklistFiles.size() > 0)
Blocklist = SpecialCaseList::createOrDie(BlocklistFiles
#if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0)
,
*vfs::getRealFileSystem()
#endif
);
}
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
static bool isRequired() {
return true;
}
private:
SanitizerCoverageOptions Options;
std::unique_ptr<SpecialCaseList> Allowlist;
std::unique_ptr<SpecialCaseList> Blocklist;
};
// Insert SanitizerCoverage instrumentation.
ModulePass *createModuleSanitizerCoverageLegacyPassPass(
const SanitizerCoverageOptions &Options = SanitizerCoverageOptions(),
const std::vector<std::string> &AllowlistFiles = std::vector<std::string>(),
const std::vector<std::string> &BlocklistFiles =
std::vector<std::string>());
} // namespace llvm
using namespace llvm;
#define DEBUG_TYPE "sancov"
@ -156,96 +98,8 @@ static const char *const SanCovLowestStackName = "__sancov_lowest_stack";
static char *skip_nozero;
/*
static cl::opt<int> ClCoverageLevel(
"sanitizer-coverage-level",
cl::desc("Sanitizer Coverage. 0: none, 1: entry block, 2: all blocks, "
"3: all blocks and critical edges"),
cl::Hidden, cl::init(3));
static cl::opt<bool> ClTracePC("sanitizer-coverage-trace-pc",
cl::desc("Experimental pc tracing"), cl::Hidden,
cl::init(false));
static cl::opt<bool> ClTracePCGuard("sanitizer-coverage-trace-pc-guard",
cl::desc("pc tracing with a guard"),
cl::Hidden, cl::init(true));
// If true, we create a global variable that contains PCs of all instrumented
// BBs, put this global into a named section, and pass this section's bounds
// to __sanitizer_cov_pcs_init.
// This way the coverage instrumentation does not need to acquire the PCs
// at run-time. Works with trace-pc-guard, inline-8bit-counters, and
// inline-bool-flag.
static cl::opt<bool> ClCreatePCTable("sanitizer-coverage-pc-table",
cl::desc("create a static PC table"),
cl::Hidden, cl::init(false));
static cl::opt<bool> ClInline8bitCounters(
"sanitizer-coverage-inline-8bit-counters",
cl::desc("increments 8-bit counter for every edge"), cl::Hidden,
cl::init(false));
static cl::opt<bool> ClInlineBoolFlag(
"sanitizer-coverage-inline-bool-flag",
cl::desc("sets a boolean flag for every edge"), cl::Hidden,
cl::init(false));
static cl::opt<bool> ClCMPTracing(
"sanitizer-coverage-trace-compares",
cl::desc("Tracing of CMP and similar instructions"), cl::Hidden,
cl::init(false));
static cl::opt<bool> ClDIVTracing("sanitizer-coverage-trace-divs",
cl::desc("Tracing of DIV instructions"),
cl::Hidden, cl::init(false));
static cl::opt<bool> ClGEPTracing("sanitizer-coverage-trace-geps",
cl::desc("Tracing of GEP instructions"),
cl::Hidden, cl::init(false));
static cl::opt<bool> ClPruneBlocks(
"sanitizer-coverage-prune-blocks",
cl::desc("Reduce the number of instrumented blocks"), cl::Hidden,
cl::init(true));
static cl::opt<bool> ClStackDepth("sanitizer-coverage-stack-depth",
cl::desc("max stack depth tracing"),
cl::Hidden, cl::init(false));
*/
namespace {
/*
SanitizerCoverageOptions getOptions(int LegacyCoverageLevel) {
SanitizerCoverageOptions Res;
switch (LegacyCoverageLevel) {
case 0:
Res.CoverageType = SanitizerCoverageOptions::SCK_None;
break;
case 1:
Res.CoverageType = SanitizerCoverageOptions::SCK_Function;
break;
case 2:
Res.CoverageType = SanitizerCoverageOptions::SCK_BB;
break;
case 3:
Res.CoverageType = SanitizerCoverageOptions::SCK_Edge;
break;
case 4:
Res.CoverageType = SanitizerCoverageOptions::SCK_Edge;
Res.IndirectCalls = true;
break;
}
return Res;
}
*/
SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) {
// Sets CoverageType and IndirectCalls.
@ -281,12 +135,14 @@ class ModuleSanitizerCoverage {
public:
ModuleSanitizerCoverage(
const SanitizerCoverageOptions &Options = SanitizerCoverageOptions(),
const SpecialCaseList * Allowlist = nullptr,
const SpecialCaseList * Blocklist = nullptr)
: Options(OverrideFromCL(Options)),
Allowlist(Allowlist),
Blocklist(Blocklist) {
const SanitizerCoverageOptions &Options = SanitizerCoverageOptions()
#if LLVM_MAJOR > 10
,
const SpecialCaseList *Allowlist = nullptr,
const SpecialCaseList *Blocklist = nullptr
#endif
)
: Options(OverrideFromCL(Options)) {
}
@ -356,9 +212,6 @@ class ModuleSanitizerCoverage {
SanitizerCoverageOptions Options;
const SpecialCaseList *Allowlist;
const SpecialCaseList *Blocklist;
uint32_t instr = 0;
GlobalVariable *AFLMapPtr = NULL;
ConstantInt * One = NULL;
@ -370,27 +223,17 @@ class ModuleSanitizerCoverageLegacyPass : public ModulePass {
public:
ModuleSanitizerCoverageLegacyPass(
const SanitizerCoverageOptions &Options = SanitizerCoverageOptions(),
const SanitizerCoverageOptions &Options = SanitizerCoverageOptions()
#if LLVM_VERSION_MAJOR > 10
,
const std::vector<std::string> &AllowlistFiles =
std::vector<std::string>(),
const std::vector<std::string> &BlocklistFiles =
std::vector<std::string>())
std::vector<std::string>()
#endif
)
: ModulePass(ID), Options(Options) {
if (AllowlistFiles.size() > 0)
Allowlist = SpecialCaseList::createOrDie(AllowlistFiles
#if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0)
,
*vfs::getRealFileSystem()
#endif
);
if (BlocklistFiles.size() > 0)
Blocklist = SpecialCaseList::createOrDie(BlocklistFiles
#if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0)
,
*vfs::getRealFileSystem()
#endif
);
initializeModuleSanitizerCoverageLegacyPassPass(
*PassRegistry::getPassRegistry());
@ -398,8 +241,12 @@ class ModuleSanitizerCoverageLegacyPass : public ModulePass {
bool runOnModule(Module &M) override {
ModuleSanitizerCoverage ModuleSancov(Options, Allowlist.get(),
Blocklist.get());
ModuleSanitizerCoverage ModuleSancov(Options
#if LLVM_MAJOR > 10
,
Allowlist.get(), Blocklist.get()
#endif
);
auto DTCallback = [this](Function &F) -> const DominatorTree * {
return &this->getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
@ -444,8 +291,12 @@ class ModuleSanitizerCoverageLegacyPass : public ModulePass {
PreservedAnalyses ModuleSanitizerCoveragePass::run(Module & M,
ModuleAnalysisManager &MAM) {
ModuleSanitizerCoverage ModuleSancov(Options, Allowlist.get(),
Blocklist.get());
ModuleSanitizerCoverage ModuleSancov(Options
#if LLVM_MAJOR > 10
,
Allowlist.get(), Blocklist.get()
#endif
);
auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
auto DTCallback = [&FAM](Function &F) -> const DominatorTree * {
@ -564,12 +415,6 @@ bool ModuleSanitizerCoverage::instrumentModule(
}
if (Options.CoverageType == SanitizerCoverageOptions::SCK_None) return false;
if (Allowlist &&
!Allowlist->inSection("coverage", "src", M.getSourceFileName()))
return false;
if (Blocklist &&
Blocklist->inSection("coverage", "src", M.getSourceFileName()))
return false;
C = &(M.getContext());
DL = &M.getDataLayout();
CurModule = &M;
@ -842,9 +687,6 @@ void ModuleSanitizerCoverage::instrumentFunction(
if (F.hasPersonalityFn() &&
isAsynchronousEHPersonality(classifyEHPersonality(F.getPersonalityFn())))
return;
if (Allowlist && !Allowlist->inSection("coverage", "fun", F.getName()))
return;
if (Blocklist && Blocklist->inSection("coverage", "fun", F.getName())) return;
if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge)
SplitAllCriticalEdges(
F, CriticalEdgeSplittingOptions().setIgnoreUnreachableDests());
@ -915,10 +757,18 @@ GlobalVariable *ModuleSanitizerCoverage::CreateFunctionLocalArrayInSection(
*CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage,
Constant::getNullValue(ArrayTy), "__sancov_gen_");
#if LLVM_VERSION_MAJOR > 12
if (TargetTriple.supportsCOMDAT() &&
(TargetTriple.isOSBinFormatELF() || !F.isInterposable()))
if (auto Comdat = getOrCreateFunctionComdat(F, TargetTriple))
Array->setComdat(Comdat);
#else
if (TargetTriple.supportsCOMDAT() && !F.isInterposable())
if (auto Comdat =
GetOrCreateFunctionComdat(F, TargetTriple, CurModuleUniqueId))
Array->setComdat(Comdat);
#endif
Array->setSection(getSectionName(Section));
#if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0)
Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedSize()));
@ -1354,12 +1204,20 @@ INITIALIZE_PASS_END(ModuleSanitizerCoverageLegacyPass, "sancov",
false)
ModulePass *llvm::createModuleSanitizerCoverageLegacyPassPass(
const SanitizerCoverageOptions &Options,
const SanitizerCoverageOptions &Options
#if LLVM_MAJOR > 10
,
const std::vector<std::string> &AllowlistFiles,
const std::vector<std::string> &BlocklistFiles) {
const std::vector<std::string> &BlocklistFiles
#endif
) {
return new ModuleSanitizerCoverageLegacyPass(Options, AllowlistFiles,
BlocklistFiles);
return new ModuleSanitizerCoverageLegacyPass(Options
#if LLVM_MAJOR > 10
,
AllowlistFiles, BlocklistFiles
#endif
);
}

View File

@ -20,7 +20,7 @@
#include "config.h"
#include "types.h"
#include "cmplog.h"
#include "llvm-ngram-coverage.h"
#include "llvm-alternative-coverage.h"
#include <stdio.h>
#include <stdlib.h>
@ -34,6 +34,7 @@
#include <errno.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#ifndef __HAIKU__
#include <sys/shm.h>
#endif
@ -96,10 +97,12 @@ int __afl_selective_coverage_temp = 1;
#if defined(__ANDROID__) || defined(__HAIKU__)
PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX];
PREV_LOC_T __afl_prev_caller[CTX_MAX_K];
u32 __afl_prev_ctx;
u32 __afl_cmp_counter;
#else
__thread PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX];
__thread PREV_LOC_T __afl_prev_caller[CTX_MAX_K];
__thread u32 __afl_prev_ctx;
__thread u32 __afl_cmp_counter;
#endif
@ -122,6 +125,21 @@ static u8 is_persistent;
static u8 _is_sancov;
/* Debug? */
static u32 __afl_debug;
/* Already initialized markers */
u32 __afl_already_initialized_shm;
u32 __afl_already_initialized_forkserver;
u32 __afl_already_initialized_first;
u32 __afl_already_initialized_second;
/* Dummy pipe for area_is_valid() */
static int __afl_dummy_fd[2] = {2, 2};
/* ensure we kill the child on termination */
void at_exit(int signal) {
@ -171,7 +189,7 @@ static void __afl_map_shm_fuzz() {
char *id_str = getenv(SHM_FUZZ_ENV_VAR);
if (getenv("AFL_DEBUG")) {
if (__afl_debug) {
fprintf(stderr, "DEBUG: fuzzcase shmem %s\n", id_str ? id_str : "none");
@ -186,7 +204,7 @@ static void __afl_map_shm_fuzz() {
int shm_fd = -1;
/* create the shared memory segment as if it was a file */
shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
shm_fd = shm_open(shm_file_path, O_RDWR, DEFAULT_PERMISSION);
if (shm_fd == -1) {
fprintf(stderr, "shm_open() failed for fuzz\n");
@ -217,7 +235,7 @@ static void __afl_map_shm_fuzz() {
__afl_fuzz_len = (u32 *)map;
__afl_fuzz_ptr = map + sizeof(u32);
if (getenv("AFL_DEBUG")) {
if (__afl_debug) {
fprintf(stderr, "DEBUG: successfully got fuzzing shared memory\n");
@ -237,6 +255,9 @@ static void __afl_map_shm_fuzz() {
static void __afl_map_shm(void) {
if (__afl_already_initialized_shm) return;
__afl_already_initialized_shm = 1;
// if we are not running in afl ensure the map exists
if (!__afl_area_ptr) { __afl_area_ptr = __afl_area_ptr_dummy; }
@ -294,18 +315,23 @@ static void __afl_map_shm(void) {
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"))
if (__afl_debug) {
fprintf(stderr,
"DEBUG: id_str %s, __afl_area_ptr %p, __afl_area_initial %p, "
"__afl_map_addr 0x%llx, MAP_SIZE %u, __afl_final_loc %u, "
"DEBUG: (1) id_str %s, __afl_area_ptr %p, __afl_area_initial %p, "
"__afl_area_ptr_dummy 0x%p, __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_area_ptr,
__afl_area_initial, __afl_map_addr, MAP_SIZE, __afl_final_loc,
FS_OPT_MAX_MAPSIZE, FS_OPT_MAX_MAPSIZE);
__afl_area_initial, __afl_area_ptr_dummy, __afl_map_addr, MAP_SIZE,
__afl_final_loc, FS_OPT_MAX_MAPSIZE, FS_OPT_MAX_MAPSIZE);
}
if (id_str) {
if (__afl_area_ptr && __afl_area_ptr != __afl_area_initial) {
if (__afl_area_ptr && __afl_area_ptr != __afl_area_initial &&
__afl_area_ptr != __afl_area_ptr_dummy) {
if (__afl_map_addr) {
@ -327,7 +353,7 @@ static void __afl_map_shm(void) {
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);
shm_fd = shm_open(shm_file_path, O_RDWR, DEFAULT_PERMISSION);
if (shm_fd == -1) {
fprintf(stderr, "shm_open() failed\n");
@ -350,17 +376,18 @@ static void __afl_map_shm(void) {
}
close(shm_fd);
shm_fd = -1;
if (shm_base == MAP_FAILED) {
close(shm_fd);
shm_fd = -1;
fprintf(stderr, "mmap() failed\n");
perror("mmap for map");
if (__afl_map_addr)
send_forkserver_error(FS_ERROR_MAP_ADDR);
else
send_forkserver_error(FS_ERROR_MMAP);
perror("mmap for map");
exit(2);
@ -439,6 +466,19 @@ static void __afl_map_shm(void) {
__afl_area_ptr_backup = __afl_area_ptr;
if (__afl_debug) {
fprintf(stderr,
"DEBUG: (2) id_str %s, __afl_area_ptr %p, __afl_area_initial %p, "
"__afl_area_ptr_dummy 0x%p, __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_area_ptr,
__afl_area_initial, __afl_area_ptr_dummy, __afl_map_addr, MAP_SIZE,
__afl_final_loc, FS_OPT_MAX_MAPSIZE, FS_OPT_MAX_MAPSIZE);
}
if (__afl_selective_coverage) {
if (__afl_map_size > MAP_INITIAL_SIZE) {
@ -467,7 +507,7 @@ static void __afl_map_shm(void) {
id_str = getenv(CMPLOG_SHM_ENV_VAR);
if (getenv("AFL_DEBUG")) {
if (__afl_debug) {
fprintf(stderr, "DEBUG: cmplog id_str %s\n",
id_str == NULL ? "<null>" : id_str);
@ -476,13 +516,19 @@ static void __afl_map_shm(void) {
if (id_str) {
if ((__afl_dummy_fd[1] = open("/dev/null", O_WRONLY)) < 0) {
if (pipe(__afl_dummy_fd) < 0) { __afl_dummy_fd[1] = 1; }
}
#ifdef USEMMAP
const char * shm_file_path = id_str;
int shm_fd = -1;
struct cmp_map *shm_base = NULL;
/* create the shared memory segment as if it was a file */
shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
shm_fd = shm_open(shm_file_path, O_RDWR, DEFAULT_PERMISSION);
if (shm_fd == -1) {
perror("shm_open() failed\n");
@ -526,6 +572,58 @@ static void __afl_map_shm(void) {
}
/* unmap SHM. */
static void __afl_unmap_shm(void) {
if (!__afl_already_initialized_shm) return;
char *id_str = getenv(SHM_ENV_VAR);
if (id_str) {
#ifdef USEMMAP
munmap((void *)__afl_area_ptr, __afl_map_size);
#else
shmdt((void *)__afl_area_ptr);
#endif
} else if ((!__afl_area_ptr || __afl_area_ptr == __afl_area_initial) &&
__afl_map_addr) {
munmap((void *)__afl_map_addr, __afl_map_size);
}
__afl_area_ptr = __afl_area_ptr_dummy;
id_str = getenv(CMPLOG_SHM_ENV_VAR);
if (id_str) {
#ifdef USEMMAP
munmap((void *)__afl_cmp_map, __afl_map_size);
#else
shmdt((void *)__afl_cmp_map);
#endif
__afl_cmp_map = NULL;
}
__afl_already_initialized_shm = 0;
}
#ifdef __linux__
static void __afl_start_snapshots(void) {
@ -554,7 +652,7 @@ static void __afl_start_snapshots(void) {
if (read(FORKSRV_FD, &was_killed, 4) != 4) { _exit(1); }
if (getenv("AFL_DEBUG")) {
if (__afl_debug) {
fprintf(stderr, "target forkserver recv: %08x\n", was_killed);
@ -631,7 +729,7 @@ static void __afl_start_snapshots(void) {
static uint32_t counter = 0;
char fn[32];
sprintf(fn, "%09u:forkserver", counter);
s32 fd_doc = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
s32 fd_doc = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
if (fd_doc >= 0) {
if (write(fd_doc, __afl_fuzz_ptr, *__afl_fuzz_len) != *__afl_fuzz_len) {
@ -731,6 +829,9 @@ static void __afl_start_snapshots(void) {
static void __afl_start_forkserver(void) {
if (__afl_already_initialized_forkserver) return;
__afl_already_initialized_forkserver = 1;
struct sigaction orig_action;
sigaction(SIGTERM, NULL, &orig_action);
old_sigterm_handler = orig_action.sa_handler;
@ -781,7 +882,7 @@ static void __afl_start_forkserver(void) {
if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
if (getenv("AFL_DEBUG")) {
if (__afl_debug) {
fprintf(stderr, "target forkserver recv: %08x\n", was_killed);
@ -859,7 +960,7 @@ static void __afl_start_forkserver(void) {
static uint32_t counter = 0;
char fn[32];
sprintf(fn, "%09u:forkserver", counter);
s32 fd_doc = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
s32 fd_doc = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
if (fd_doc >= 0) {
if (write(fd_doc, __afl_fuzz_ptr, *__afl_fuzz_len) != *__afl_fuzz_len) {
@ -1016,11 +1117,14 @@ void __afl_manual_init(void) {
__afl_sharedmem_fuzzing = 0;
if (__afl_area_ptr == NULL) __afl_area_ptr = __afl_area_ptr_dummy;
if (getenv("AFL_DEBUG"))
if (__afl_debug) {
fprintf(stderr,
"DEBUG: disabled instrumentation because of "
"AFL_DISABLE_LLVM_INSTRUMENTATION\n");
}
}
if (!init_done) {
@ -1060,6 +1164,11 @@ __attribute__((constructor(CTOR_PRIO))) void __afl_auto_early(void) {
__attribute__((constructor(1))) void __afl_auto_second(void) {
if (__afl_already_initialized_second) return;
__afl_already_initialized_second = 1;
if (getenv("AFL_DEBUG")) { __afl_debug = 1; }
if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
u8 *ptr;
@ -1084,17 +1193,18 @@ __attribute__((constructor(1))) void __afl_auto_second(void) {
}
}
} // ptr memleak report is a false positive
/* preset __afl_area_ptr #1 - at constructor level 0 global variables have
not been set */
__attribute__((constructor(0))) void __afl_auto_first(void) {
if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
u8 *ptr;
if (__afl_already_initialized_first) return;
__afl_already_initialized_first = 1;
ptr = (u8 *)malloc(MAP_INITIAL_SIZE);
if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
u8 *ptr = (u8 *)malloc(MAP_INITIAL_SIZE);
if (ptr && (ssize_t)ptr != -1) {
@ -1103,7 +1213,7 @@ __attribute__((constructor(0))) void __afl_auto_first(void) {
}
}
} // ptr memleak report is a false positive
/* The following stuff deals with supporting -fsanitize-coverage=trace-pc-guard.
It remains non-operational in the traditional, plugin-backed LLVM mode.
@ -1171,11 +1281,13 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
_is_sancov = 1;
if (getenv("AFL_DEBUG")) {
if (__afl_debug) {
fprintf(stderr,
"Running __sanitizer_cov_trace_pc_guard_init: %p-%p (%lu edges)\n",
start, stop, (unsigned long)(stop - start));
"Running __sanitizer_cov_trace_pc_guard_init: %p-%p (%lu edges) "
"after_fs=%u\n",
start, stop, (unsigned long)(stop - start),
__afl_already_initialized_forkserver);
}
@ -1191,6 +1303,40 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
}
/* instrumented code is loaded *after* our forkserver is up. this is a
problem. We cannot prevent collisions then :( */
if (__afl_already_initialized_forkserver &&
__afl_final_loc + 1 + stop - start > __afl_map_size) {
if (__afl_debug) {
fprintf(stderr, "Warning: new instrumented code after the forkserver!\n");
}
__afl_final_loc = 2;
if (1 + stop - start > __afl_map_size) {
*(start++) = ++__afl_final_loc;
while (start < stop) {
if (R(100) < inst_ratio)
*start = ++__afl_final_loc % __afl_map_size;
else
*start = 0;
start++;
}
return;
}
}
/* Make sure that the first element in the range is always set - we use that
to avoid duplicate calls (which can happen as an artifact of the underlying
implementation in LLVM). */
@ -1208,6 +1354,28 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
}
if (__afl_debug) {
fprintf(stderr,
"Done __sanitizer_cov_trace_pc_guard_init: __afl_final_loc = %u\n",
__afl_final_loc);
}
if (__afl_already_initialized_shm && __afl_final_loc > __afl_map_size) {
if (__afl_debug) {
fprintf(stderr, "Reinit shm necessary (+%u)\n",
__afl_final_loc - __afl_map_size);
}
__afl_unmap_shm();
__afl_map_shm();
}
}
///// CmpLog instrumentation
@ -1508,6 +1676,12 @@ void __sanitizer_cov_trace_cmp16(uint128_t arg1, uint128_t arg2) {
}
void __sanitizer_cov_trace_const_cmp16(uint128_t arg1, uint128_t arg2) {
__cmplog_ins_hook16(arg1, arg2, 0);
}
#endif
void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
@ -1551,17 +1725,43 @@ void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
}
__attribute__((weak)) void *__asan_region_is_poisoned(void *beg, size_t size) {
return NULL;
}
// POSIX shenanigan to see if an area is mapped.
// If it is mapped as X-only, we have a problem, so maybe we should add a check
// to avoid to call it on .text addresses
static int area_is_mapped(void *ptr, size_t len) {
static int area_is_valid(void *ptr, size_t len) {
if (unlikely(!ptr || __asan_region_is_poisoned(ptr, len))) { return 0; }
long r = syscall(SYS_write, __afl_dummy_fd[1], ptr, len);
if (r <= 0 || r > len) return 0;
// even if the write succeed this can be a false positive if we cross
// a page boundary. who knows why.
char *p = (char *)ptr;
char *page = (char *)((uintptr_t)p & ~(sysconf(_SC_PAGE_SIZE) - 1));
long page_size = sysconf(_SC_PAGE_SIZE);
char *page = (char *)((uintptr_t)p & ~(page_size - 1)) + page_size;
int r = msync(page, (p - page) + len, MS_ASYNC);
if (r < 0) return errno != ENOMEM;
return 1;
if (page > p + len) {
// no, not crossing a page boundary
return (int)r;
} else {
// yes it crosses a boundary, hence we can only return the length of
// rest of the first page, we cannot detect if the next page is valid
// or not, neither by SYS_write nor msync() :-(
return (int)(page - p);
}
}
@ -1569,20 +1769,25 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) {
/*
u32 i;
if (!area_is_mapped(ptr1, 32) || !area_is_mapped(ptr2, 32)) return;
if (area_is_valid(ptr1, 32) <= 0 || area_is_valid(ptr2, 32) <= 0) return;
fprintf(stderr, "rtn arg0=");
for (i = 0; i < 24; i++)
for (i = 0; i < 32; i++)
fprintf(stderr, "%02x", ptr1[i]);
fprintf(stderr, " arg1=");
for (i = 0; i < 24; i++)
for (i = 0; i < 32; i++)
fprintf(stderr, "%02x", ptr2[i]);
fprintf(stderr, "\n");
*/
if (unlikely(!__afl_cmp_map)) return;
// fprintf(stderr, "RTN1 %p %p\n", ptr1, ptr2);
int l1, l2;
if ((l1 = area_is_valid(ptr1, 32)) <= 0 ||
(l2 = area_is_valid(ptr2, 32)) <= 0)
return;
int len = MIN(l1, l2);
if (!area_is_mapped(ptr1, 32) || !area_is_mapped(ptr2, 32)) return;
// fprintf(stderr, "RTN2 %u\n", len);
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (k >> 4) ^ (k << 8);
k &= CMP_MAP_W - 1;
@ -1592,17 +1797,17 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) {
if (__afl_cmp_map->headers[k].type != CMP_TYPE_RTN) {
__afl_cmp_map->headers[k].type = CMP_TYPE_RTN;
hits = 0;
__afl_cmp_map->headers[k].hits = 1;
__afl_cmp_map->headers[k].shape = 31;
__afl_cmp_map->headers[k].shape = len - 1;
hits = 0;
} else {
hits = __afl_cmp_map->headers[k].hits++;
if (__afl_cmp_map->headers[k].shape < 31) {
if (__afl_cmp_map->headers[k].shape < len) {
__afl_cmp_map->headers[k].shape = 31;
__afl_cmp_map->headers[k].shape = len - 1;
}
@ -1610,9 +1815,10 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) {
hits &= CMP_MAP_RTN_H - 1;
__builtin_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v0,
ptr1, 32);
ptr1, len);
__builtin_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v1,
ptr2, 32);
ptr2, len);
// fprintf(stderr, "RTN3\n");
}
@ -1658,7 +1864,8 @@ static u8 *get_llvm_stdstring(u8 *string) {
void __cmplog_rtn_gcc_stdstring_cstring(u8 *stdstring, u8 *cstring) {
if (unlikely(!__afl_cmp_map)) return;
if (!area_is_mapped(stdstring, 32) || !area_is_mapped(cstring, 32)) return;
if (area_is_valid(stdstring, 32) <= 0 || area_is_valid(cstring, 32) <= 0)
return;
__cmplog_rtn_hook(get_gcc_stdstring(stdstring), cstring);
@ -1667,7 +1874,7 @@ void __cmplog_rtn_gcc_stdstring_cstring(u8 *stdstring, u8 *cstring) {
void __cmplog_rtn_gcc_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) {
if (unlikely(!__afl_cmp_map)) return;
if (!area_is_mapped(stdstring1, 32) || !area_is_mapped(stdstring2, 32))
if (area_is_valid(stdstring1, 32) <= 0 || area_is_valid(stdstring2, 32) <= 0)
return;
__cmplog_rtn_hook(get_gcc_stdstring(stdstring1),
@ -1678,7 +1885,8 @@ void __cmplog_rtn_gcc_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) {
void __cmplog_rtn_llvm_stdstring_cstring(u8 *stdstring, u8 *cstring) {
if (unlikely(!__afl_cmp_map)) return;
if (!area_is_mapped(stdstring, 32) || !area_is_mapped(cstring, 32)) return;
if (area_is_valid(stdstring, 32) <= 0 || area_is_valid(cstring, 32) <= 0)
return;
__cmplog_rtn_hook(get_llvm_stdstring(stdstring), cstring);
@ -1687,7 +1895,7 @@ void __cmplog_rtn_llvm_stdstring_cstring(u8 *stdstring, u8 *cstring) {
void __cmplog_rtn_llvm_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) {
if (unlikely(!__afl_cmp_map)) return;
if (!area_is_mapped(stdstring1, 32) || !area_is_mapped(stdstring2, 32))
if (area_is_valid(stdstring1, 32) <= 0 || area_is_valid(stdstring2, 32) <= 0)
return;
__cmplog_rtn_hook(get_llvm_stdstring(stdstring1),

View File

@ -60,20 +60,25 @@ bool isIgnoreFunction(const llvm::Function *F) {
"asan.",
"llvm.",
"sancov.",
"__ubsan_",
"__ubsan",
"ign.",
"__afl_",
"__afl",
"_fini",
"__libc_csu",
"__libc_",
"__asan",
"__msan",
"__cmplog",
"__sancov",
"__san",
"__cxx_",
"__decide_deferred",
"_GLOBAL",
"_ZZN6__asan",
"_ZZN6__lsan",
"msan.",
"LLVMFuzzerM",
"LLVMFuzzerC",
"LLVMFuzzerI",
"__decide_deferred",
"maybe_duplicate_stderr",
"discard_output",
"close_stdout",
@ -89,6 +94,20 @@ bool isIgnoreFunction(const llvm::Function *F) {
}
static const char *ignoreSubstringList[] = {
"__asan", "__msan", "__ubsan", "__lsan",
"__san", "__sanitize", "__cxx", "_GLOBAL__",
"DebugCounter", "DwarfDebug", "DebugLoc"
};
for (auto const &ignoreListFunc : ignoreSubstringList) {
if (F->getName().contains(ignoreListFunc)) { return true; }
}
return false;
}

View File

@ -357,6 +357,7 @@ bool AFLdict2filePass::runOnModule(Module &M) {
StringRef TmpStr;
bool HasStr1;
getConstantStringInfo(Str1P, TmpStr);
if (TmpStr.empty()) {
HasStr1 = false;
@ -403,7 +404,7 @@ bool AFLdict2filePass::runOnModule(Module &M) {
dyn_cast<ConstantDataArray>(Var->getInitializer())) {
HasStr2 = true;
Str2 = Array->getAsString().str();
Str2 = Array->getRawDataValues().str();
}
@ -479,7 +480,7 @@ bool AFLdict2filePass::runOnModule(Module &M) {
dyn_cast<ConstantDataArray>(Var->getInitializer())) {
HasStr1 = true;
Str1 = Array->getAsString().str();
Str1 = Array->getRawDataValues().str();
}
@ -520,14 +521,18 @@ bool AFLdict2filePass::runOnModule(Module &M) {
optLen = thestring.length();
if (optLen < 2 || (optLen == 2 && !thestring[1])) { continue; }
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 (optLen < 2) { continue; }
if (literalLength + 1 == optLen) { // add null byte
thestring.append("\0", 1);
addedNull = true;
@ -542,17 +547,21 @@ bool AFLdict2filePass::runOnModule(Module &M) {
// was not already added
if (!isMemcmp) {
if (addedNull == false) {
if (addedNull == false && thestring[optLen - 1] != '\0') {
thestring.append("\0", 1); // add null byte
optLen++;
}
// ensure we do not have garbage
size_t offset = thestring.find('\0', 0);
if (offset + 1 < optLen) optLen = offset + 1;
thestring = thestring.substr(0, optLen);
if (!isStdString) {
// ensure we do not have garbage
size_t offset = thestring.find('\0', 0);
if (offset + 1 < optLen) optLen = offset + 1;
thestring = thestring.substr(0, optLen);
}
}

View File

@ -519,7 +519,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
Var->getInitializer())) {
HasStr2 = true;
Str2 = Array->getAsString().str();
Str2 = Array->getRawDataValues().str();
}
@ -595,7 +595,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
Var->getInitializer())) {
HasStr1 = true;
Str1 = Array->getAsString().str();
Str1 = Array->getRawDataValues().str();
}
@ -635,15 +635,18 @@ bool AFLLTOPass::runOnModule(Module &M) {
thestring = Str2;
optLen = thestring.length();
if (optLen < 2 || (optLen == 2 && !thestring[1])) { continue; }
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 (optLen < 2) { continue; }
if (literalLength + 1 == optLen) { // add null byte
thestring.append("\0", 1);
addedNull = true;
@ -658,17 +661,21 @@ bool AFLLTOPass::runOnModule(Module &M) {
// was not already added
if (!isMemcmp) {
if (addedNull == false) {
if (addedNull == false && thestring[optLen - 1] != '\0') {
thestring.append("\0", 1); // add null byte
optLen++;
}
// ensure we do not have garbage
size_t offset = thestring.find('\0', 0);
if (offset + 1 < optLen) optLen = offset + 1;
thestring = thestring.substr(0, optLen);
if (!isStdString) {
// ensure we do not have garbage
size_t offset = thestring.find('\0', 0);
if (offset + 1 < optLen) optLen = offset + 1;
thestring = thestring.substr(0, optLen);
}
}

View File

@ -62,7 +62,7 @@ typedef long double max_align_t;
#endif
#include "afl-llvm-common.h"
#include "llvm-ngram-coverage.h"
#include "llvm-alternative-coverage.h"
using namespace llvm;
@ -82,9 +82,10 @@ class AFLCoverage : public ModulePass {
protected:
uint32_t ngram_size = 0;
uint32_t ctx_k = 0;
uint32_t map_size = MAP_SIZE;
uint32_t function_minimum_size = 1;
char * ctx_str = NULL, *skip_nozero = NULL;
char * ctx_str = NULL, *caller_str = NULL, *skip_nozero = NULL;
};
@ -183,10 +184,16 @@ bool AFLCoverage::runOnModule(Module &M) {
skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
unsigned PrevLocSize = 0;
unsigned PrevCallerSize = 0;
char *ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE");
if (!ngram_size_str) ngram_size_str = getenv("AFL_NGRAM_SIZE");
char *ctx_k_str = getenv("AFL_LLVM_CTX_K");
if (!ctx_k_str) ctx_k_str = getenv("AFL_CTX_K");
ctx_str = getenv("AFL_LLVM_CTX");
caller_str = getenv("AFL_LLVM_CALLER");
bool instrument_ctx = ctx_str || caller_str;
#ifdef AFL_HAVE_VECTOR_INTRINSICS
/* Decide previous location vector size (must be a power of two) */
@ -204,6 +211,31 @@ bool AFLCoverage::runOnModule(Module &M) {
if (ngram_size)
PrevLocSize = ngram_size - 1;
else
PrevLocSize = 1;
/* Decide K-ctx vector size (must be a power of two) */
VectorType *PrevCallerTy = NULL;
if (ctx_k_str)
if (sscanf(ctx_k_str, "%u", &ctx_k) != 1 || ctx_k < 1 || ctx_k > CTX_MAX_K)
FATAL("Bad value of AFL_CTX_K (must be between 1 and CTX_MAX_K (%u))",
CTX_MAX_K);
if (ctx_k == 1) {
ctx_k = 0;
instrument_ctx = true;
caller_str = ctx_k_str; // Enable CALLER instead
}
if (ctx_k) {
PrevCallerSize = ctx_k;
instrument_ctx = true;
}
#else
if (ngram_size_str)
#ifndef LLVM_VERSION_PATCH
@ -217,8 +249,20 @@ bool AFLCoverage::runOnModule(Module &M) {
"%d.%d.%d!",
LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, LLVM_VERSION_PATCH);
#endif
if (ctx_k_str)
#ifndef LLVM_VERSION_PATCH
FATAL(
"Sorry, K-CTX branch coverage is not supported with llvm version "
"%d.%d.%d!",
LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, 0);
#else
FATAL(
"Sorry, K-CTX branch coverage is not supported with llvm version "
"%d.%d.%d!",
LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, LLVM_VERSION_PATCH);
#endif
PrevLocSize = 1;
#endif
PrevLocSize = 1;
#ifdef AFL_HAVE_VECTOR_INTRINSICS
int PrevLocVecSize = PowerOf2Ceil(PrevLocSize);
@ -231,6 +275,17 @@ bool AFLCoverage::runOnModule(Module &M) {
);
#endif
#ifdef AFL_HAVE_VECTOR_INTRINSICS
int PrevCallerVecSize = PowerOf2Ceil(PrevCallerSize);
if (ctx_k)
PrevCallerTy = VectorType::get(IntLocTy, PrevCallerVecSize
#if LLVM_VERSION_MAJOR >= 12
,
false
#endif
);
#endif
/* Get globals for the SHM region and the previous location. Note that
__afl_prev_loc is thread-local. */
@ -238,9 +293,10 @@ bool AFLCoverage::runOnModule(Module &M) {
new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,
GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
GlobalVariable *AFLPrevLoc;
GlobalVariable *AFLPrevCaller;
GlobalVariable *AFLContext = NULL;
if (ctx_str)
if (ctx_str || caller_str)
#if defined(__ANDROID__) || defined(__HAIKU__)
AFLContext = new GlobalVariable(
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx");
@ -274,6 +330,31 @@ bool AFLCoverage::runOnModule(Module &M) {
GlobalVariable::GeneralDynamicTLSModel, 0, false);
#endif
#ifdef AFL_HAVE_VECTOR_INTRINSICS
if (ctx_k)
#if defined(__ANDROID__) || defined(__HAIKU__)
AFLPrevCaller = new GlobalVariable(
M, PrevCallerTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
/* Initializer */ nullptr, "__afl_prev_caller");
#else
AFLPrevCaller = new GlobalVariable(
M, PrevCallerTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
/* Initializer */ nullptr, "__afl_prev_caller",
/* InsertBefore */ nullptr, GlobalVariable::GeneralDynamicTLSModel,
/* AddressSpace */ 0, /* IsExternallyInitialized */ false);
#endif
else
#endif
#if defined(__ANDROID__) || defined(__HAIKU__)
AFLPrevCaller =
new GlobalVariable(M, Int32Ty, false, GlobalValue::ExternalLinkage, 0,
"__afl_prev_caller");
#else
AFLPrevCaller = new GlobalVariable(
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_caller",
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
@ -288,13 +369,30 @@ bool AFLCoverage::runOnModule(Module &M) {
PrevLocShuffle.push_back(ConstantInt::get(Int32Ty, PrevLocSize));
Constant *PrevLocShuffleMask = ConstantVector::get(PrevLocShuffle);
Constant * PrevCallerShuffleMask = NULL;
SmallVector<Constant *, 32> PrevCallerShuffle = {UndefValue::get(Int32Ty)};
if (ctx_k) {
for (unsigned I = 0; I < PrevCallerSize - 1; ++I)
PrevCallerShuffle.push_back(ConstantInt::get(Int32Ty, I));
for (int I = PrevCallerSize; I < PrevCallerVecSize; ++I)
PrevCallerShuffle.push_back(ConstantInt::get(Int32Ty, PrevCallerSize));
PrevCallerShuffleMask = ConstantVector::get(PrevCallerShuffle);
}
#endif
// other constants we need
ConstantInt *Zero = ConstantInt::get(Int8Ty, 0);
ConstantInt *One = ConstantInt::get(Int8Ty, 1);
LoadInst *PrevCtx = NULL; // CTX sensitive coverage
Value * PrevCtx = NULL; // CTX sensitive coverage
LoadInst *PrevCaller = NULL; // K-CTX coverage
/* Instrument all the things! */
@ -318,12 +416,30 @@ bool AFLCoverage::runOnModule(Module &M) {
IRBuilder<> IRB(&(*IP));
// Context sensitive coverage
if (ctx_str && &BB == &F.getEntryBlock()) {
if (instrument_ctx && &BB == &F.getEntryBlock()) {
// 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));
#ifdef AFL_HAVE_VECTOR_INTRINSICS
if (ctx_k) {
PrevCaller = IRB.CreateLoad(AFLPrevCaller);
PrevCaller->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
PrevCtx =
IRB.CreateZExt(IRB.CreateXorReduce(PrevCaller), IRB.getInt32Ty());
} else
#endif
{
// load the context ID of the previous function and write to to a
// local variable on the stack
LoadInst *PrevCtxLoad = IRB.CreateLoad(AFLContext);
PrevCtxLoad->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
PrevCtx = PrevCtxLoad;
}
// does the function have calls? and is any of the calls larger than one
// basic block?
@ -354,10 +470,32 @@ bool AFLCoverage::runOnModule(Module &M) {
// 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));
Value *NewCtx = ConstantInt::get(Int32Ty, AFL_R(map_size));
#ifdef AFL_HAVE_VECTOR_INTRINSICS
if (ctx_k) {
Value *ShuffledPrevCaller = IRB.CreateShuffleVector(
PrevCaller, UndefValue::get(PrevCallerTy),
PrevCallerShuffleMask);
Value *UpdatedPrevCaller = IRB.CreateInsertElement(
ShuffledPrevCaller, NewCtx, (uint64_t)0);
StoreInst *Store =
IRB.CreateStore(UpdatedPrevCaller, AFLPrevCaller);
Store->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
} else
#endif
{
if (ctx_str) NewCtx = IRB.CreateXor(PrevCtx, NewCtx);
StoreInst *StoreCtx = IRB.CreateStore(NewCtx, AFLContext);
StoreCtx->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
}
}
@ -411,13 +549,20 @@ bool AFLCoverage::runOnModule(Module &M) {
// in CTX mode we have to restore the original context for the caller -
// she might be calling other functions which need the correct CTX
if (ctx_str && has_calls) {
if (instrument_ctx && has_calls) {
Instruction *Inst = BB.getTerminator();
if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst)) {
IRBuilder<> Post_IRB(Inst);
StoreInst * RestoreCtx = Post_IRB.CreateStore(PrevCtx, AFLContext);
StoreInst *RestoreCtx;
#ifdef AFL_HAVE_VECTOR_INTRINSICS
if (ctx_k)
RestoreCtx = IRB.CreateStore(PrevCaller, AFLPrevCaller);
else
#endif
RestoreCtx = Post_IRB.CreateStore(PrevCtx, AFLContext);
RestoreCtx->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
@ -458,7 +603,7 @@ bool AFLCoverage::runOnModule(Module &M) {
#endif
PrevLocTrans = PrevLoc;
if (ctx_str)
if (instrument_ctx)
PrevLocTrans =
IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, PrevCtx), Int32Ty);
else
@ -545,13 +690,20 @@ 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) {
if (instrument_ctx && has_calls) {
Instruction *Inst = BB.getTerminator();
if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst)) {
IRBuilder<> Post_IRB(Inst);
StoreInst * RestoreCtx = Post_IRB.CreateStore(PrevCtx, AFLContext);
StoreInst *RestoreCtx;
#ifdef AFL_HAVE_VECTOR_INTRINSICS
if (ctx_k)
RestoreCtx = IRB.CreateStore(PrevCaller, AFLPrevCaller);
else
#endif
RestoreCtx = Post_IRB.CreateStore(PrevCtx, AFLContext);
RestoreCtx->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));

View File

@ -418,7 +418,7 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
IntegerType * intTyOp0 = NULL;
IntegerType * intTyOp1 = NULL;
unsigned max_size = 0, cast_size = 0;
unsigned char attr = 0, do_cast = 0;
unsigned char attr = 0;
std::vector<Value *> args;
CmpInst *cmpInst = dyn_cast<CmpInst>(selectcmpInst);
@ -484,7 +484,6 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
max_size = 128;
attr += 8;
do_cast = 1;
} else {
@ -503,12 +502,7 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
if (!max_size || max_size < 16) { continue; }
if (max_size % 8) {
max_size = (((max_size / 8) + 1) * 8);
do_cast = 1;
}
if (max_size % 8) { max_size = (((max_size / 8) + 1) * 8); }
if (max_size > 128) {
@ -521,7 +515,6 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
}
max_size = 128;
do_cast = 1;
}
@ -537,7 +530,6 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
break;
default:
cast_size = 128;
do_cast = 1;
}
@ -574,7 +566,7 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
}
// fprintf(stderr, "_ExtInt(%u) castTo %u with attr %u didcast %u\n",
// max_size, cast_size, attr, do_cast);
// max_size, cast_size, attr);
switch (cast_size) {

View File

@ -229,9 +229,9 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
dyn_cast<ConstantDataArray>(Var->getInitializer())) {
HasStr2 = true;
Str2 = Array->getAsString();
Str2 = Array->getRawDataValues();
valueMap[Str2P] = new std::string(Str2.str());
fprintf(stderr, "glo2 %s\n", Str2.str().c_str());
// fprintf(stderr, "glo2 %s\n", Str2.str().c_str());
}
@ -254,7 +254,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
Var->getInitializer())) {
HasStr1 = true;
Str1 = Array->getAsString();
Str1 = Array->getRawDataValues();
valueMap[Str1P] = new std::string(Str1.str());
// fprintf(stderr, "glo1 %s\n", Str1.str().c_str());
@ -316,7 +316,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
uint64_t len = ilen->getZExtValue();
// if len is zero this is a pointless call but allow real
// implementation to worry about that
if (!len) continue;
if (len < 2) continue;
if (isMemcmp) {
@ -420,15 +420,29 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
}
if (TmpConstStr.length() < 2 ||
(TmpConstStr.length() == 2 && !TmpConstStr[1])) {
continue;
}
// add null termination character implicit in c strings
TmpConstStr.append("\0", 1);
if (!isMemcmp && TmpConstStr[TmpConstStr.length() - 1]) {
TmpConstStr.append("\0", 1);
}
// in the unusual case the const str has embedded null
// characters, the string comparison functions should terminate
// at the first null
if (!isMemcmp)
if (!isMemcmp) {
TmpConstStr.assign(TmpConstStr, 0, TmpConstStr.find('\0') + 1);
}
constStrLen = TmpConstStr.length();
// prefer use of StringRef (in comparison to std::string a StringRef has
// built-in runtime bounds checking, which makes debugging easier)

View File

@ -14,5 +14,8 @@ typedef u64 PREV_LOC_T;
/* Maximum ngram size */
#define NGRAM_SIZE_MAX 16U
/* Maximum K for top-K context sensitivity */
#define CTX_MAX_K 32U
#endif

View File

@ -149,8 +149,11 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) {
auto op1 = FcmpInst->getOperand(1);
/* find out what the new predicate is going to be */
auto pred = dyn_cast<CmpInst>(FcmpInst)->getPredicate();
auto cmp_inst = dyn_cast<CmpInst>(FcmpInst);
if (!cmp_inst) { continue; }
auto pred = cmp_inst->getPredicate();
CmpInst::Predicate new_pred;
switch (pred) {
case CmpInst::FCMP_UGE:
@ -276,8 +279,11 @@ bool SplitComparesTransform::simplifyCompares(Module &M) {
auto op1 = IcmpInst->getOperand(1);
/* find out what the new predicate is going to be */
auto pred = dyn_cast<CmpInst>(IcmpInst)->getPredicate();
auto cmp_inst = dyn_cast<CmpInst>(IcmpInst);
if (!cmp_inst) { continue; }
auto pred = cmp_inst->getPredicate();
CmpInst::Predicate new_pred;
switch (pred) {
case CmpInst::ICMP_UGE:
@ -412,8 +418,11 @@ bool SplitComparesTransform::simplifyIntSignedness(Module &M) {
IntegerType *IntType = IntegerType::get(C, bitw);
/* get the new predicate */
auto pred = dyn_cast<CmpInst>(IcmpInst)->getPredicate();
auto cmp_inst = dyn_cast<CmpInst>(IcmpInst);
if (!cmp_inst) { continue; }
auto pred = cmp_inst->getPredicate();
CmpInst::Predicate new_pred;
if (pred == CmpInst::ICMP_SGT) {
new_pred = CmpInst::ICMP_UGT;
@ -603,6 +612,10 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
if (op_size != op1->getType()->getPrimitiveSizeInBits()) { continue; }
const unsigned int sizeInBits = op0->getType()->getPrimitiveSizeInBits();
// BUG FIXME TODO: u64 does not work for > 64 bit ... e.g. 80 and 128 bit
if (sizeInBits > 64) { continue; }
const unsigned int precision = sizeInBits == 32 ? 24
: sizeInBits == 64 ? 53
: sizeInBits == 128 ? 113
@ -610,8 +623,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
: sizeInBits == 80 ? 65
: sizeInBits - 8;
const unsigned shiftR_exponent = precision - 1;
// BUG FIXME TODO: u64 does not work for > 64 bit ... e.g. 80 and 128 bit
const unsigned shiftR_exponent = precision - 1;
const unsigned long long mask_fraction =
(1ULL << (shiftR_exponent - 1)) | ((1ULL << (shiftR_exponent - 1)) - 1);
const unsigned long long mask_exponent =
@ -1113,7 +1125,9 @@ size_t SplitComparesTransform::splitIntCompares(Module &M, unsigned bitw) {
auto op0 = IcmpInst->getOperand(0);
auto op1 = IcmpInst->getOperand(1);
auto pred = dyn_cast<CmpInst>(IcmpInst)->getPredicate();
auto cmp_inst = dyn_cast<CmpInst>(IcmpInst);
if (!cmp_inst) { continue; }
auto pred = cmp_inst->getPredicate();
BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(IcmpInst));

View File

@ -1 +1 @@
e36a30ebca
ddc4a9748d

View File

@ -99,6 +99,13 @@ Just set AFL_QEMU_INST_RANGES=A,B,C...
The format of the items in the list is either a range of addresses like 0x123-0x321
or a module name like module.so (that is matched in the mapped object filename).
Alternatively you can tell QEMU to ignore part of an address space for instrumentation.
Just set AFL_QEMU_EXCLUDE_RANGES=A,B,C...
The format of the items on the list is the same as for AFL_QEMU_INST_RANGES, and excluding ranges
takes priority over any included ranges or AFL_INST_LIBS.
## 7) CompareCoverage
CompareCoverage is a sub-instrumentation with effects similar to laf-intel.

View File

@ -59,51 +59,11 @@ if [ ! -f "../afl-showmap" ]; then
fi
PREREQ_NOTFOUND=
for i in git wget sha384sum bison flex iconv patch pkg-config; do
T=`command -v "$i" 2>/dev/null`
if [ "$T" = "" ]; then
echo "[-] Error: '$i' not found, please install first."
PREREQ_NOTFOUND=1
fi
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."
PREREQ_NOTFOUND=1
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."
PREREQ_NOTFOUND=1
fi
if [ "$PREREQ_NOTFOUND" = "1" ]; then
exit 1
fi
echo "[+] All checks passed!"
@ -131,9 +91,13 @@ test -d qemuafl || { echo "[-] Not checked out, please install git or check your
echo "[+] Got qemuafl."
cd "qemuafl" || exit 1
echo "[*] Checking out $QEMUAFL_VERSION"
sh -c 'git stash && git stash drop' 1>/dev/null 2>/dev/null
git checkout "$QEMUAFL_VERSION" || echo Warning: could not check out to commit $QEMUAFL_VERSION
if [ -n "$NO_CHECKOUT" ]; then
echo "[*] Skipping checkout to $QEMUAFL_VERSION"
else
echo "[*] Checking out $QEMUAFL_VERSION"
sh -c 'git stash' 1>/dev/null 2>/dev/null
git checkout "$QEMUAFL_VERSION" || echo Warning: could not check out to commit $QEMUAFL_VERSION
fi
echo "[*] Making sure imported headers matches"
cp "../../include/config.h" "./qemuafl/imported/" || exit 1
@ -233,7 +197,6 @@ QEMU_CONF_FLAGS=" \
--disable-xen \
--disable-xen-pci-passthrough \
--disable-xfsctl \
--python=${PYTHONBIN} \
--target-list="${CPU_TARGET}-linux-user" \
--without-default-devices \
"
@ -372,6 +335,20 @@ if [ "$ORIG_CROSS" = "" ]; then
then # works on Arch Linux
CROSS=$CPU_TARGET-pc-linux-gnu-gcc
fi
if ! command -v "$CROSS" > /dev/null && [ "$CPU_TARGET" = "i386" ]
then
CROSS=i686-linux-gnu-gcc
if ! command -v "$CROSS" > /dev/null
then # works on Arch Linux
CROSS=i686-pc-linux-gnu-gcc
fi
if ! command -v "$CROSS" > /dev/null && [ "`uname -m`" = "x86_64" ]
then # set -m32
test "$CC" = "" && CC="gcc"
CROSS="$CC"
CROSS_FLAGS=-m32
fi
fi
fi
if ! command -v "$CROSS" > /dev/null ; then
@ -387,13 +364,13 @@ if ! command -v "$CROSS" > /dev/null ; then
echo "[!] Cross compiler $CROSS could not be found, cannot compile libcompcov libqasan and unsigaction"
fi
else
echo "[+] Building afl++ qemu support libraries with CC=$CROSS"
echo "[+] Building afl++ qemu support libraries with CC=\"$CROSS $CROSS_FLAGS\""
echo "[+] Building libcompcov ..."
make -C libcompcov CC=$CROSS && echo "[+] libcompcov ready"
make -C libcompcov CC="$CROSS $CROSS_FLAGS" && echo "[+] libcompcov ready"
echo "[+] Building unsigaction ..."
make -C unsigaction CC=$CROSS && echo "[+] unsigaction ready"
make -C unsigaction CC="$CROSS $CROSS_FLAGS" && echo "[+] unsigaction ready"
echo "[+] Building libqasan ..."
make -C libqasan CC=$CROSS && echo "[+] unsigaction ready"
make -C libqasan CC="$CROSS $CROSS_FLAGS" && echo "[+] unsigaction ready"
fi
echo "[+] All done for qemu_mode, enjoy!"

View File

@ -51,6 +51,7 @@ ssize_t write(int fd, const void *buf, size_t count) {
void *rtv = __builtin_return_address(0);
QASAN_DEBUG("%14p: write(%d, %p, %zu)\n", rtv, fd, buf, count);
QASAN_LOAD(buf, count);
ssize_t r = __lq_libc_write(fd, buf, count);
QASAN_DEBUG("\t\t = %zd\n", r);
@ -63,6 +64,7 @@ ssize_t read(int fd, void *buf, size_t count) {
void *rtv = __builtin_return_address(0);
QASAN_DEBUG("%14p: read(%d, %p, %zu)\n", rtv, fd, buf, count);
QASAN_STORE(buf, count);
ssize_t r = __lq_libc_read(fd, buf, count);
QASAN_DEBUG("\t\t = %zd\n", r);

View File

@ -159,6 +159,9 @@ size_t __libqasan_malloc_usable_size(void *ptr) {
char *p = ptr;
p -= sizeof(struct chunk_begin);
// Validate that the chunk marker is readable (a crude check
// to verify that ptr is a valid malloc region before we dereference it)
QASAN_LOAD(p, sizeof(struct chunk_begin) - REDZONE_SIZE);
return ((struct chunk_begin *)p)->requested_size;
}
@ -225,6 +228,9 @@ void __libqasan_free(void *ptr) {
struct chunk_begin *p = ptr;
p -= 1;
// Validate that the chunk marker is readable (a crude check
// to verify that ptr is a valid malloc region before we dereference it)
QASAN_LOAD(p, sizeof(struct chunk_begin) - REDZONE_SIZE);
size_t n = p->requested_size;
QASAN_STORE(ptr, n);

View File

@ -212,7 +212,7 @@ static s32 write_to_file(u8 *path, u8 *mem, u32 len) {
unlink(path); /* Ignore errors */
ret = open(path, O_RDWR | O_CREAT | O_EXCL, 0600);
ret = open(path, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (ret < 0) { PFATAL("Unable to create '%s'", path); }
@ -785,6 +785,7 @@ static void set_up_environment(void) {
"abort_on_error=1:"
"detect_leaks=0:"
"allocator_may_return_null=1:"
"detect_odr_violation=0:"
"symbolize=0:"
"handle_segv=0:"
"handle_sigbus=0:"
@ -821,38 +822,7 @@ static void set_up_environment(void) {
if (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);
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
} else {
@ -1078,31 +1048,6 @@ int main(int argc, char **argv_orig, char **envp) {
if (optind == argc || !in_file) { usage(argv[0]); }
if (qemu_mode && getenv("AFL_USE_QASAN")) {
u8 *preload = getenv("AFL_PRELOAD");
u8 *libqasan = get_libqasan_path(argv_orig[0]);
if (!preload) {
setenv("AFL_PRELOAD", libqasan, 0);
} else {
u8 *result = ck_alloc(strlen(libqasan) + strlen(preload) + 2);
strcpy(result, libqasan);
strcat(result, " ");
strcat(result, preload);
setenv("AFL_PRELOAD", result, 1);
ck_free(result);
}
ck_free(libqasan);
}
map_size = get_map_size();
use_hex_offsets = !!get_afl_env("AFL_ANALYZE_HEX");

View File

@ -280,7 +280,7 @@ static void add_instrumentation(void) {
}
outfd = open(modified_file, O_WRONLY | O_EXCL | O_CREAT, 0600);
outfd = open(modified_file, O_WRONLY | O_EXCL | O_CREAT, DEFAULT_PERMISSION);
if (outfd < 0) { PFATAL("Unable to write to '%s'", modified_file); }

View File

@ -22,7 +22,7 @@
#include "types.h"
#include "debug.h"
#include "alloc-inl.h"
#include "llvm-ngram-coverage.h"
#include "llvm-alternative-coverage.h"
#include <stdio.h>
#include <unistd.h>
@ -50,7 +50,7 @@ static u8 **cc_params; /* Parameters passed to the real CC */
static u32 cc_par_cnt = 1; /* Param count, including argv0 */
static u8 clang_mode; /* Invoked as afl-clang*? */
static u8 llvm_fullpath[PATH_MAX];
static u8 instrument_mode, instrument_opt_mode, ngram_size, lto_mode;
static u8 instrument_mode, instrument_opt_mode, ngram_size, ctx_k, lto_mode;
static u8 compiler_mode, plusplus_mode, have_instr_env = 0;
static u8 have_gcc, have_llvm, have_gcc_plugin, have_lto, have_instr_list = 0;
static u8 * lto_flag = AFL_CLANG_FLTO, *argvnull;
@ -73,7 +73,9 @@ enum {
INSTRUMENT_GCC = 6,
INSTRUMENT_CLANG = 7,
INSTRUMENT_OPT_CTX = 8,
INSTRUMENT_OPT_NGRAM = 16
INSTRUMENT_OPT_NGRAM = 16,
INSTRUMENT_OPT_CALLER = 32,
INSTRUMENT_OPT_CTX_K = 64,
};
@ -88,7 +90,7 @@ char instrument_mode_string[18][18] = {
"GCC",
"CLANG",
"CTX",
"",
"CALLER",
"",
"",
"",
@ -588,6 +590,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
#if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0)
#ifdef __ANDROID__
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
instrument_mode != INSTRUMENT_LLVMNATIVE;
#else
if (have_instr_list) {
@ -597,6 +600,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
"-fsanitize-coverage-allow/denylist, you can use "
"AFL_LLVM_ALLOWLIST/AFL_LLMV_DENYLIST instead.\n");
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
instrument_mode = INSTRUMENT_LLVMNATIVE;
} else {
@ -616,6 +620,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
"Using unoptimized trace-pc-guard, upgrade to llvm 10.0.1+ for "
"enhanced version.\n");
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
instrument_mode = INSTRUMENT_LLVMNATIVE;
#else
FATAL("pcguard instrumentation requires llvm 4.0.1+");
#endif
@ -680,19 +685,49 @@ static void edit_params(u32 argc, char **argv, char **envp) {
/* Detect stray -v calls from ./configure scripts. */
u8 skip_next = 0;
while (--argc) {
u8 *cur = *(++argv);
if (skip_next) {
skip_next = 0;
continue;
}
if (!strncmp(cur, "--afl", 5)) continue;
if (lto_mode && !strncmp(cur, "-fuse-ld=", 9)) continue;
if (lto_mode && !strncmp(cur, "--ld-path=", 10)) continue;
if (!strncmp(cur, "-fno-unroll", 11)) continue;
if (strstr(cur, "afl-compiler-rt") || strstr(cur, "afl-llvm-rt")) continue;
if (!strcmp(cur, "-Wl,-z,defs") || !strcmp(cur, "-Wl,--no-undefined"))
if (!strcmp(cur, "-Wl,-z,defs") || !strcmp(cur, "-Wl,--no-undefined") ||
!strcmp(cur, "--no-undefined")) {
continue;
if (!strncmp(cur, "-fsanitize=fuzzer-", strlen("-fsanitize=fuzzer-")) ||
!strncmp(cur, "-fsanitize-coverage", strlen("-fsanitize-coverage"))) {
}
if (!strcmp(cur, "-z")) {
u8 *param = *(argv + 1);
if (!strcmp(param, "defs")) {
skip_next = 1;
continue;
}
}
if ((!strncmp(cur, "-fsanitize=fuzzer-", strlen("-fsanitize=fuzzer-")) ||
!strncmp(cur, "-fsanitize-coverage", strlen("-fsanitize-coverage"))) &&
(strncmp(cur, "sanitize-coverage-allow",
strlen("sanitize-coverage-allow")) &&
strncmp(cur, "sanitize-coverage-deny",
strlen("sanitize-coverage-deny")) &&
instrument_mode != INSTRUMENT_LLVMNATIVE)) {
if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); }
continue;
@ -938,7 +973,10 @@ static void edit_params(u32 argc, char **argv, char **envp) {
}
if (preprocessor_only) {
// prevent unnecessary build errors
cc_params[cc_par_cnt++] = "-Wno-unused-command-line-argument";
if (preprocessor_only || have_c) {
/* In the preprocessor_only case (-E), we are not actually compiling at
all but requesting the compiler to output preprocessed sources only.
@ -957,18 +995,24 @@ static void edit_params(u32 argc, char **argv, char **envp) {
switch (bit_mode) {
case 0:
cc_params[cc_par_cnt++] =
alloc_printf("%s/afl-compiler-rt.o", obj_path);
if (!shared_linking)
cc_params[cc_par_cnt++] =
alloc_printf("%s/afl-compiler-rt.o", obj_path);
if (lto_mode)
cc_params[cc_par_cnt++] =
alloc_printf("%s/afl-llvm-rt-lto.o", obj_path);
break;
case 32:
cc_params[cc_par_cnt++] =
alloc_printf("%s/afl-compiler-rt-32.o", obj_path);
if (access(cc_params[cc_par_cnt - 1], R_OK))
FATAL("-m32 is not supported by your compiler");
if (!shared_linking) {
cc_params[cc_par_cnt++] =
alloc_printf("%s/afl-compiler-rt-32.o", obj_path);
if (access(cc_params[cc_par_cnt - 1], R_OK))
FATAL("-m32 is not supported by your compiler");
}
if (lto_mode) {
cc_params[cc_par_cnt++] =
@ -981,10 +1025,15 @@ static void edit_params(u32 argc, char **argv, char **envp) {
break;
case 64:
cc_params[cc_par_cnt++] =
alloc_printf("%s/afl-compiler-rt-64.o", obj_path);
if (access(cc_params[cc_par_cnt - 1], R_OK))
FATAL("-m64 is not supported by your compiler");
if (!shared_linking) {
cc_params[cc_par_cnt++] =
alloc_printf("%s/afl-compiler-rt-64.o", obj_path);
if (access(cc_params[cc_par_cnt - 1], R_OK))
FATAL("-m64 is not supported by your compiler");
}
if (lto_mode) {
cc_params[cc_par_cnt++] =
@ -999,20 +1048,17 @@ static void edit_params(u32 argc, char **argv, char **envp) {
}
#if !defined(__APPLE__) && !defined(__sun)
if (!shared_linking && !have_c)
if (!shared_linking)
cc_params[cc_par_cnt++] =
alloc_printf("-Wl,--dynamic-list=%s/dynamic_list.txt", obj_path);
#endif
#if defined(USEMMAP) && !defined(__HAIKU__)
if (!have_c) cc_params[cc_par_cnt++] = "-lrt";
#endif
// prevent unnecessary build errors
cc_params[cc_par_cnt++] = "-Wno-unused-command-line-argument";
}
#if defined(USEMMAP) && !defined(__HAIKU__)
cc_params[cc_par_cnt++] = "-lrt";
#endif
#endif
cc_params[cc_par_cnt] = NULL;
@ -1023,7 +1069,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
int main(int argc, char **argv, char **envp) {
int i;
int i, passthrough = 0;
char *callname = argv[0], *ptr = NULL;
if (getenv("AFL_DEBUG")) {
@ -1043,6 +1089,13 @@ int main(int argc, char **argv, char **envp) {
}
if (getenv("AFL_PASSTHROUGH") || getenv("AFL_NOOPT")) {
passthrough = 1;
if (!debug) { be_quiet = 1; }
}
if ((ptr = strrchr(callname, '/')) != NULL) callname = ptr + 1;
argvnull = (u8 *)argv[0];
check_environment_vars(envp);
@ -1211,6 +1264,7 @@ int main(int argc, char **argv, char **envp) {
} else if (strcasecmp(ptr, "LLVMNATIVE") == 0 ||
strcasecmp(ptr, "NATIVE") == 0 ||
strcasecmp(ptr, "LLVM-NATIVE") == 0) {
compiler_mode = LLVM;
@ -1273,6 +1327,7 @@ int main(int argc, char **argv, char **envp) {
}
if (getenv("AFL_LLVM_CTX")) instrument_opt_mode |= INSTRUMENT_OPT_CTX;
if (getenv("AFL_LLVM_CALLER")) instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
if (getenv("AFL_LLVM_NGRAM_SIZE")) {
@ -1286,6 +1341,26 @@ int main(int argc, char **argv, char **envp) {
}
if (getenv("AFL_LLVM_CTX_K")) {
ctx_k = atoi(getenv("AFL_LLVM_CTX_K"));
if (ctx_k < 1 || ctx_k > CTX_MAX_K)
FATAL("K-CTX instrumentation mode must be between 1 and CTX_MAX_K (%u)",
CTX_MAX_K);
if (ctx_k == 1) {
setenv("AFL_LLVM_CALLER", "1", 1);
unsetenv("AFL_LLVM_CTX_K");
instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
} else {
instrument_opt_mode |= INSTRUMENT_OPT_CTX_K;
}
}
if (getenv("AFL_LLVM_INSTRUMENT")) {
u8 *ptr2 = strtok(getenv("AFL_LLVM_INSTRUMENT"), ":,;");
@ -1381,6 +1456,44 @@ int main(int argc, char **argv, char **envp) {
}
if (strncasecmp(ptr2, "ctx-", strlen("ctx-")) == 0) {
u8 *ptr3 = ptr2 + strlen("ctx-");
while (*ptr3 && (*ptr3 < '0' || *ptr3 > '9'))
ptr3++;
if (!*ptr3) {
if ((ptr3 = getenv("AFL_LLVM_CTX_K")) == NULL)
FATAL(
"you must set the K-CTX K with (e.g. for value 2) "
"AFL_LLVM_INSTRUMENT=ctx-2");
}
ctx_k = atoi(ptr3);
if (ctx_k < 1 || ctx_k > CTX_MAX_K)
FATAL(
"K-CTX instrumentation option must be between 1 and CTX_MAX_K "
"(%u)",
CTX_MAX_K);
if (ctx_k == 1) {
instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
setenv("AFL_LLVM_CALLER", "1", 1);
unsetenv("AFL_LLVM_CTX_K");
} else {
instrument_opt_mode |= (INSTRUMENT_OPT_CTX_K);
u8 *ptr4 = alloc_printf("%u", ctx_k);
setenv("AFL_LLVM_CTX_K", ptr4, 1);
}
}
if (strncasecmp(ptr2, "ctx", strlen("ctx")) == 0) {
instrument_opt_mode |= INSTRUMENT_OPT_CTX;
@ -1388,6 +1501,13 @@ int main(int argc, char **argv, char **envp) {
}
if (strncasecmp(ptr2, "caller", strlen("caller")) == 0) {
instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
setenv("AFL_LLVM_CALLER", "1", 1);
}
if (strncasecmp(ptr2, "ngram", strlen("ngram")) == 0) {
u8 *ptr3 = ptr2 + strlen("ngram");
@ -1421,6 +1541,27 @@ int main(int argc, char **argv, char **envp) {
}
if ((instrument_opt_mode & INSTRUMENT_OPT_CTX) &&
(instrument_opt_mode & INSTRUMENT_OPT_CALLER)) {
FATAL("you cannot set CTX and CALLER together");
}
if ((instrument_opt_mode & INSTRUMENT_OPT_CTX) &&
(instrument_opt_mode & INSTRUMENT_OPT_CTX_K)) {
FATAL("you cannot set CTX and K-CTX together");
}
if ((instrument_opt_mode & INSTRUMENT_OPT_CALLER) &&
(instrument_opt_mode & INSTRUMENT_OPT_CTX_K)) {
FATAL("you cannot set CALLER and K-CTX together");
}
if (instrument_opt_mode && instrument_mode == INSTRUMENT_DEFAULT &&
(compiler_mode == LLVM || compiler_mode == UNSET)) {
@ -1498,12 +1639,13 @@ int main(int argc, char **argv, char **envp) {
" CLASSIC %s no yes module yes yes "
"yes\n"
" - NORMAL\n"
" - CALLER\n"
" - CTX\n"
" - NGRAM-{2-16}\n"
" INSTRIM no yes module yes yes "
" yes\n"
" - NORMAL\n"
" - CTX\n"
" - CALLER\n"
" - NGRAM-{2-16}\n"
" [GCC_PLUGIN] gcc plugin: %s%s\n"
" CLASSIC DEFAULT no yes no no no "
@ -1535,8 +1677,8 @@ int main(int argc, char **argv, char **envp) {
"of afl-cc.\n\n");
#if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0)
#define NATIVE_MSG \
" NATIVE: use llvm's native PCGUARD instrumentation (less " \
#define NATIVE_MSG \
" LLVM-NATIVE: use llvm's native PCGUARD instrumentation (less " \
"performant)\n"
#else
#define NATIVE_MSG ""
@ -1550,7 +1692,10 @@ int main(int argc, char **argv, char **envp) {
NATIVE_MSG
" CLASSIC: decision target instrumentation (README.llvm.md)\n"
" CTX: CLASSIC + callee context (instrumentation/README.ctx.md)\n"
" CALLER: CLASSIC + single callee context "
"(instrumentation/README.ctx.md)\n"
" CTX: CLASSIC + full callee context "
"(instrumentation/README.ctx.md)\n"
" NGRAM-x: CLASSIC + previous path "
"((instrumentation/README.ngram.md)\n"
" INSTRIM: Dominator tree (for LLVM <= 6.0) "
@ -1593,6 +1738,8 @@ int main(int argc, char **argv, char **envp) {
" AFL_DONT_OPTIMIZE: disable optimization instead of -O3\n"
" AFL_NO_BUILTIN: no builtins for string compare functions (for "
"libtokencap.so)\n"
" AFL_NOOP: behave like a normal compiler (to pass configure "
"tests)\n"
" AFL_PATH: path to instrumenting pass and runtime "
"(afl-compiler-rt.*o)\n"
" AFL_IGNORE_UNKNOWN_ENVS: don't warn on unknown env vars\n"
@ -1644,15 +1791,17 @@ int main(int argc, char **argv, char **envp) {
" AFL_LLVM_CMPLOG: log operands of comparisons (RedQueen "
"mutator)\n"
" AFL_LLVM_INSTRUMENT: set instrumentation mode:\n"
" CLASSIC, INSTRIM, PCGUARD, LTO, GCC, CLANG, CTX, NGRAM-2 ... "
"NGRAM-16\n"
" CLASSIC, INSTRIM, PCGUARD, LTO, GCC, CLANG, CALLER, CTX, "
"NGRAM-2 ..-16\n"
" You can also use the old environment variables instead:\n"
" AFL_LLVM_USE_TRACE_PC: use LLVM trace-pc-guard instrumentation\n"
" AFL_LLVM_INSTRIM: use light weight instrumentation InsTrim\n"
" AFL_LLVM_INSTRIM_LOOPHEAD: optimize loop tracing for speed "
"(option to INSTRIM)\n"
" AFL_LLVM_CTX: use context sensitive coverage (for CLASSIC and "
"INSTRIM)\n"
" AFL_LLVM_CALLER: use single context sensitive coverage (for "
"CLASSIC)\n"
" AFL_LLVM_CTX: use full context sensitive coverage (for "
"CLASSIC)\n"
" AFL_LLVM_NGRAM_SIZE: use ngram prev_loc count coverage (for "
"CLASSIC & INSTRIM)\n");
@ -1770,7 +1919,7 @@ int main(int argc, char **argv, char **envp) {
}
if (instrument_opt_mode && compiler_mode != LLVM)
FATAL("CTX and NGRAM can only be used in LLVM mode");
FATAL("CTX, CALLER and NGRAM can only be used in LLVM mode");
if (!instrument_opt_mode) {
@ -1780,15 +1929,18 @@ int main(int argc, char **argv, char **envp) {
} else {
if (instrument_opt_mode == INSTRUMENT_OPT_CTX)
char *ptr2 = alloc_printf(" + NGRAM-%u", ngram_size);
char *ptr3 = alloc_printf(" + K-CTX-%u", ctx_k);
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);
ptr = alloc_printf(
"%s%s%s%s%s", instrument_mode_string[instrument_mode],
(instrument_opt_mode & INSTRUMENT_OPT_CTX) ? " + CTX" : "",
(instrument_opt_mode & INSTRUMENT_OPT_CALLER) ? " + CALLER" : "",
(instrument_opt_mode & INSTRUMENT_OPT_NGRAM) ? ptr2 : "",
(instrument_opt_mode & INSTRUMENT_OPT_CTX_K) ? ptr3 : "");
ck_free(ptr2);
ck_free(ptr3);
}
@ -1799,11 +1951,14 @@ int main(int argc, char **argv, char **envp) {
"(requires LLVM 11 or higher)");
#endif
if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC &&
instrument_mode != INSTRUMENT_CFG)
if (instrument_opt_mode && instrument_mode == INSTRUMENT_CFG &&
instrument_opt_mode & INSTRUMENT_OPT_CTX)
FATAL("CFG instrumentation mode supports NGRAM and CALLER, but not CTX.");
else if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC)
// we will drop CFG/INSTRIM in the future so do not advertise
FATAL(
"CTX and NGRAM instrumentation options can only be used with LLVM and "
"CFG or CLASSIC instrumentation modes!");
"CALLER, CTX and NGRAM instrumentation options can only be used with "
"the LLVM CLASSIC instrumentation mode.");
if (getenv("AFL_LLVM_SKIP_NEVERZERO") && getenv("AFL_LLVM_NOT_ZERO"))
FATAL(
@ -1897,7 +2052,16 @@ int main(int argc, char **argv, char **envp) {
}
execvp(cc_params[0], (char **)cc_params);
if (passthrough) {
argv[0] = cc_params[0];
execvp(cc_params[0], (char **)argv);
} else {
execvp(cc_params[0], (char **)cc_params);
}
FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]);

View File

@ -149,9 +149,14 @@ void argv_cpy_free(char **argv) {
char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
if (!unlikely(own_loc)) { FATAL("BUG: param own_loc is NULL"); }
if (unlikely(getenv("AFL_QEMU_CUSTOM_BIN"))) {
u8 *tmp, *cp = NULL, *rsl, *own_copy;
WARNF(
"AFL_QEMU_CUSTOM_BIN is enabled. "
"You must run your target under afl-qemu-trace on your own!");
return argv;
}
char **new_argv = ck_alloc(sizeof(char *) * (argc + 4));
if (unlikely(!new_argv)) { FATAL("Illegal amount of arguments specified"); }
@ -164,70 +169,8 @@ char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
/* Now we need to actually find the QEMU binary to put in argv[0]. */
tmp = getenv("AFL_PATH");
if (tmp) {
cp = alloc_printf("%s/afl-qemu-trace", tmp);
if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); }
*target_path_p = new_argv[0] = cp;
return new_argv;
}
own_copy = ck_strdup(own_loc);
rsl = strrchr(own_copy, '/');
if (rsl) {
*rsl = 0;
cp = alloc_printf("%s/afl-qemu-trace", own_copy);
ck_free(own_copy);
if (!access(cp, X_OK)) {
*target_path_p = new_argv[0] = cp;
return new_argv;
}
} else {
ck_free(own_copy);
}
if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) {
if (cp) { ck_free(cp); }
*target_path_p = new_argv[0] = ck_strdup(BIN_PATH "/afl-qemu-trace");
return new_argv;
}
SAYF("\n" cLRD "[-] " cRST
"Oops, unable to find the 'afl-qemu-trace' binary. The binary must be "
"built\n"
" separately by following the instructions in "
"qemu_mode/README.md. "
"If you\n"
" already have the binary installed, you may need to specify "
"AFL_PATH in the\n"
" environment.\n\n"
" Of course, even without QEMU, afl-fuzz can still work with "
"binaries that are\n"
" instrumented at compile time with afl-gcc. It is also possible to "
"use it as a\n"
" traditional non-instrumented fuzzer by specifying '-n' in the "
"command "
"line.\n");
FATAL("Failed to locate 'afl-qemu-trace'.");
*target_path_p = new_argv[0] = find_afl_binary(own_loc, "afl-qemu-trace");
return new_argv;
}
@ -235,10 +178,6 @@ char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
if (!unlikely(own_loc)) { FATAL("BUG: param own_loc is NULL"); }
u8 *tmp, *cp = NULL, *rsl, *own_copy;
char **new_argv = ck_alloc(sizeof(char *) * (argc + 3));
if (unlikely(!new_argv)) { FATAL("Illegal amount of arguments specified"); }
@ -249,152 +188,10 @@ char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
/* Now we need to actually find the QEMU binary to put in argv[0]. */
tmp = getenv("AFL_PATH");
if (tmp) {
cp = alloc_printf("%s/afl-qemu-trace", 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); }
*target_path_p = new_argv[0] = cp;
return new_argv;
}
own_copy = ck_strdup(own_loc);
rsl = strrchr(own_copy, '/');
if (rsl) {
*rsl = 0;
cp = alloc_printf("%s/afl-qemu-trace", own_copy);
if (cp && !access(cp, X_OK)) {
ck_free(cp);
cp = alloc_printf("%s/afl-wine-trace", own_copy);
if (!access(cp, X_OK)) {
*target_path_p = new_argv[0] = cp;
return new_argv;
}
}
ck_free(own_copy);
} else {
ck_free(own_copy);
}
u8 *ncp = BIN_PATH "/afl-qemu-trace";
if (!access(ncp, X_OK)) {
ncp = BIN_PATH "/afl-wine-trace";
if (!access(ncp, X_OK)) {
*target_path_p = new_argv[0] = ck_strdup(ncp);
return new_argv;
}
}
SAYF("\n" cLRD "[-] " cRST
"Oops, unable to find the '%s' binary. The binary must be "
"built\n"
" separately by following the instructions in "
"qemu_mode/README.md. "
"If you\n"
" already have the binary installed, you may need to specify "
"AFL_PATH in the\n"
" environment.\n\n"
" Of course, even without QEMU, afl-fuzz can still work with "
"binaries that are\n"
" instrumented at compile time with afl-gcc. It is also possible to "
"use it as a\n"
" traditional non-instrumented fuzzer by specifying '-n' in the "
"command "
"line.\n",
ncp);
FATAL("Failed to locate '%s'.", ncp);
}
/* Get libqasan path. */
u8 *get_libqasan_path(u8 *own_loc) {
if (!unlikely(own_loc)) { FATAL("BUG: param own_loc is NULL"); }
u8 *tmp, *cp = NULL, *rsl, *own_copy;
tmp = getenv("AFL_PATH");
if (tmp) {
cp = alloc_printf("%s/libqasan.so", tmp);
if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); }
return cp;
}
own_copy = ck_strdup(own_loc);
rsl = strrchr(own_copy, '/');
if (rsl) {
*rsl = 0;
cp = alloc_printf("%s/libqasan.so", own_copy);
ck_free(own_copy);
if (!access(cp, X_OK)) { return cp; }
} else {
ck_free(own_copy);
}
if (!access(AFL_PATH "/libqasan.so", X_OK)) {
if (cp) { ck_free(cp); }
return ck_strdup(AFL_PATH "/libqasan.so");
}
SAYF("\n" cLRD "[-] " cRST
"Oops, unable to find the 'libqasan.so' binary. The binary must be "
"built\n"
" separately by following the instructions in "
"qemu_mode/libqasan/README.md. "
"If you\n"
" already have the binary installed, you may need to specify "
"AFL_PATH in the\n"
" environment.\n");
FATAL("Failed to locate 'libqasan.so'.");
u8 *tmp = find_afl_binary(own_loc, "afl-qemu-trace");
ck_free(tmp);
*target_path_p = new_argv[0] = find_afl_binary(own_loc, "afl-wine-trace");
return new_argv;
}
@ -488,6 +285,70 @@ u8 *find_binary(u8 *fname) {
}
u8 *find_afl_binary(u8 *own_loc, u8 *fname) {
u8 *afl_path = NULL, *target_path, *own_copy;
if ((afl_path = getenv("AFL_PATH"))) {
target_path = alloc_printf("%s/%s", afl_path, fname);
if (!access(target_path, X_OK)) {
return target_path;
} else {
ck_free(target_path);
}
}
if (own_loc) {
own_copy = ck_strdup(own_loc);
u8 *rsl = strrchr(own_copy, '/');
if (rsl) {
*rsl = 0;
target_path = alloc_printf("%s/%s", own_copy, fname);
ck_free(own_copy);
if (!access(target_path, X_OK)) {
return target_path;
} else {
ck_free(target_path);
}
} else {
ck_free(own_copy);
}
}
target_path = alloc_printf("%s/%s", BIN_PATH, fname);
if (!access(target_path, X_OK)) {
return target_path;
} else {
ck_free(target_path);
}
return find_binary(fname);
}
/* Parses the kill signal environment variable, FATALs on error.
If the env is not set, sets the env to default_signal for the signal handlers
and returns the default_signal. */
@ -682,6 +543,7 @@ void check_environment_vars(char **envp) {
env[strlen(afl_environment_variables[i])] == '=') {
match = 1;
if ((val = getenv(afl_environment_variables[i])) && !*val) {
WARNF(
@ -756,6 +618,98 @@ char *get_afl_env(char *env) {
}
bool extract_and_set_env(u8 *env_str) {
if (!env_str) { return false; }
bool ret = false; // return false by default
u8 *p = ck_strdup(env_str);
u8 *end = p + strlen((char *)p);
u8 *rest = p;
u8 closing_sym = ' ';
u8 c;
size_t num_pairs = 0;
while (rest < end) {
while (*rest == ' ') {
rest++;
}
if (rest + 1 >= end) break;
u8 *key = rest;
// env variable names may not start with numbers or '='
if (*key == '=' || (*key >= '0' && *key <= '9')) { goto free_and_return; }
while (rest < end && *rest != '=' && *rest != ' ') {
c = *rest;
// lowercase is bad but we may still allow it
if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') &&
(c < '0' || c > '9') && c != '_') {
goto free_and_return;
}
rest++;
}
if (*rest != '=') { goto free_and_return; }
*rest = '\0'; // done with variable name
rest += 1;
if (rest >= end || *rest == ' ') { goto free_and_return; }
u8 *val = rest;
if (*val == '\'' || *val == '"') {
closing_sym = *val;
val += 1;
rest += 1;
if (rest >= end) { goto free_and_return; }
} else {
closing_sym = ' ';
}
while (rest < end && *rest != closing_sym) {
rest++;
}
if (closing_sym != ' ' && *rest != closing_sym) { goto free_and_return; }
*rest = '\0'; // done with variable value
rest += 1;
if (rest < end && *rest != ' ') { goto free_and_return; }
num_pairs++;
setenv(key, val, 1);
}
if (num_pairs) { ret = true; }
free_and_return:
ck_free(p);
return ret;
}
/* Read mask bitmap from file. This is for the -B option. */
void read_bitmap(u8 *fname, u8 *map, size_t len) {
@ -1122,7 +1076,7 @@ u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms) {
/* Reads the map size from ENV */
u32 get_map_size(void) {
uint32_t map_size = (MAP_SIZE << 2); // needed for target ctors :(
uint32_t map_size = DEFAULT_SHMEM_SIZE;
char * ptr;
if ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE"))) {
@ -1130,7 +1084,7 @@ u32 get_map_size(void) {
map_size = atoi(ptr);
if (!map_size || map_size > (1 << 29)) {
FATAL("illegal AFL_MAP_SIZE %u, must be between %u and %u", map_size, 32U,
FATAL("illegal AFL_MAP_SIZE %u, must be between %u and %u", map_size, 64U,
1U << 29);
}
@ -1150,7 +1104,7 @@ FILE *create_ffile(u8 *fn) {
s32 fd;
FILE *f;
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
@ -1168,7 +1122,7 @@ s32 create_file(u8 *fn) {
s32 fd;
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }

View File

@ -481,27 +481,28 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
/* 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", 1); }
/* Set sane defaults for ASAN if nothing else specified. */
if (fsrv->debug == true && !getenv("ASAN_OPTIONS"))
if (!getenv("ASAN_OPTIONS"))
setenv("ASAN_OPTIONS",
"abort_on_error=1:"
"detect_leaks=0:"
"malloc_context_size=0:"
"symbolize=0:"
"allocator_may_return_null=1:"
"detect_odr_violation=0:"
"handle_segv=0:"
"handle_sigbus=0:"
"handle_abort=0:"
"handle_sigfpe=0:"
"handle_sigill=0",
0);
1);
/* Set sane defaults for UBSAN if nothing else specified. */
if (fsrv->debug == true && !getenv("UBSAN_OPTIONS"))
if (!getenv("UBSAN_OPTIONS"))
setenv("UBSAN_OPTIONS",
"halt_on_error=1:"
"abort_on_error=1:"
@ -513,7 +514,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
"handle_abort=0:"
"handle_sigfpe=0:"
"handle_sigill=0",
0);
1);
/* Envs for QASan */
setenv("QASAN_MAX_CALL_STACK", "0", 0);
@ -522,7 +523,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
/* MSAN is tricky, because it doesn't support abort_on_error=1 at this
point. So, we do this in a very hacky way. */
if (fsrv->debug == true && !getenv("MSAN_OPTIONS"))
if (!getenv("MSAN_OPTIONS"))
setenv("MSAN_OPTIONS",
"exit_code=" STRINGIFY(MSAN_ERROR) ":"
"symbolize=0:"
@ -535,7 +536,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
"handle_abort=0:"
"handle_sigfpe=0:"
"handle_sigill=0",
0);
1);
fsrv->init_child_func(fsrv, argv);
@ -808,7 +809,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
"have a\n"
" restrictive memory limit configured, this is expected; please "
"read\n"
" %s/notes_for_asan.md for help.\n",
" %s/notes_for_asan.md for help and run with '-m 0'.\n",
doc_path);
} else if (!fsrv->mem_limit) {
@ -816,18 +817,21 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
SAYF("\n" cLRD "[-] " cRST
"Whoops, the target binary crashed suddenly, "
"before receiving any input\n"
" from the fuzzer! There are several probable explanations:\n\n"
" from the fuzzer! You can try the following:\n\n"
" - The target binary requires a large map and crashes before "
"reporting.\n"
" Set a high value (e.g. AFL_MAP_SIZE=1024000) or use "
"AFL_DEBUG=1 to see the\n"
" message from the target binary\n\n"
" - The target binary crashes because necessary runtime "
"conditions it needs\n"
" are not met. Try to:\n"
" 1. Run again with AFL_DEBUG=1 set and check the output of "
"the target\n"
" binary for clues.\n"
" 2. Run again with AFL_DEBUG=1 and 'ulimit -c unlimited' and "
"analyze the\n"
" generated core dump.\n\n"
" - The binary is just buggy and explodes entirely on its own. "
"If so, you\n"
" need to fix the underlying problem or find a better "
"replacement.\n\n"
" - Possibly the target requires a huge coverage map and has "
"CTORS.\n"
" Retry with setting AFL_MAP_SIZE=10000000.\n\n"
MSG_FORK_ON_APPLE
@ -843,13 +847,17 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
SAYF("\n" cLRD "[-] " cRST
"Whoops, the target binary crashed suddenly, "
"before receiving any input\n"
" from the fuzzer! There are several probable explanations:\n\n"
" from the fuzzer! You can try the following:\n\n"
" - The target binary requires a large map and crashes before "
"reporting.\n"
" Set a high value (e.g. AFL_MAP_SIZE=1024000) or use "
"AFL_DEBUG=1 to see the\n"
" message from the target binary\n\n"
" - The target binary crashes because necessary runtime "
"conditions it needs\n"
" are not met. Try to:\n"
" 1. Run again with AFL_DEBUG=1 set and check the output of "
"the target\n"
" binary for clues.\n"
" 2. Run again with AFL_DEBUG=1 and 'ulimit -c unlimited' and "
"analyze the\n"
" generated core dump.\n\n"
" - The current memory limit (%s) is too restrictive, causing "
"the\n"
@ -867,13 +875,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
" estimate the required amount of virtual memory for the "
"binary.\n\n"
" - The binary is just buggy and explodes entirely on its own. "
"If so, you\n"
" need to fix the underlying problem or find a better "
"replacement.\n\n"
MSG_FORK_ON_APPLE
" - Possibly the target requires a huge coverage map and has "
"CTORS.\n"
" Retry with setting AFL_MAP_SIZE=10000000.\n\n"
" - Less likely, there is a horrible bug in the fuzzer. If other "
"options\n"
" fail, poke <afl-users@googlegroups.com> for troubleshooting "
@ -902,16 +909,30 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
"with ASAN and\n"
" you have a restrictive memory limit configured, this is "
"expected; please\n"
" read %s/notes_for_asan.md for help.\n",
" read %s/notes_for_asan.md for help and run with '-m 0'.\n",
doc_path);
} else if (!fsrv->mem_limit) {
SAYF("\n" cLRD "[-] " cRST
"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 and AFL_LLVM_MAP_ADDR"
" then recompiling without this parameter.\n"
"Hmm, looks like the target binary terminated before we could complete"
" a\n"
"handshake with the injected code. You can try the following:\n\n"
" - The target binary crashes because necessary runtime conditions "
"it needs\n"
" are not met. Try to:\n"
" 1. Run again with AFL_DEBUG=1 set and check the output of the "
"target\n"
" binary for clues.\n"
" 2. Run again with AFL_DEBUG=1 and 'ulimit -c unlimited' and "
"analyze the\n"
" generated core dump.\n\n"
" - Possibly the target requires a huge coverage map and has "
"CTORS.\n"
" Retry with setting AFL_MAP_SIZE=10000000.\n\n"
"Otherwise there is a horrible bug in the fuzzer.\n"
"Poke <afl-users@googlegroups.com> for troubleshooting tips.\n");
@ -923,10 +944,24 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
"\n" cLRD "[-] " cRST
"Hmm, looks like the target binary terminated "
"before we could complete a\n"
" handshake with the injected code. There are %s probable "
"explanations:\n\n"
" handshake with the injected code. You can try the following:\n\n"
"%s"
" - The target binary crashes because necessary runtime conditions "
"it needs\n"
" are not met. Try to:\n"
" 1. Run again with AFL_DEBUG=1 set and check the output of the "
"target\n"
" binary for clues.\n"
" 2. Run again with AFL_DEBUG=1 and 'ulimit -c unlimited' and "
"analyze the\n"
" generated core dump.\n\n"
" - Possibly the target requires a huge coverage map and has "
"CTORS.\n"
" Retry with setting AFL_MAP_SIZE=10000000.\n\n"
" - The current memory limit (%s) is too restrictive, causing an "
"OOM\n"
" fault in the dynamic linker. This can be fixed with the -m "
@ -950,7 +985,6 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
"options\n"
" fail, poke <afl-users@googlegroups.com> for troubleshooting "
"tips.\n",
getenv(DEFER_ENV_VAR) ? "three" : "two",
getenv(DEFER_ENV_VAR)
? " - You are using deferred forkserver, but __AFL_INIT() is "
"never\n"
@ -1030,12 +1064,14 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) {
if (unlikely(fsrv->no_unlink)) {
fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_TRUNC,
DEFAULT_PERMISSION);
} else {
unlink(fsrv->out_file); /* Ignore errors. */
fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_EXCL,
DEFAULT_PERMISSION);
}

View File

@ -42,7 +42,7 @@ void write_bitmap(afl_state_t *afl) {
afl->bitmap_changed = 0;
snprintf(fname, PATH_MAX, "%s/fuzz_bitmap", afl->out_dir);
fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to open '%s'", fname); }
@ -407,7 +407,7 @@ static void write_crash_readme(afl_state_t *afl) {
sprintf(fn, "%s/crashes/README.txt", afl->out_dir);
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600);
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
/* Do not die on errors here - that would be impolite. */
@ -509,7 +509,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
alloc_printf("%s/queue/id_%06u", afl->out_dir, afl->queued_paths);
#endif /* ^!SIMPLE_FILES */
fd = open(queue_fn, O_WRONLY | O_CREAT | O_EXCL, 0600);
fd = open(queue_fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", queue_fn); }
ck_write(fd, mem, len, queue_fn);
close(fd);
@ -783,7 +783,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
/* If we're here, we apparently want to save the crash or hang
test case, too. */
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600);
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", fn); }
ck_write(fd, mem, len, fn);
close(fd);

View File

@ -387,6 +387,130 @@ static inline u8 memcmp_nocase(u8 *m1, u8 *m2, u32 len) {
}
/* add an extra/dict/token - no checks performed, no sorting */
static void add_extra_nocheck(afl_state_t *afl, u8 *mem, u32 len) {
afl->extras = afl_realloc((void **)&afl->extras,
(afl->extras_cnt + 1) * sizeof(struct extra_data));
if (unlikely(!afl->extras)) { PFATAL("alloc"); }
afl->extras[afl->extras_cnt].data = ck_alloc(len);
afl->extras[afl->extras_cnt].len = len;
memcpy(afl->extras[afl->extras_cnt].data, mem, len);
afl->extras_cnt++;
/* We only want to print this once */
if (afl->extras_cnt == afl->max_det_extras + 1) {
WARNF("More than %u tokens - will use them probabilistically.",
afl->max_det_extras);
}
}
/* Sometimes strings in input is transformed to unicode internally, so for
fuzzing we should attempt to de-unicode if it looks like simple unicode */
void deunicode_extras(afl_state_t *afl) {
if (!afl->extras_cnt) return;
u32 i, j, orig_cnt = afl->extras_cnt;
u8 buf[64];
for (i = 0; i < orig_cnt; ++i) {
if (afl->extras[i].len < 6 || afl->extras[i].len > 64 ||
afl->extras[i].len % 2) {
continue;
}
u32 k = 0, z1 = 0, z2 = 0, z3 = 0, z4 = 0, half = afl->extras[i].len >> 1;
u32 quarter = half >> 1;
for (j = 0; j < afl->extras[i].len; ++j) {
switch (j % 4) {
case 2:
if (!afl->extras[i].data[j]) { ++z3; }
// fall through
case 0:
if (!afl->extras[i].data[j]) { ++z1; }
break;
case 3:
if (!afl->extras[i].data[j]) { ++z4; }
// fall through
case 1:
if (!afl->extras[i].data[j]) { ++z2; }
break;
}
}
if ((z1 < half && z2 < half) || z1 + z2 == afl->extras[i].len) { continue; }
// also maybe 32 bit unicode?
if (afl->extras[i].len % 4 == 0 && afl->extras[i].len >= 12 &&
(z3 == quarter || z4 == quarter) && z1 + z2 == quarter * 3) {
for (j = 0; j < afl->extras[i].len; ++j) {
if (z4 < quarter) {
if (j % 4 == 3) { buf[k++] = afl->extras[i].data[j]; }
} else if (z3 < quarter) {
if (j % 4 == 2) { buf[k++] = afl->extras[i].data[j]; }
} else if (z2 < half) {
if (j % 4 == 1) { buf[k++] = afl->extras[i].data[j]; }
} else {
if (j % 4 == 0) { buf[k++] = afl->extras[i].data[j]; }
}
}
add_extra_nocheck(afl, buf, k);
k = 0;
}
for (j = 0; j < afl->extras[i].len; ++j) {
if (z1 < half) {
if (j % 2 == 0) { buf[k++] = afl->extras[i].data[j]; }
} else {
if (j % 2 == 1) { buf[k++] = afl->extras[i].data[j]; }
}
}
add_extra_nocheck(afl, buf, k);
}
qsort(afl->extras, afl->extras_cnt, sizeof(struct extra_data),
compare_extras_len);
}
/* Removes duplicates from the loaded extras. This can happen if multiple files
are loaded */
@ -396,9 +520,9 @@ void dedup_extras(afl_state_t *afl) {
u32 i, j, orig_cnt = afl->extras_cnt;
for (i = 0; i < afl->extras_cnt - 1; i++) {
for (i = 0; i < afl->extras_cnt - 1; ++i) {
for (j = i + 1; j < afl->extras_cnt; j++) {
for (j = i + 1; j < afl->extras_cnt; ++j) {
restart_dedup:
@ -462,30 +586,11 @@ void add_extra(afl_state_t *afl, u8 *mem, u32 len) {
}
afl->extras = afl_realloc((void **)&afl->extras,
(afl->extras_cnt + 1) * sizeof(struct extra_data));
if (unlikely(!afl->extras)) { PFATAL("alloc"); }
afl->extras[afl->extras_cnt].data = ck_alloc(len);
afl->extras[afl->extras_cnt].len = len;
memcpy(afl->extras[afl->extras_cnt].data, mem, len);
afl->extras_cnt++;
add_extra_nocheck(afl, mem, len);
qsort(afl->extras, afl->extras_cnt, sizeof(struct extra_data),
compare_extras_len);
/* We only want to print this once */
if (afl->extras_cnt == afl->max_det_extras + 1) {
WARNF("More than %u tokens - will use them probabilistically.",
afl->max_det_extras);
}
}
/* Maybe add automatic extra. */
@ -626,7 +731,7 @@ void save_auto(afl_state_t *afl) {
alloc_printf("%s/queue/.state/auto_extras/auto_%06u", afl->out_dir, i);
s32 fd;
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }

View File

@ -152,7 +152,8 @@ void bind_to_free_cpu(afl_state_t *afl) {
do {
if ((lockfd = open(lockfile, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0) {
if ((lockfd = open(lockfile, O_RDWR | O_CREAT | O_EXCL,
DEFAULT_PERMISSION)) < 0) {
if (first) {
@ -828,7 +829,7 @@ void perform_dry_run(afl_state_t *afl) {
for (idx = 0; idx < afl->queued_paths; idx++) {
q = afl->queue_buf[idx];
if (unlikely(q->disabled)) { continue; }
if (unlikely(!q || q->disabled)) { continue; }
u8 res;
s32 fd;
@ -1069,7 +1070,7 @@ void perform_dry_run(afl_state_t *afl) {
}
afl->max_depth = 0;
for (i = 0; i < afl->queued_paths; i++) {
for (i = 0; i < afl->queued_paths && likely(afl->queue_buf[i]); i++) {
if (!afl->queue_buf[i]->disabled &&
afl->queue_buf[i]->depth > afl->max_depth)
@ -1136,10 +1137,11 @@ void perform_dry_run(afl_state_t *afl) {
for (idx = 0; idx < afl->queued_paths; idx++) {
q = afl->queue_buf[idx];
if (q->disabled || q->cal_failed || !q->exec_cksum) { continue; }
if (!q || q->disabled || q->cal_failed || !q->exec_cksum) { continue; }
u32 done = 0;
for (i = idx + 1; i < afl->queued_paths && !done; i++) {
for (i = idx + 1;
i < afl->queued_paths && !done && likely(afl->queue_buf[i]); i++) {
struct queue_entry *p = afl->queue_buf[i];
if (p->disabled || p->cal_failed || !p->exec_cksum) { continue; }
@ -1191,7 +1193,7 @@ void perform_dry_run(afl_state_t *afl) {
for (idx = 0; idx < afl->queued_paths; idx++) {
if (!afl->queue_buf[idx]->disabled &&
if (afl->queue_buf[idx] && !afl->queue_buf[idx]->disabled &&
afl->queue_buf[idx]->depth > afl->max_depth)
afl->max_depth = afl->queue_buf[idx]->depth;
@ -1218,7 +1220,7 @@ static void link_or_copy(u8 *old_path, u8 *new_path) {
sfd = open(old_path, O_RDONLY);
if (sfd < 0) { PFATAL("Unable to open '%s'", old_path); }
dfd = open(new_path, O_WRONLY | O_CREAT | O_EXCL, 0600);
dfd = open(new_path, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (dfd < 0) { PFATAL("Unable to create '%s'", new_path); }
tmp = ck_alloc(64 * 1024);
@ -1247,7 +1249,7 @@ void pivot_inputs(afl_state_t *afl) {
ACTF("Creating hard links for all input files...");
for (i = 0; i < afl->queued_paths; i++) {
for (i = 0; i < afl->queued_paths && likely(afl->queue_buf[i]); i++) {
q = afl->queue_buf[i];
@ -1811,9 +1813,13 @@ static void handle_existing_out_dir(afl_state_t *afl) {
}
fn = alloc_printf("%s/plot_data", afl->out_dir);
if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
ck_free(fn);
if (!afl->in_place_resume) {
fn = alloc_printf("%s/plot_data", afl->out_dir);
if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
ck_free(fn);
}
fn = alloc_printf("%s/cmdline", afl->out_dir);
if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
@ -2007,17 +2013,35 @@ void setup_dirs_fds(afl_state_t *afl) {
/* Gnuplot output file. */
tmp = alloc_printf("%s/plot_data", afl->out_dir);
int fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, 0600);
if (fd < 0) { PFATAL("Unable to create '%s'", tmp); }
ck_free(tmp);
afl->fsrv.plot_file = fdopen(fd, "w");
if (!afl->fsrv.plot_file) { PFATAL("fdopen() failed"); }
if (!afl->in_place_resume) {
int fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", tmp); }
ck_free(tmp);
afl->fsrv.plot_file = fdopen(fd, "w");
if (!afl->fsrv.plot_file) { PFATAL("fdopen() failed"); }
fprintf(
afl->fsrv.plot_file,
"# unix_time, cycles_done, cur_path, paths_total, "
"pending_total, pending_favs, map_size, unique_crashes, "
"unique_hangs, max_depth, execs_per_sec, total_execs, edges_found\n");
} else {
int fd = open(tmp, O_WRONLY | O_CREAT, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", tmp); }
ck_free(tmp);
afl->fsrv.plot_file = fdopen(fd, "w");
if (!afl->fsrv.plot_file) { PFATAL("fdopen() failed"); }
fseek(afl->fsrv.plot_file, 0, SEEK_END);
}
fprintf(afl->fsrv.plot_file,
"# unix_time, cycles_done, cur_path, paths_total, "
"pending_total, pending_favs, map_size, unique_crashes, "
"unique_hangs, max_depth, execs_per_sec, total_execs, edges_found\n");
fflush(afl->fsrv.plot_file);
/* ignore errors */
@ -2034,7 +2058,7 @@ void setup_cmdline_file(afl_state_t *afl, char **argv) {
/* Store the command line to reproduce our findings */
tmp = alloc_printf("%s/cmdline", afl->out_dir);
fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, 0600);
fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", tmp); }
ck_free(tmp);
@ -2069,7 +2093,8 @@ void setup_stdio_file(afl_state_t *afl) {
unlink(afl->fsrv.out_file); /* Ignore errors */
afl->fsrv.out_fd = open(afl->fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, 0600);
afl->fsrv.out_fd =
open(afl->fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (afl->fsrv.out_fd < 0) {
@ -2457,7 +2482,7 @@ void check_asan_opts(afl_state_t *afl) {
}
if (!strstr(x, "symbolize=0")) {
if (!afl->debug && !strstr(x, "symbolize=0")) {
FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!");
@ -2591,6 +2616,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
}
if (afl->afl_env.afl_skip_bin_check || afl->use_wine || afl->unicorn_mode ||
(afl->fsrv.qemu_mode && getenv("AFL_QEMU_CUSTOM_BIN")) ||
afl->non_instrumented_mode) {
return;

View File

@ -465,7 +465,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
unlink(q->fname); /* ignore errors */
fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, 0600);
fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); }

View File

@ -5119,14 +5119,23 @@ pacemaker_fuzzing:
/* Update afl->pending_not_fuzzed count if we made it through the
calibration cycle and have not seen this entry before. */
/*
// TODO FIXME: I think we need this plus need an -L -1 check
if (!afl->stop_soon && !afl->queue_cur->cal_failed &&
(afl->queue_cur->was_fuzzed == 0 || afl->queue_cur->fuzz_level == 0)
&& !afl->queue_cur->disabled) {
// if (!afl->stop_soon && !afl->queue_cur->cal_failed &&
// !afl->queue_cur->was_fuzzed) {
if (!afl->queue_cur->was_fuzzed) {
// afl->queue_cur->was_fuzzed = 1;
// --afl->pending_not_fuzzed;
// if (afl->queue_cur->favored) --afl->pending_favored;
// }
--afl->pending_not_fuzzed;
afl->queue_cur->was_fuzzed = 1;
if (afl->queue_cur->favored) { --afl->pending_favored; }
}
}
*/
orig_in = NULL;

View File

@ -198,34 +198,35 @@ void create_alias_table(afl_state_t *afl) {
while (nS)
afl->alias_probability[S[--nS]] = 1;
#ifdef INTROSPECTION
u8 fn[PATH_MAX];
snprintf(fn, PATH_MAX, "%s/introspection_corpus.txt", afl->out_dir);
FILE *f = fopen(fn, "a");
if (f) {
/*
#ifdef INTROSPECTION
u8 fn[PATH_MAX];
snprintf(fn, PATH_MAX, "%s/introspection_corpus.txt", afl->out_dir);
FILE *f = fopen(fn, "a");
if (f) {
for (i = 0; i < n; i++) {
for (i = 0; i < n; i++) {
struct queue_entry *q = afl->queue_buf[i];
fprintf(
f,
"entry=%u name=%s favored=%s variable=%s disabled=%s len=%u "
"exec_us=%u "
"bitmap_size=%u bitsmap_size=%u tops=%u weight=%f perf_score=%f\n",
i, q->fname, q->favored ? "true" : "false",
q->var_behavior ? "true" : "false", q->disabled ? "true" : "false",
q->len, (u32)q->exec_us, q->bitmap_size, q->bitsmap_size, q->tc_ref,
q->weight, q->perf_score);
struct queue_entry *q = afl->queue_buf[i];
fprintf(
f,
"entry=%u name=%s favored=%s variable=%s disabled=%s len=%u "
"exec_us=%u "
"bitmap_size=%u bitsmap_size=%u tops=%u weight=%f perf_score=%f\n",
i, q->fname, q->favored ? "true" : "false",
q->var_behavior ? "true" : "false", q->disabled ? "true" : "false",
q->len, (u32)q->exec_us, q->bitmap_size, q->bitsmap_size, q->tc_ref,
q->weight, q->perf_score);
}
fprintf(f, "\n");
fclose(f);
}
fprintf(f, "\n");
fclose(f);
}
#endif
#endif
*/
/*
fprintf(stderr, " entry alias probability perf_score weight
filename\n"); for (u32 i = 0; i < n; ++i) fprintf(stderr, " %5u %5u %11u
@ -248,7 +249,7 @@ void mark_as_det_done(afl_state_t *afl, struct queue_entry *q) {
snprintf(fn, PATH_MAX, "%s/queue/.state/deterministic_done/%s", afl->out_dir,
strrchr(q->fname, '/') + 1);
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600);
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
close(fd);
@ -271,7 +272,7 @@ void mark_as_variable(afl_state_t *afl, struct queue_entry *q) {
if (symlink(ldest, fn)) {
s32 fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600);
s32 fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
close(fd);
@ -299,7 +300,7 @@ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) {
s32 fd;
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600);
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
close(fd);
@ -324,7 +325,7 @@ static u8 check_if_text(afl_state_t *afl, struct queue_entry *q) {
if (len >= MAX_FILE) len = MAX_FILE - 1;
if ((fd = open(q->fname, O_RDONLY)) < 0) return 0;
buf = afl_realloc(AFL_BUF_PARAM(in_scratch), len);
buf = afl_realloc(AFL_BUF_PARAM(in_scratch), len + 1);
comp = read(fd, buf, len);
close(fd);
if (comp != (ssize_t)len) return 0;
@ -679,13 +680,17 @@ void cull_queue(afl_state_t *afl) {
}
afl->top_rated[i]->favored = 1;
++afl->queued_favored;
if (!afl->top_rated[i]->favored) {
if (afl->top_rated[i]->fuzz_level == 0 ||
!afl->top_rated[i]->was_fuzzed) {
afl->top_rated[i]->favored = 1;
++afl->queued_favored;
++afl->pending_favored;
if (afl->top_rated[i]->fuzz_level == 0 ||
!afl->top_rated[i]->was_fuzzed) {
++afl->pending_favored;
}
}

View File

@ -1853,7 +1853,7 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
}
static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl,
u8 *o_pattern, u8 *changed_val, u32 idx,
u8 *o_pattern, u8 *changed_val, u8 plen, u32 idx,
u32 taint_len, u8 *orig_buf, u8 *buf, u8 *cbuf,
u32 len, u8 lvl, u8 *status) {
@ -1866,7 +1866,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl,
u8 save[40];
u32 saved_idx = idx, pre, from = 0, to = 0, i, j;
u32 its_len = MIN((u32)32, len - idx);
u32 its_len = MIN((u32)plen, len - idx);
its_len = MIN(its_len, taint_len);
u32 saved_its_len = its_len;
@ -2365,9 +2365,9 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
status = 0;
if (unlikely(rtn_extend_encoding(afl, o->v0, o->v1, orig_o->v0,
orig_o->v1, idx, taint_len, orig_buf,
buf, cbuf, len, lvl, &status))) {
if (unlikely(rtn_extend_encoding(
afl, o->v0, o->v1, orig_o->v0, orig_o->v1, SHAPE_BYTES(h->shape),
idx, taint_len, orig_buf, buf, cbuf, len, lvl, &status))) {
return 1;
@ -2382,9 +2382,9 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
status = 0;
if (unlikely(rtn_extend_encoding(afl, o->v1, o->v0, orig_o->v1,
orig_o->v0, idx, taint_len, orig_buf,
buf, cbuf, len, lvl, &status))) {
if (unlikely(rtn_extend_encoding(
afl, o->v1, o->v0, orig_o->v1, orig_o->v0, SHAPE_BYTES(h->shape),
idx, taint_len, orig_buf, buf, cbuf, len, lvl, &status))) {
return 1;

View File

@ -83,7 +83,8 @@ write_to_testcase(afl_state_t *afl, void *mem, u32 len) {
afl->document_counter++,
describe_op(afl, 0, NAME_MAX - strlen("000000000:")));
if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600)) >= 0) {
if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION)) >=
0) {
if (write(doc_fd, mem, len) != len)
PFATAL("write to mutation file failed: %s", fn);
@ -247,12 +248,14 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at,
if (unlikely(afl->no_unlink)) {
fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_TRUNC,
DEFAULT_PERMISSION);
} else {
unlink(afl->fsrv.out_file); /* Ignore errors. */
fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_EXCL,
DEFAULT_PERMISSION);
}
@ -564,7 +567,8 @@ void sync_fuzzers(afl_state_t *afl) {
/* document the attempt to sync to this instance */
sprintf(qd_synced_path, "%s/.synced/%s.last", afl->out_dir, sd_ent->d_name);
id_fd = open(qd_synced_path, O_RDWR | O_CREAT | O_TRUNC, 0600);
id_fd =
open(qd_synced_path, O_RDWR | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
if (id_fd >= 0) close(id_fd);
/* Skip anything that doesn't have a queue/ subdirectory. */
@ -587,7 +591,7 @@ void sync_fuzzers(afl_state_t *afl) {
sprintf(qd_synced_path, "%s/.synced/%s", afl->out_dir, sd_ent->d_name);
id_fd = open(qd_synced_path, O_RDWR | O_CREAT, 0600);
id_fd = open(qd_synced_path, O_RDWR | O_CREAT, DEFAULT_PERMISSION);
if (id_fd < 0) { PFATAL("Unable to create '%s'", qd_synced_path); }
@ -851,7 +855,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
if (unlikely(afl->no_unlink)) {
fd = open(q->fname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
fd = open(q->fname, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); }
@ -866,7 +870,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
} else {
unlink(q->fname); /* ignore errors */
fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, 0600);
fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); }

View File

@ -433,6 +433,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
afl->afl_env.afl_kill_signal =
(u8 *)get_afl_env(afl_environment_variables[i]);
} else if (!strncmp(env, "AFL_TARGET_ENV",
afl_environment_variable_len)) {
afl->afl_env.afl_target_env =
(u8 *)get_afl_env(afl_environment_variables[i]);
}
} else {

View File

@ -391,10 +391,11 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
fprintf(afl->fsrv.plot_file,
"%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f, %llu, "
"%u\n",
get_cur_time() / 1000, afl->queue_cycle - 1, afl->current_entry,
afl->queued_paths, afl->pending_not_fuzzed, afl->pending_favored,
bitmap_cvg, afl->unique_crashes, afl->unique_hangs, afl->max_depth,
eps, afl->plot_prev_ed, t_bytes); /* ignore errors */
(afl->prev_run_time + get_cur_time() - afl->start_time),
afl->queue_cycle - 1, afl->current_entry, afl->queued_paths,
afl->pending_not_fuzzed, afl->pending_favored, bitmap_cvg,
afl->unique_crashes, afl->unique_hangs, afl->max_depth, eps,
afl->plot_prev_ed, t_bytes); /* ignore errors */
fflush(afl->fsrv.plot_file);
@ -645,6 +646,13 @@ void show_stats(afl_state_t *afl) {
#define SP10 SP5 SP5
#define SP20 SP10 SP10
/* Since `total_crashes` does not get reloaded from disk on restart,
it indicates if we found crashes this round already -> paint red.
If it's 0, but `unique_crashes` is set from a past run, paint in yellow. */
char *crash_color = afl->total_crashes ? cLRD
: afl->unique_crashes ? cYEL
: cRST;
/* Lord, forgive me this. */
SAYF(SET_G1 bSTG bLT bH bSTOP cCYA
@ -732,7 +740,7 @@ void show_stats(afl_state_t *afl) {
u_stringify_time_diff(time_tmp, cur_ms, afl->last_crash_time);
SAYF(bV bSTOP " last uniq crash : " cRST "%-33s " bSTG bV bSTOP
" uniq crashes : %s%-6s" bSTG bV "\n",
time_tmp, afl->unique_crashes ? cLRD : cRST, tmp);
time_tmp, crash_color, tmp);
sprintf(tmp, "%s%s", u_stringify_int(IB(0), afl->unique_hangs),
(afl->unique_hangs >= KEEP_UNIQUE_HANG) ? "+" : "");
@ -815,15 +823,13 @@ void show_stats(afl_state_t *afl) {
SAYF(bV bSTOP " total execs : " cRST "%-20s " bSTG bV bSTOP
" new crashes : %s%-22s" bSTG bV "\n",
u_stringify_int(IB(0), afl->fsrv.total_execs),
afl->unique_crashes ? cLRD : cRST, tmp);
u_stringify_int(IB(0), afl->fsrv.total_execs), crash_color, tmp);
} else {
SAYF(bV bSTOP " total execs : " cRST "%-20s " bSTG bV bSTOP
" total crashes : %s%-22s" bSTG bV "\n",
u_stringify_int(IB(0), afl->fsrv.total_execs),
afl->unique_crashes ? cLRD : cRST, tmp);
u_stringify_int(IB(0), afl->fsrv.total_execs), crash_color, tmp);
}

View File

@ -223,6 +223,7 @@ static void usage(u8 *argv0, int more_help) {
"AFL_PYTHON_MODULE: mutate and trim inputs with the specified Python module\n"
"AFL_QUIET: suppress forkserver status messages\n"
"AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
"AFL_TARGET_ENV: pass extra environment variables to target\n"
"AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n"
"AFL_SKIP_BIN_CHECK: skip the check, if the target is an executable\n"
"AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n"
@ -351,7 +352,7 @@ int main(int argc, char **argv_orig, char **envp) {
exit_1 = !!afl->afl_env.afl_bench_just_one;
SAYF(cCYA "afl-fuzz" VERSION cRST
" based on afl by Michal Zalewski and a big online community\n");
" based on afl by Michal Zalewski and a large online community\n");
doc_path = access(DOC_PATH, F_OK) != 0 ? (u8 *)"docs" : (u8 *)DOC_PATH;
@ -1022,32 +1023,6 @@ int main(int argc, char **argv_orig, char **envp) {
}
if (afl->fsrv.qemu_mode && getenv("AFL_USE_QASAN")) {
u8 *preload = getenv("AFL_PRELOAD");
u8 *libqasan = get_libqasan_path(argv_orig[0]);
if (!preload) {
setenv("AFL_PRELOAD", libqasan, 0);
} else {
u8 *result = ck_alloc(strlen(libqasan) + strlen(preload) + 2);
strcpy(result, libqasan);
strcat(result, " ");
strcat(result, preload);
setenv("AFL_PRELOAD", result, 1);
ck_free(result);
}
afl->afl_env.afl_preload = (u8 *)getenv("AFL_PRELOAD");
ck_free(libqasan);
}
if (afl->fsrv.mem_limit && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260;
OKF("afl++ is maintained by Marc \"van Hauser\" Heuse, Heiko \"hexcoder\" "
@ -1312,38 +1287,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->fsrv.qemu_mode) {
u8 *qemu_preload = getenv("QEMU_SET_ENV");
u8 *afl_preload = getenv("AFL_PRELOAD");
u8 *buf;
s32 j, afl_preload_size = strlen(afl_preload);
for (j = 0; j < afl_preload_size; ++j) {
if (afl_preload[j] == ',') {
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);
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
} else {
@ -1360,6 +1304,13 @@ int main(int argc, char **argv_orig, char **envp) {
}
if (afl->afl_env.afl_target_env &&
!extract_and_set_env(afl->afl_env.afl_target_env)) {
FATAL("Bad value of AFL_TARGET_ENV");
}
save_cmdline(afl, argc, argv);
fix_up_banner(afl, argv[optind]);
@ -1403,6 +1354,15 @@ int main(int argc, char **argv_orig, char **envp) {
set_scheduler_mode(SCHEDULER_MODE_LOW_LATENCY);
#endif
#ifdef __APPLE__
if (pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0) != 0) {
WARNF("general thread priority settings failed");
}
#endif
init_count_class16();
if (afl->is_main_node && check_main_node_exists(afl) == 1) {
@ -1437,23 +1397,8 @@ int main(int argc, char **argv_orig, char **envp) {
// read_foreign_testcases(afl, 1); for the moment dont do this
OKF("Loaded a total of %u seeds.", afl->queued_paths);
load_auto(afl);
pivot_inputs(afl);
if (extras_dir_cnt) {
for (i = 0; i < extras_dir_cnt; i++) {
load_extras(afl, extras_dir[i]);
}
dedup_extras(afl);
OKF("Loaded a total of %u extras.", afl->extras_cnt);
}
if (!afl->timeout_given) { find_timeout(afl); } // only for resumes!
if ((afl->tmp_dir = afl->afl_env.afl_tmpdir) != NULL &&
@ -1568,6 +1513,21 @@ int main(int argc, char **argv_orig, char **envp) {
}
if (afl->non_instrumented_mode || afl->fsrv.qemu_mode || afl->unicorn_mode) {
map_size = afl->fsrv.map_size = MAP_SIZE;
afl->virgin_bits = ck_realloc(afl->virgin_bits, map_size);
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, map_size);
afl->virgin_crash = ck_realloc(afl->virgin_crash, map_size);
afl->var_bytes = ck_realloc(afl->var_bytes, map_size);
afl->top_rated = ck_realloc(afl->top_rated, map_size * sizeof(void *));
afl->clean_trace = ck_realloc(afl->clean_trace, map_size);
afl->clean_trace_custom = ck_realloc(afl->clean_trace_custom, map_size);
afl->first_trace = ck_realloc(afl->first_trace, map_size);
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, map_size);
}
afl->argv = use_argv;
afl->fsrv.trace_bits =
afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->non_instrumented_mode);
@ -1575,49 +1535,49 @@ int main(int argc, char **argv_orig, char **envp) {
if (!afl->non_instrumented_mode && !afl->fsrv.qemu_mode &&
!afl->unicorn_mode) {
afl->fsrv.map_size = 4194304; // dummy temporary value
setenv("AFL_MAP_SIZE", "4194304", 1);
if (map_size <= DEFAULT_SHMEM_SIZE && !afl->non_instrumented_mode &&
!afl->fsrv.qemu_mode && !afl->unicorn_mode) {
afl->fsrv.map_size = DEFAULT_SHMEM_SIZE; // dummy temporary value
char vbuf[16];
snprintf(vbuf, sizeof(vbuf), "%u", DEFAULT_SHMEM_SIZE);
setenv("AFL_MAP_SIZE", vbuf, 1);
}
u32 new_map_size = afl_fsrv_get_mapsize(
&afl->fsrv, afl->argv, &afl->stop_soon, afl->afl_env.afl_debug_child);
if (new_map_size && new_map_size != 4194304) {
// only reinitialize if the map needs to be larger than what we have.
if (map_size < new_map_size) {
// only reinitialize when it makes sense
if (map_size < new_map_size ||
(new_map_size > map_size && new_map_size - map_size > MAP_SIZE)) {
OKF("Re-initializing maps to %u bytes", new_map_size);
OKF("Re-initializing maps to %u bytes", new_map_size);
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
afl->var_bytes = ck_realloc(afl->var_bytes, new_map_size);
afl->top_rated =
ck_realloc(afl->top_rated, new_map_size * sizeof(void *));
afl->clean_trace = ck_realloc(afl->clean_trace, new_map_size);
afl->clean_trace_custom =
ck_realloc(afl->clean_trace_custom, new_map_size);
afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
afl->var_bytes = ck_realloc(afl->var_bytes, new_map_size);
afl->top_rated =
ck_realloc(afl->top_rated, new_map_size * sizeof(void *));
afl->clean_trace = ck_realloc(afl->clean_trace, new_map_size);
afl->clean_trace_custom =
ck_realloc(afl->clean_trace_custom, new_map_size);
afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
afl_fsrv_kill(&afl->fsrv);
afl_shm_deinit(&afl->shm);
afl->fsrv.map_size = new_map_size;
afl->fsrv.trace_bits =
afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode);
setenv("AFL_NO_AUTODICT", "1", 1); // loaded already
afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
afl->afl_env.afl_debug_child);
}
afl_fsrv_kill(&afl->fsrv);
afl_shm_deinit(&afl->shm);
afl->fsrv.map_size = new_map_size;
afl->fsrv.trace_bits =
afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode);
setenv("AFL_NO_AUTODICT", "1", 1); // loaded already
afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
afl->afl_env.afl_debug_child);
map_size = new_map_size;
}
afl->fsrv.map_size = map_size;
}
if (afl->cmplog_binary) {
@ -1630,57 +1590,77 @@ int main(int argc, char **argv_orig, char **envp) {
afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary;
afl->cmplog_fsrv.init_child_func = cmplog_exec_child;
afl->cmplog_fsrv.map_size = 4194304;
if ((map_size <= DEFAULT_SHMEM_SIZE ||
afl->cmplog_fsrv.map_size < map_size) &&
!afl->non_instrumented_mode && !afl->fsrv.qemu_mode &&
!afl->unicorn_mode) {
afl->cmplog_fsrv.map_size = MAX(map_size, (u32)DEFAULT_SHMEM_SIZE);
char vbuf[16];
snprintf(vbuf, sizeof(vbuf), "%u", afl->cmplog_fsrv.map_size);
setenv("AFL_MAP_SIZE", vbuf, 1);
}
u32 new_map_size =
afl_fsrv_get_mapsize(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon,
afl->afl_env.afl_debug_child);
if (new_map_size && new_map_size != 4194304) {
// only reinitialize when it needs to be larger
if (map_size < new_map_size) {
// only reinitialize when it needs to be larger
if (map_size < new_map_size) {
OKF("Re-initializing maps to %u bytes due cmplog", new_map_size);
OKF("Re-initializing maps to %u bytes due cmplog", new_map_size);
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
afl->var_bytes = ck_realloc(afl->var_bytes, new_map_size);
afl->top_rated =
ck_realloc(afl->top_rated, new_map_size * sizeof(void *));
afl->clean_trace = ck_realloc(afl->clean_trace, new_map_size);
afl->clean_trace_custom =
ck_realloc(afl->clean_trace_custom, new_map_size);
afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
afl->var_bytes = ck_realloc(afl->var_bytes, new_map_size);
afl->top_rated =
ck_realloc(afl->top_rated, new_map_size * sizeof(void *));
afl->clean_trace = ck_realloc(afl->clean_trace, new_map_size);
afl->clean_trace_custom =
ck_realloc(afl->clean_trace_custom, new_map_size);
afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
afl_fsrv_kill(&afl->fsrv);
afl_fsrv_kill(&afl->cmplog_fsrv);
afl_shm_deinit(&afl->shm);
afl_fsrv_kill(&afl->fsrv);
afl_fsrv_kill(&afl->cmplog_fsrv);
afl_shm_deinit(&afl->shm);
afl->cmplog_fsrv.map_size = new_map_size; // non-cmplog stays the same
afl->cmplog_fsrv.map_size = new_map_size; // non-cmplog stays the same
map_size = new_map_size;
afl->fsrv.trace_bits =
afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode);
setenv("AFL_NO_AUTODICT", "1", 1); // loaded already
afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
afl->afl_env.afl_debug_child);
afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon,
afl->afl_env.afl_debug_child);
map_size = new_map_size;
}
setenv("AFL_NO_AUTODICT", "1", 1); // loaded already
afl->fsrv.trace_bits =
afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode);
afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits;
afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
afl->afl_env.afl_debug_child);
afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon,
afl->afl_env.afl_debug_child);
}
afl->cmplog_fsrv.map_size = map_size;
OKF("Cmplog forkserver successfully started");
}
load_auto(afl);
if (extras_dir_cnt) {
for (i = 0; i < extras_dir_cnt; i++) {
load_extras(afl, extras_dir[i]);
}
}
deunicode_extras(afl);
dedup_extras(afl);
if (afl->extras_cnt) { OKF("Loaded a total of %u extras.", afl->extras_cnt); }
// after we have the correct bitmap size we can read the bitmap -B option
// and set the virgin maps
if (afl->in_bitmap) {

View File

@ -162,8 +162,8 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
snprintf(shm->g_shm_file_path, L_tmpnam, "/afl_%d_%ld", getpid(), random());
/* create the shared memory segment as if it was a file */
shm->g_shm_fd =
shm_open(shm->g_shm_file_path, O_CREAT | O_RDWR | O_EXCL, 0600);
shm->g_shm_fd = shm_open(shm->g_shm_file_path, O_CREAT | O_RDWR | O_EXCL,
DEFAULT_PERMISSION);
if (shm->g_shm_fd == -1) { PFATAL("shm_open() failed"); }
/* configure the size of the shared memory segment */
@ -202,7 +202,8 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
/* create the shared memory segment as if it was a file */
shm->cmplog_g_shm_fd =
shm_open(shm->cmplog_g_shm_file_path, O_CREAT | O_RDWR | O_EXCL, 0600);
shm_open(shm->cmplog_g_shm_file_path, O_CREAT | O_RDWR | O_EXCL,
DEFAULT_PERMISSION);
if (shm->cmplog_g_shm_fd == -1) { PFATAL("shm_open() failed"); }
/* configure the size of the shared memory segment */
@ -241,13 +242,14 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
#else
u8 *shm_str;
shm->shm_id = shmget(IPC_PRIVATE, map_size, IPC_CREAT | IPC_EXCL | 0600);
shm->shm_id =
shmget(IPC_PRIVATE, map_size, IPC_CREAT | IPC_EXCL | DEFAULT_PERMISSION);
if (shm->shm_id < 0) { PFATAL("shmget() failed"); }
if (shm->cmplog_mode) {
shm->cmplog_shm_id = shmget(IPC_PRIVATE, sizeof(struct cmp_map),
IPC_CREAT | IPC_EXCL | 0600);
IPC_CREAT | IPC_EXCL | DEFAULT_PERMISSION);
if (shm->cmplog_shm_id < 0) {

View File

@ -252,7 +252,7 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
} else {
unlink(outfile); /* Ignore errors */
fd = open(outfile, O_WRONLY | O_CREAT | O_EXCL, 0600);
fd = open(outfile, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", outfile); }
}
@ -563,6 +563,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
"detect_leaks=0:"
"allocator_may_return_null=1:"
"symbolize=0:"
"detect_odr_violation=0:"
"handle_segv=0:"
"handle_sigbus=0:"
"handle_abort=0:"
@ -598,38 +599,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
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);
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
} else {
@ -945,31 +915,6 @@ int main(int argc, char **argv_orig, char **envp) {
if (optind == argc || !out_file) { usage(argv[0]); }
if (fsrv->qemu_mode && getenv("AFL_USE_QASAN")) {
u8 *preload = getenv("AFL_PRELOAD");
u8 *libqasan = get_libqasan_path(argv_orig[0]);
if (!preload) {
setenv("AFL_PRELOAD", libqasan, 0);
} else {
u8 *result = ck_alloc(strlen(libqasan) + strlen(preload) + 2);
strcpy(result, libqasan);
strcat(result, " ");
strcat(result, preload);
setenv("AFL_PRELOAD", result, 1);
ck_free(result);
}
ck_free(libqasan);
}
if (in_dir) {
if (!out_file && !collect_coverage)
@ -1174,7 +1119,8 @@ int main(int argc, char **argv_orig, char **envp) {
unlink(stdin_file);
atexit(at_exit_handler);
fsrv->out_file = stdin_file;
fsrv->out_fd = open(stdin_file, O_RDWR | O_CREAT | O_EXCL, 0600);
fsrv->out_fd =
open(stdin_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); }
if (arg_offset && use_argv[arg_offset] != stdin_file) {

View File

@ -244,7 +244,7 @@ static s32 write_to_file(u8 *path, u8 *mem, u32 len) {
unlink(path); /* Ignore errors */
ret = open(path, O_RDWR | O_CREAT | O_EXCL, 0600);
ret = open(path, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (ret < 0) { PFATAL("Unable to create '%s'", path); }
@ -666,7 +666,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
unlink(out_file);
fsrv->out_file = out_file;
fsrv->out_fd = open(out_file, O_RDWR | O_CREAT | O_EXCL, 0600);
fsrv->out_fd = open(out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); }
@ -717,6 +717,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
"detect_leaks=0:"
"allocator_may_return_null=1:"
"symbolize=0:"
"detect_odr_violation=0:"
"handle_segv=0:"
"handle_sigbus=0:"
"handle_abort=0:"
@ -752,38 +753,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
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);
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
} else {
@ -1078,31 +1048,6 @@ int main(int argc, char **argv_orig, char **envp) {
check_environment_vars(envp);
setenv("AFL_NO_AUTODICT", "1", 1);
if (fsrv->qemu_mode && getenv("AFL_USE_QASAN")) {
u8 *preload = getenv("AFL_PRELOAD");
u8 *libqasan = get_libqasan_path(argv_orig[0]);
if (!preload) {
setenv("AFL_PRELOAD", libqasan, 0);
} else {
u8 *result = ck_alloc(strlen(libqasan) + strlen(preload) + 2);
strcpy(result, libqasan);
strcat(result, " ");
strcat(result, preload);
setenv("AFL_PRELOAD", result, 1);
ck_free(result);
}
ck_free(libqasan);
}
/* initialize cmplog_mode */
shm.cmplog_mode = 0;

View File

@ -18,6 +18,10 @@
#include <sys/stat.h>
#include <fcntl.h>
#ifdef TEST_SHARED_OBJECT
#define main main_exported
#endif
int main(int argc, char **argv) {
int fd = 0;

View File

@ -37,9 +37,9 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && {
echo "00000" > in/in
# Run afl-fuzz w/ the C mutator
$ECHO "$GREY[*] running afl-fuzz for the C mutator, this will take approx 5 seconds"
$ECHO "$GREY[*] running afl-fuzz for the C mutator, this will take approx 10 seconds"
{
AFL_CUSTOM_MUTATOR_LIBRARY=./libexamplemutator.so AFL_CUSTOM_MUTATOR_ONLY=1 ../afl-fuzz -V1 -m ${MEM_LIMIT} -i in -o out -- ./test-custom-mutator >>errors 2>&1
AFL_CUSTOM_MUTATOR_LIBRARY=./libexamplemutator.so AFL_CUSTOM_MUTATOR_ONLY=1 ../afl-fuzz -V10 -m ${MEM_LIMIT} -i in -o out -- ./test-custom-mutator >>errors 2>&1
} >>errors 2>&1
# Check results
@ -57,9 +57,9 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && {
rm -rf out errors core.*
# Run afl-fuzz w/ multiple C mutators
$ECHO "$GREY[*] running afl-fuzz with multiple custom C mutators, this will take approx 5 seconds"
$ECHO "$GREY[*] running afl-fuzz with multiple custom C mutators, this will take approx 10 seconds"
{
AFL_CUSTOM_MUTATOR_LIBRARY="./libexamplemutator.so;./libexamplemutator2.so" AFL_CUSTOM_MUTATOR_ONLY=1 ../afl-fuzz -V1 -m ${MEM_LIMIT} -i in -o out -- ./test-multiple-mutators >>errors 2>&1
AFL_CUSTOM_MUTATOR_LIBRARY="./libexamplemutator.so;./libexamplemutator2.so" AFL_CUSTOM_MUTATOR_ONLY=1 ../afl-fuzz -V10 -m ${MEM_LIMIT} -i in -o out -- ./test-multiple-mutators >>errors 2>&1
} >>errors 2>&1
test -n "$( ls out/default/crashes/id:000000* 2>/dev/null )" && { # TODO: update here
@ -76,11 +76,11 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && {
rm -rf out errors core.*
# Run afl-fuzz w/ the Python mutator
$ECHO "$GREY[*] running afl-fuzz for the Python mutator, this will take approx 5 seconds"
$ECHO "$GREY[*] running afl-fuzz for the Python mutator, this will take approx 10 seconds"
{
export PYTHONPATH=${CUSTOM_MUTATOR_PATH}
export AFL_PYTHON_MODULE=example
AFL_CUSTOM_MUTATOR_ONLY=1 ../afl-fuzz -V5 -m ${MEM_LIMIT} -i in -o out -- ./test-custom-mutator >>errors 2>&1
AFL_CUSTOM_MUTATOR_ONLY=1 ../afl-fuzz -V10 -m ${MEM_LIMIT} -i in -o out -- ./test-custom-mutator >>errors 2>&1
unset PYTHONPATH
unset AFL_PYTHON_MODULE
} >>errors 2>&1

23
test/test-dlopen.c Normal file
View File

@ -0,0 +1,23 @@
#include <stdio.h>
#include <errno.h>
#include <dlfcn.h>
#include <stdlib.h>
int main(int argc, char **argv) {
if (!getenv("TEST_DLOPEN_TARGET")) return 1;
void *lib = dlopen(getenv("TEST_DLOPEN_TARGET"), RTLD_LAZY);
if (!lib) {
perror(dlerror());
return 2;
}
int (*func)(int, char **) = dlsym(lib, "main_exported");
if (!func) return 3;
return func(argc, argv);
}

View File

@ -43,6 +43,48 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
$ECHO "$RED[!] llvm_mode failed"
CODE=1
}
../afl-clang-fast -DTEST_SHARED_OBJECT=1 -z defs -fPIC -shared -o test-instr.so ../test-instr.c > /dev/null 2>&1
test -e test-instr.so && {
$ECHO "$GREEN[+] llvm_mode shared object with -z defs compilation succeeded"
../afl-clang-fast -o test-dlopen.plain test-dlopen.c -ldl > /dev/null 2>&1
test -e test-dlopen.plain && {
$ECHO "$GREEN[+] llvm_mode test-dlopen compilation succeeded"
echo 0 | TEST_DLOPEN_TARGET=./test-instr.so AFL_QUIET=1 ./test-dlopen.plain > /dev/null 2>&1
if [ $? -ne 0 ]; then
$ECHO "$RED[!] llvm_mode test-dlopen exits with an error"
CODE=1
fi
echo 0 | TEST_DLOPEN_TARGET=./test-instr.so AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-dlopen.plain.0 -r -- ./test-dlopen.plain > /dev/null 2>&1
TEST_DLOPEN_TARGET=./test-instr.so AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-dlopen.plain.1 -r -- ./test-dlopen.plain < /dev/null > /dev/null 2>&1
test -e test-dlopen.plain.0 -a -e test-dlopen.plain.1 && {
diff test-dlopen.plain.0 test-dlopen.plain.1 > /dev/null 2>&1 && {
$ECHO "$RED[!] llvm_mode test-dlopen instrumentation should be different on different input but is not"
CODE=1
} || {
$ECHO "$GREEN[+] llvm_mode test-dlopen instrumentation present and working correctly"
TUPLES=`echo 0|TEST_DLOPEN_TARGET=./test-instr.so AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- ./test-dlopen.plain 2>&1 | grep Captur | awk '{print$3}'`
test "$TUPLES" -gt 3 -a "$TUPLES" -lt 12 && {
$ECHO "$GREEN[+] llvm_mode test-dlopen run reported $TUPLES instrumented locations which is fine"
} || {
$ECHO "$RED[!] llvm_mode test-dlopen instrumentation produces weird numbers: $TUPLES"
CODE=1
}
test "$TUPLES" -lt 3 && SKIP=1
true
}
} || {
$ECHO "$RED[!] llvm_mode test-dlopen instrumentation failed"
CODE=1
}
} || {
$ECHO "$RED[!] llvm_mode test-dlopen compilation failed"
CODE=1
}
rm -f test-dlopen.plain test-dlopen.plain.0 test-dlopen.plain.1 test-instr.so
} || {
$ECHO "$RED[!] llvm_mode shared object with -z defs compilation failed"
CODE=1
}
test -e test-compcov.harden && test_compcov_binary_functionality ./test-compcov.harden && {
grep -Eq$GREPAOPTION 'stack_chk_fail|fstack-protector-all|fortified' test-compcov.harden > /dev/null 2>&1 && {
$ECHO "$GREEN[+] llvm_mode hardened mode succeeded and is working"
@ -162,9 +204,9 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
test -e test-floatingpoint && {
mkdir -p in
echo ZZZZ > in/in
$ECHO "$GREY[*] running afl-fuzz with floating point splitting, this will take max. 30 seconds"
$ECHO "$GREY[*] running afl-fuzz with floating point splitting, this will take max. 45 seconds"
{
AFL_BENCH_UNTIL_CRASH=1 AFL_NO_UI=1 ../afl-fuzz -s 1 -V30 -m ${MEM_LIMIT} -i in -o out -D -- ./test-floatingpoint >>errors 2>&1
AFL_BENCH_UNTIL_CRASH=1 AFL_NO_UI=1 ../afl-fuzz -Z -s 123 -V50 -m ${MEM_LIMIT} -i in -o out -D -- ./test-floatingpoint >>errors 2>&1
} >>errors 2>&1
test -n "$( ls out/default/crashes/id:* 2>/dev/null )" && {
$ECHO "$GREEN[+] llvm_mode laf-intel floatingpoint splitting feature works correctly"

View File

@ -1,45 +0,0 @@
# This is the Dockerfile for testing problems in Travis build
# configuration #1.
# This needs not to be rebuild everytime, most of the time it needs just to
# be build once and then started when debugging issues and execute:
# cd /AFLplusplus/
# git pull
# make distrib
#
FROM ubuntu:bionic
LABEL "about"="travis image 1"
RUN apt-get update && apt-get -y install \
automake \
bison \
build-essential \
clang \
flex \
git \
python3.7 python3.7-dev \
python3-setuptools \
libtool libtool-bin \
libglib2.0-dev \
python-setuptools \
wget \
ca-certificates \
libpixman-1-dev \
gcc-7 gcc-7-plugin-dev libc++-7-dev \
findutils \
libcmocka-dev \
joe nano vim locate \
&& rm -rf /var/lib/apt/lists/*
ENV AFL_NO_UI=1
ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
ENV LLVM_CONFIG=llvm-config-6.0
RUN cd / && \
git clone https://github.com/AFLplusplus/AFLplusplus && \
cd AFLplusplus && \
git checkout dev && \
cd qemu_mode && wget http://download.qemu-project.org/qemu-3.1.1.tar.xz && \
cd ../unicorn_mode && git submodule init && git submodule update || true && \
cd /AFLplusplus && ASAN_BUILD=1 make source-only || true
WORKDIR /AFLplusplus
CMD ["/bin/bash"]

View File

@ -1,45 +0,0 @@
# This is the Dockerfile for testing problems in Travis build
# configuration #1.
# This needs not to be rebuild everytime, most of the time it needs just to
# be build once and then started when debugging issues and execute:
# cd /AFLplusplus/
# git pull
# make distrib
#
FROM ubuntu:focal
LABEL "about"="travis image 4"
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get -y install \
automake \
bison \
build-essential \
clang \
flex \
git \
python3 python3-dev \
python3-setuptools \
libtool libtool-bin \
libglib2.0-dev \
python-setuptools \
wget \
ca-certificates \
libpixman-1-dev \
gcc-9 gcc-9-plugin-dev libc++-9-dev \
findutils \
libcmocka-dev \
joe nano vim locate \
&& rm -rf /var/lib/apt/lists/*
ENV AFL_NO_UI=1
ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
RUN cd / && \
git clone https://github.com/AFLplusplus/AFLplusplus && \
cd AFLplusplus && \
git checkout dev && \
cd qemu_mode && wget http://download.qemu-project.org/qemu-3.1.1.tar.xz && \
cd ../unicorn_mode && git submodule init && git submodule update || true && \
cd /AFLplusplus && ASAN_BUILD=1 make source-only || true
WORKDIR /AFLplusplus
CMD ["/bin/bash"]

View File

@ -1,49 +0,0 @@
# This is the Dockerfile for testing problems in Travis builds
# configuration #3.
# This needs not to be rebuild everytime, most of the time it needs just to
# be build once and then started when debugging issues and execute:
# cd /AFLplusplus/
# git pull
# make distrib
#
FROM ubuntu:trusty
LABEL "about"="travis image 3"
RUN apt-get update && apt-get -y install \
automake \
bison \
build-essential \
clang \
flex \
git \
python2.7 python2.7-dev \
python3-setuptools \
libtool \
libglib2.0-dev \
python-setuptools \
wget \
ca-certificates \
libpixman-1-dev \
gcc-4.8 gcc-4.8-plugin-dev \
libc++-dev \
findutils \
libcmocka-dev \
joe nano vim locate \
&& rm -rf /var/lib/apt/lists/*
ENV TERM linux
ENV DEBIAN_FRONTEND noninteractive
ENV LLVM_CONFIG=llvm-config-3.4
ENV AFL_NO_UI=1
ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
RUN cd / && \
git clone https://github.com/AFLplusplus/AFLplusplus && \
cd AFLplusplus && \
git checkout dev && \
cd qemu_mode && wget http://download.qemu-project.org/qemu-3.1.1.tar.xz && \
cd ../unicorn_mode && git submodule init && git submodule update || true && \
cd /AFLplusplus && ASAN_BUILD=1 make source-only || true
WORKDIR /AFLplusplus
CMD ["/bin/bash"]

View File

@ -1,46 +0,0 @@
# This is the Dockerfile for testing problems in Travis builds
# configuration #2.
# This needs not to be rebuild everytime, most of the time it needs just to
# be build once and then started when debugging issues and execute:
# cd /AFLplusplus/
# git pull
# make distrib
#
FROM ubuntu:xenial
LABEL "about"="travis image 2"
RUN apt-get update && apt-get -y install \
automake \
bison \
build-essential \
clang-6.0 \
flex \
git \
python3 python3-dev \
python3-setuptools \
libtool libtool-bin \
libglib2.0-dev \
python-setuptools \
wget \
ca-certificates \
libpixman-1-dev \
gcc-5 gcc-5-plugin-dev \
libc++-dev \
findutils \
libcmocka-dev \
joe nano vim locate \
&& rm -rf /var/lib/apt/lists/*
ENV LLVM_CONFIG=llvm-config-6.0
ENV AFL_NO_UI=1
ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
RUN cd / && \
git clone https://github.com/AFLplusplus/AFLplusplus && \
cd AFLplusplus && \
git checkout dev && \
cd qemu_mode && wget http://download.qemu-project.org/qemu-3.1.1.tar.xz && \
cd ../unicorn_mode && git submodule init && git submodule update || true && \
cd /AFLplusplus && ASAN_BUILD=1 make source-only || true
WORKDIR /AFLplusplus
CMD ["/bin/bash"]

View File

@ -0,0 +1,197 @@
# Copyright (c) 2021 Brandon Miller (zznop)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
"""IDA script for loading state that was dumped from a running process using unicorn AFL's GDB
plugin (unicorn_dumper_gdb.py). The dumper script can be found in the AFL++ repository at:
https://github.com/AFLplusplus/AFLplusplus/blob/stable/unicorn_mode/helper_scripts/unicorn_dumper_gdb.py
"""
import json
from pathlib import Path, PurePath
import zlib
import idaapi
import ida_bytes
import ida_kernwin
import ida_nalt
import ida_segment
class ContextLoaderError(Exception):
"""Base "catch all" exception for this script
"""
class ArchNotSupportedError(ContextLoaderError):
"""Exception raised if the input file CPU architecture isn't supported fully
"""
def parse_mapping_index(filepath: str):
"""Open and unmarshal the _index.json file
:param filepath: Path to the JSON file
:return: Dict representing index file contents
"""
if filepath is None:
raise ContextLoaderError('_index.json file was not selected')
try:
with open(filepath, 'rb') as _file:
return json.load(_file)
except Exception as ex:
raise ContextLoaderError('Failed to parse json file {}'.format(filepath)) from ex
def get_input_name():
"""Get the name of the input file
:retrun: Name of the input file
"""
input_filepath = ida_nalt.get_input_file_path()
return Path(input_filepath).name
def write_segment_bytes(start: int, filepath: str):
""""Read data from context file and write it to the IDA segment
:param start: Start address
:param filepath: Path to context file
"""
with open(filepath, 'rb') as _file:
data = _file.read()
decompressed_data = zlib.decompress(data)
ida_bytes.put_bytes(start, decompressed_data)
def create_segment(context_dir: str, segment: dict, is_be: bool):
"""Create segment in IDA and map in the data from the file
:param context_dir: Parent directory of the context files
:param segment: Segment information from _index.json
:param is_be: True if processor is big endian, otherwise False
"""
input_name = get_input_name()
if Path(segment['name']).name != input_name:
ida_seg = idaapi.segment_t()
ida_seg.start_ea = segment['start']
ida_seg.end_ea = segment['end']
ida_seg.bitness = 1 if is_be else 0
if segment['permissions']['r']:
ida_seg.perm |= ida_segment.SEGPERM_READ
if segment['permissions']['w']:
ida_seg.perm |= ida_segment.SEGPERM_WRITE
if segment['permissions']['x']:
ida_seg.perm |= ida_segment.SEGPERM_EXEC
idaapi.add_segm_ex(ida_seg, Path(segment['name']).name, 'CODE', idaapi.ADDSEG_OR_DIE)
else:
idaapi.add_segm_ex(ida_seg, Path(segment['name']).name, 'DATA', idaapi.ADDSEG_OR_DIE)
if segment['content_file']:
write_segment_bytes(segment['start'], PurePath(context_dir, segment['content_file']))
def create_segments(index: dict, context_dir: str):
"""Iterate segments in index JSON, create the segment in IDA, and map in the data from the file
:param index: _index.json JSON data
:param context_dir: Parent directory of the context files
"""
info = idaapi.get_inf_structure()
is_be = info.is_be()
for segment in index['segments']:
create_segment(context_dir, segment, is_be)
def rebase_program(index: dict):
"""Rebase the program to the offset specified in the context _index.json
:param index: _index.json JSON data
"""
input_name = get_input_name()
new_base = None
for segment in index['segments']:
if not segment['name']:
continue
segment_name = Path(segment['name']).name
if input_name == segment_name:
new_base = segment['start']
break
if not new_base:
raise ContextLoaderError('Input file is not in _index.json')
current_base = idaapi.get_imagebase()
ida_segment.rebase_program(new_base-current_base, 8)
def get_pc_by_arch(index: dict) -> int:
"""Queries the input file CPU architecture and attempts to lookup the address of the program
counter in the _index.json by register name
:param index: _index.json JSON data
:return: Program counter value or None
"""
progctr = None
info = idaapi.get_inf_structure()
if info.procname == 'metapc':
if info.is_64bit():
progctr = index['regs']['rax']
elif info.is_32bit():
progctr = index['regs']['eax']
return progctr
def write_reg_info(index: dict):
"""Write register info as line comment at instruction pointed to by the program counter and
change focus to that location
:param index: _index.json JSON data
"""
cmt = ''
for reg, val in index['regs'].items():
cmt += f"{reg.ljust(6)} : {hex(val)}\n"
progctr = get_pc_by_arch(index)
if progctr is None:
raise ArchNotSupportedError(
'Architecture not fully supported, skipping register status comment')
ida_bytes.set_cmt(progctr, cmt, 0)
ida_kernwin.jumpto(progctr)
def main(filepath):
"""Main - parse _index.json input and map context files into the database
:param filepath: Path to the _index.json file
"""
try:
index = parse_mapping_index(filepath)
context_dir = Path(filepath).parent
rebase_program(index)
create_segments(index, context_dir)
write_reg_info(index)
except ContextLoaderError as ex:
print(ex)
if __name__ == '__main__':
main(ida_kernwin.ask_file(1, '*.json', 'Import file name'))

0
unicorn_mode/samples/speedtest/get_offsets.py Normal file → Executable file
View File

View File

@ -237,38 +237,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
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);
afl_free(buf);
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
} else {

View File

@ -187,6 +187,8 @@ static int ExecuteFilesOnyByOne(int argc, char **argv) {
}
close(fd);
}
free(buf);
@ -204,10 +206,20 @@ int main(int argc, char **argv) {
"To fuzz with afl-fuzz execute this:\n"
" afl-fuzz [afl-flags] -- %s [-N]\n"
"afl-fuzz will run N iterations before re-spawning the process (default: "
"1000)\n"
"INT_MAX)\n"
"======================================================\n",
argv[0], argv[0]);
if (getenv("AFL_GDB")) {
char cmd[64];
snprintf(cmd, sizeof(cmd), "cat /proc/%d/maps", getpid());
system(cmd);
fprintf(stderr, "DEBUG: aflpp_driver pid is %d\n", getpid());
sleep(1);
}
output_file = stderr;
maybe_duplicate_stderr();
maybe_close_fd_mask();

View File

@ -60,12 +60,12 @@ if
fi
if [ ! -f "$BIN" -o ! -x "$BIN" ]; then
echo "[-] Error: binary '$2' not found or is not executable." 1>&2
echo "[-] Error: binary '$BIN' not found or is not executable." 1>&2
exit 1
fi
if [ ! -d "$DIR/queue" ]; then
echo "[-] Error: directory '$1' not found or not created by afl-fuzz." 1>&2
echo "[-] Error: directory '$DIR' not found or not created by afl-fuzz." 1>&2
exit 1
fi

View File

@ -168,7 +168,7 @@ static void *__dislocator_alloc(size_t len) {
u8 * ret, *base;
size_t tlen;
int flags, fd, sp;
int flags, protflags, fd, sp;
if (total_mem + len > max_mem || total_mem + len < total_mem) {
@ -191,8 +191,14 @@ static void *__dislocator_alloc(size_t len) {
base = NULL;
tlen = (1 + PG_COUNT(rlen + 8)) * PAGE_SIZE;
protflags = PROT_READ | PROT_WRITE;
flags = MAP_PRIVATE | MAP_ANONYMOUS;
fd = -1;
#if defined(PROT_MAX)
// apply when sysctl vm.imply_prot_max is set to 1
// no-op otherwise
protflags |= PROT_MAX(PROT_READ | PROT_WRITE);
#endif
#if defined(USEHUGEPAGE)
sp = (rlen >= SUPER_PAGE_SIZE && !(rlen % SUPER_PAGE_SIZE));
@ -215,7 +221,7 @@ static void *__dislocator_alloc(size_t len) {
(void)sp;
#endif
ret = (u8 *)mmap(base, tlen, PROT_READ | PROT_WRITE, flags, fd, 0);
ret = (u8 *)mmap(base, tlen, protflags, flags, fd, 0);
#if defined(USEHUGEPAGE)
/* We try one more time with regular call */
if (ret == MAP_FAILED) {
@ -229,7 +235,7 @@ static void *__dislocator_alloc(size_t len) {
#elif defined(__sun)
flags &= -MAP_ALIGN;
#endif
ret = (u8 *)mmap(NULL, tlen, PROT_READ | PROT_WRITE, flags, fd, 0);
ret = (u8 *)mmap(NULL, tlen, protflags, flags, fd, 0);
}