Compare commits

...

110 Commits
3.10c ... 3.11c

Author SHA1 Message Date
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
61c8304f24 fixes 2021-03-15 20:32:01 +01: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
57 changed files with 1389 additions and 496 deletions

View File

@ -3,8 +3,8 @@ name: CI
on:
push:
branches: [ stable, dev ]
pull_request:
branches: [ stable, dev ]
# pull_request:
# branches: [ stable, dev ]
jobs:
build:

View File

@ -3,8 +3,8 @@ name: "CodeQL"
on:
push:
branches: [ stable, dev ]
pull_request:
branches: [ stable, dev ]
# pull_request:
# branches: [ stable, dev ]
jobs:
analyze:

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

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

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.11c](https://github.com/AFLplusplus/AFLplusplus/releases)
Github Version: 3.11a
Github Version: 3.12a
Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
@ -175,7 +175,7 @@ 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 install build-essential python3-dev automake flex bison libglib2.0-dev libpixman-1-dev python3-setuptools clang lld llvm llvm-dev libstdc++-dev
make distrib
sudo make install
```
@ -224,10 +224,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 +238,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 +304,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 +399,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 +493,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 +546,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 +562,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:

View File

@ -2,12 +2,15 @@
## Roadmap 3.00+
- AFL_MAP_SIZE for qemu_mode and unicorn_mode
- 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 +26,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,36 @@
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.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.

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

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

@ -26,7 +26,7 @@
/* Version string: */
// c = release, a = volatile github dev, e = experimental branch
#define VERSION "++3.10c"
#define VERSION "++3.11c"
/******************************************************
* *
@ -54,10 +54,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

@ -80,7 +80,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,10 +120,12 @@ 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",
@ -141,6 +145,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

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

@ -733,7 +733,7 @@ bool ModuleSanitizerCoverage::instrumentModule(
Var->getInitializer())) {
HasStr2 = true;
Str2 = Array->getAsString().str();
Str2 = Array->getRawDataValues().str();
}
@ -809,7 +809,7 @@ bool ModuleSanitizerCoverage::instrumentModule(
Var->getInitializer())) {
HasStr1 = true;
Str1 = Array->getAsString().str();
Str1 = Array->getRawDataValues().str();
}
@ -849,15 +849,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 +875,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);
}
}

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");
@ -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) {
@ -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,6 +516,12 @@ 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;
@ -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);
@ -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);
@ -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
@ -1551,17 +1719,42 @@ 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) {
char *p = (char *)ptr;
char *page = (char *)((uintptr_t)p & ~(sysconf(_SC_PAGE_SIZE) - 1));
if (unlikely(__asan_region_is_poisoned(ptr, len))) { return 0; }
int r = msync(page, (p - page) + len, MS_ASYNC);
if (r < 0) return errno != ENOMEM;
return 1;
long r = syscall(__afl_dummy_fd[1], SYS_write, ptr, len);
if (unlikely(r <= 0 || r > len)) { // fail - maybe hitting asan boundary?
char *p = (char *)ptr;
long page_size = sysconf(_SC_PAGE_SIZE);
char *page = (char *)((uintptr_t)p & ~(page_size - 1)) + page_size;
if (page < p + len) { return 0; } // no isnt, return fail
len -= (p + len - page);
r = syscall(__afl_dummy_fd[1], SYS_write, p, len);
}
// partial writes - we return what was written.
if (likely(r >= 0 && r <= len)) {
return (int)r;
} else {
return 0;
}
}
@ -1569,19 +1762,22 @@ 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;
if (!area_is_mapped(ptr1, 32) || !area_is_mapped(ptr2, 32)) return;
int l1, l2;
if ((l1 = area_is_valid(ptr1, 32)) <= 0 ||
(l2 = area_is_valid(ptr2, 32)) <= 0)
return;
int len = MIN(l1, l2);
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (k >> 4) ^ (k << 8);
@ -1592,17 +1788,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 +1806,9 @@ 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);
}
@ -1658,7 +1854,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 +1864,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 +1875,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 +1885,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

@ -62,13 +62,15 @@ bool isIgnoreFunction(const llvm::Function *F) {
"sancov.",
"__ubsan_",
"ign.",
"__afl_",
"__afl",
"_fini",
"__libc_csu",
"__libc_",
"__asan",
"__msan",
"__cmplog",
"__sancov",
"__cxx_",
"_GLOBAL",
"msan.",
"LLVMFuzzerM",
"LLVMFuzzerC",

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
d1ca56b84e

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

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

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",
"",
"",
"",
@ -938,7 +940,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.
@ -999,18 +1004,15 @@ 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";
cc_params[cc_par_cnt++] = "-lrt";
#endif
// prevent unnecessary build errors
cc_params[cc_par_cnt++] = "-Wno-unused-command-line-argument";
}
#endif
@ -1023,7 +1025,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 +1045,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);
@ -1273,6 +1282,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 +1296,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 +1411,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 +1456,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 +1496,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 +1594,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 "
@ -1550,7 +1647,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 +1693,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 +1746,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 +1874,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 +1884,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 +1906,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 +2007,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

@ -682,6 +682,7 @@ void check_environment_vars(char **envp) {
env[strlen(afl_environment_variables[i])] == '=') {
match = 1;
if ((val = getenv(afl_environment_variables[i])) && !*val) {
WARNF(
@ -1122,7 +1123,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 = 8000000; // a very large default map
char * ptr;
if ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE"))) {
@ -1130,7 +1131,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);
}

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);
@ -820,7 +821,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
" - The target binary requires a large map and crashes before "
"reporting.\n"
" Set a high value (e.g. AFL_MAP_SIZE=1024000) or use "
" Set a high value (e.g. AFL_MAP_SIZE=8000000) or use "
"AFL_DEBUG=1 to see the\n"
" message from the target binary\n\n"
@ -847,7 +848,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
" - The target binary requires a large map and crashes before "
"reporting.\n"
" Set a high value (e.g. AFL_MAP_SIZE=1024000) or use "
" Set a high value (e.g. AFL_MAP_SIZE=8000000) or use "
"AFL_DEBUG=1 to see the\n"
" message from the target binary\n\n"
@ -908,10 +909,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
} else if (!fsrv->mem_limit) {
SAYF("\n" cLRD "[-] " cRST
"Hmm, looks like the target binary terminated before we could"
" complete a 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.\n"
"Most likely the target has a huge coverage map, retry with setting"
" the\n"
"environment variable AFL_MAP_SIZE=8000000\n"
"Otherwise there is a horrible bug in the fuzzer.\n"
"Poke <afl-users@googlegroups.com> for troubleshooting tips.\n");
@ -927,6 +930,11 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
"explanations:\n\n"
"%s"
" - Most likely the target has a huge coverage map, retry with "
"setting the\n"
" environment variable AFL_MAP_SIZE=8000000\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 "

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. */

View File

@ -828,7 +828,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 +1069,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 +1136,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 +1192,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;
@ -1247,7 +1248,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];
@ -2457,7 +2458,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!");

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

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

@ -645,6 +645,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 +739,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 +822,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

@ -351,7 +351,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;
@ -1403,6 +1403,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 +1446,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 +1562,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,42 +1584,44 @@ 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 <= 8000000 && !afl->non_instrumented_mode &&
!afl->fsrv.qemu_mode && !afl->unicorn_mode) {
afl->fsrv.map_size = 8000000; // dummy temporary value
setenv("AFL_MAP_SIZE", "8000000", 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 when it makes sense
if ((map_size < new_map_size ||
(new_map_size != MAP_SIZE && new_map_size < map_size &&
map_size - new_map_size > 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;
@ -1630,57 +1641,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 <= 8000000 && !afl->non_instrumented_mode &&
!afl->fsrv.qemu_mode && !afl->unicorn_mode) {
afl->cmplog_fsrv.map_size = 8000000; // dummy temporary value
setenv("AFL_MAP_SIZE", "8000000", 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);
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_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon,
afl->afl_env.afl_debug_child);
} else {
map_size = new_map_size;
}
afl->cmplog_fsrv.map_size = new_map_size;
}
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

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

View 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:"

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

View File

@ -162,9 +162,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"

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

View File

@ -204,7 +204,7 @@ 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]);