aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvan Hauser <vh@thc.org>2021-03-10 15:45:14 +0100
committerGitHub <noreply@github.com>2021-03-10 15:45:14 +0100
commit2d92bb483ec3a3c0c30d568b432d15e971fc7015 (patch)
tree5066235cea9d80c5996ab44fa2f6eaddb5656f43
parent976cb3e36c130dc31fb189e9bb4f036730fca7ee (diff)
parent071edb1a2ddcf787680ca5096ddc1d6e28addd0b (diff)
downloadafl++-2d92bb483ec3a3c0c30d568b432d15e971fc7015.tar.gz
Merge pull request #786 from AFLplusplus/dev
push to stable
-rw-r--r--README.md32
-rwxr-xr-xafl-cmin14
-rwxr-xr-xafl-system-config2
-rw-r--r--docs/Changelog.md16
-rw-r--r--docs/env_variables.md11
-rw-r--r--docs/ideas.md4
-rw-r--r--include/envs.h6
-rw-r--r--instrumentation/LLVMInsTrim.so.cc2
-rw-r--r--instrumentation/README.cmplog.md10
-rw-r--r--instrumentation/README.ctx.md2
-rw-r--r--instrumentation/README.gcc_plugin.md61
-rw-r--r--instrumentation/README.neverzero.md2
-rw-r--r--instrumentation/README.ngram.md4
-rw-r--r--instrumentation/README.out_of_line.md8
-rw-r--r--instrumentation/README.persistent_mode.md26
-rw-r--r--instrumentation/afl-compiler-rt.o.c49
-rw-r--r--instrumentation/afl-llvm-common.cc6
-rw-r--r--instrumentation/afl-llvm-pass.so.cc184
-rw-r--r--instrumentation/llvm-alternative-coverage.h (renamed from instrumentation/llvm-ngram-coverage.h)3
-rwxr-xr-xqemu_mode/build_qemu_support.sh65
-rw-r--r--src/afl-cc.c119
-rw-r--r--src/afl-common.c1
-rw-r--r--src/afl-forkserver.c25
-rw-r--r--src/afl-fuzz-init.c15
-rw-r--r--src/afl-fuzz.c39
25 files changed, 519 insertions, 187 deletions
diff --git a/README.md b/README.md
index 6b11fee4..c3c73f3f 100644
--- a/README.md
+++ b/README.md
@@ -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
```
@@ -226,7 +226,7 @@ These build options exist:
* AFL_NO_X86 - if compiling on non-intel/amd platforms
* LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g. Debian)
-e.g.: make ASAN_BUILD=1
+e.g.: `make ASAN_BUILD=1`
## Good examples and writeups
@@ -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
@@ -554,7 +564,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:
diff --git a/afl-cmin b/afl-cmin
index 7f8544eb..778d7487 100755
--- a/afl-cmin
+++ b/afl-cmin
@@ -346,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
@@ -358,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"
@@ -378,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")
}
@@ -500,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"
diff --git a/afl-system-config b/afl-system-config
index 9905ac81..ae37a062 100755
--- a/afl-system-config
+++ b/afl-system-config
@@ -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
diff --git a/docs/Changelog.md b/docs/Changelog.md
index 3ca4a20b..c475911d 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -9,10 +9,14 @@ 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.11a (dev)
- - afl-fuzz
+ - afl-fuzz:
+ - fix sanitizer settings (bug since 3.10c)
- add non-unicode variants from unicode-looking dictionary entries
- Rust custom mutator API improvements
- - afl-cc
+ - 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
@@ -20,12 +24,16 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
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)
- - Renamed CTX to CALLER, added correct/real CTX implementation to CLASSIC
- - qemu_mode
+ - 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)
diff --git a/docs/env_variables.md b/docs/env_variables.md
index f6ed12d0..a20f1e42 100644
--- a/docs/env_variables.md
+++ b/docs/env_variables.md
@@ -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.
diff --git a/docs/ideas.md b/docs/ideas.md
index 08cb16ef..0130cf61 100644
--- a/docs/ideas.md
+++ b/docs/ideas.md
@@ -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
diff --git a/include/envs.h b/include/envs.h
index 26f4de90..4d4d6b0e 100644
--- a/include/envs.h
+++ b/include/envs.h
@@ -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",
diff --git a/instrumentation/LLVMInsTrim.so.cc b/instrumentation/LLVMInsTrim.so.cc
index f0de6536..62de6ec5 100644
--- a/instrumentation/LLVMInsTrim.so.cc
+++ b/instrumentation/LLVMInsTrim.so.cc
@@ -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"
diff --git a/instrumentation/README.cmplog.md b/instrumentation/README.cmplog.md
index 5f855e1f..a796c7a7 100644
--- a/instrumentation/README.cmplog.md
+++ b/instrumentation/README.cmplog.md
@@ -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:
diff --git a/instrumentation/README.ctx.md b/instrumentation/README.ctx.md
index 577b3e5f..335e9921 100644
--- a/instrumentation/README.ctx.md
+++ b/instrumentation/README.ctx.md
@@ -29,7 +29,7 @@ many map collisions occur.
## Caller Branch Coverage
If the context sensitive coverage introduces too may collisions and becoming
-decremental, the user can choose to augment edge coverage with just the
+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:
diff --git a/instrumentation/README.gcc_plugin.md b/instrumentation/README.gcc_plugin.md
index 12449efd..230ceb73 100644
--- a/instrumentation/README.gcc_plugin.md
+++ b/instrumentation/README.gcc_plugin.md
@@ -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).
diff --git a/instrumentation/README.neverzero.md b/instrumentation/README.neverzero.md
index 5c894d6e..49104e00 100644
--- a/instrumentation/README.neverzero.md
+++ b/instrumentation/README.neverzero.md
@@ -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.
diff --git a/instrumentation/README.ngram.md b/instrumentation/README.ngram.md
index de3ba432..da61ef32 100644
--- a/instrumentation/README.ngram.md
+++ b/instrumentation/README.ngram.md
@@ -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`
diff --git a/instrumentation/README.out_of_line.md b/instrumentation/README.out_of_line.md
index aad215b6..2264f91f 100644
--- a/instrumentation/README.out_of_line.md
+++ b/instrumentation/README.out_of_line.md
@@ -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.
diff --git a/instrumentation/README.persistent_mode.md b/instrumentation/README.persistent_mode.md
index 2cf76adf..24f81ea0 100644
--- a/instrumentation/README.persistent_mode.md
+++ b/instrumentation/README.persistent_mode.md
@@ -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!
diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c
index a702ec39..cca38cd0 100644
--- a/instrumentation/afl-compiler-rt.o.c
+++ b/instrumentation/afl-compiler-rt.o.c
@@ -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>
@@ -97,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
@@ -313,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 (__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) {
@@ -459,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) {
@@ -1097,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 (__afl_debug)
+ if (__afl_debug) {
+
fprintf(stderr,
"DEBUG: disabled instrumentation because of "
"AFL_DISABLE_LLVM_INSTRUMENTATION\n");
+ }
+
}
if (!init_done) {
@@ -1285,8 +1308,12 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
if (__afl_already_initialized_forkserver &&
__afl_final_loc + 1 + stop - start > __afl_map_size) {
- if (__afl_debug)
- fprintf(stderr, "Warning: new instrumneted code after the forkserver!\n");
+ if (__afl_debug) {
+
+ fprintf(stderr, "Warning: new instrumented code after the forkserver!\n");
+
+ }
+
__afl_final_loc = 2;
if (1 + stop - start > __afl_map_size) {
@@ -1771,7 +1798,7 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) {
if (__afl_cmp_map->headers[k].shape < len) {
- __afl_cmp_map->headers[k].shape = len;
+ __afl_cmp_map->headers[k].shape = len - 1;
}
diff --git a/instrumentation/afl-llvm-common.cc b/instrumentation/afl-llvm-common.cc
index aa54f4f7..0fd3a011 100644
--- a/instrumentation/afl-llvm-common.cc
+++ b/instrumentation/afl-llvm-common.cc
@@ -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",
diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc
index 33898aec..0f773aba 100644
--- a/instrumentation/afl-llvm-pass.so.cc
+++ b/instrumentation/afl-llvm-pass.so.cc
@@ -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,6 +82,7 @@ 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, *caller_str = NULL, *skip_nozero = NULL;
@@ -183,12 +184,17 @@ 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) */
VectorType *PrevLocTy = NULL;
@@ -205,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
@@ -218,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);
@@ -232,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. */
@@ -239,6 +293,7 @@ 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 || caller_str)
@@ -276,6 +331,31 @@ bool AFLCoverage::runOnModule(Module &M) {
#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
it to undef to allow the optimizer to do its thing. */
@@ -289,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! */
@@ -319,12 +416,30 @@ bool AFLCoverage::runOnModule(Module &M) {
IRBuilder<> IRB(&(*IP));
// Context sensitive coverage
- if ((ctx_str || caller_str) && &BB == &F.getEntryBlock()) {
+ if (instrument_ctx && &BB == &F.getEntryBlock()) {
+
+#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;
- // 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));
+ }
// does the function have calls? and is any of the calls larger than one
// basic block?
@@ -356,10 +471,31 @@ bool AFLCoverage::runOnModule(Module &M) {
if (has_calls) {
Value *NewCtx = ConstantInt::get(Int32Ty, AFL_R(map_size));
- if (ctx_str) NewCtx = IRB.CreateXor(PrevCtx, NewCtx);
- StoreInst *StoreCtx = IRB.CreateStore(NewCtx, AFLContext);
- StoreCtx->setMetadata(M.getMDKindID("nosanitize"),
- MDNode::get(C, None));
+#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));
+
+ }
}
@@ -413,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 || caller_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));
@@ -460,7 +603,7 @@ bool AFLCoverage::runOnModule(Module &M) {
#endif
PrevLocTrans = PrevLoc;
- if (ctx_str || caller_str)
+ if (instrument_ctx)
PrevLocTrans =
IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, PrevCtx), Int32Ty);
else
@@ -547,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 || caller_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));
diff --git a/instrumentation/llvm-ngram-coverage.h b/instrumentation/llvm-alternative-coverage.h
index 666839c8..0d7b3957 100644
--- a/instrumentation/llvm-ngram-coverage.h
+++ b/instrumentation/llvm-alternative-coverage.h
@@ -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
diff --git a/qemu_mode/build_qemu_support.sh b/qemu_mode/build_qemu_support.sh
index 4d3d9bf6..38085389 100755
--- a/qemu_mode/build_qemu_support.sh
+++ b/qemu_mode/build_qemu_support.sh
@@ -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!"
@@ -237,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 \
"
@@ -376,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
@@ -391,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!"
diff --git a/src/afl-cc.c b/src/afl-cc.c
index ab794877..44654de0 100644
--- a/src/afl-cc.c
+++ b/src/afl-cc.c
@@ -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;
@@ -75,6 +75,7 @@ enum {
INSTRUMENT_OPT_CTX = 8,
INSTRUMENT_OPT_NGRAM = 16,
INSTRUMENT_OPT_CALLER = 32,
+ INSTRUMENT_OPT_CTX_K = 64,
};
@@ -939,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.
@@ -1000,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
@@ -1024,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")) {
@@ -1044,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);
@@ -1288,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"), ":,;");
@@ -1383,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;
@@ -1437,6 +1503,20 @@ int main(int argc, char **argv, char **envp) {
}
+ 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)) {
@@ -1613,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"
@@ -1803,13 +1885,17 @@ int main(int argc, char **argv, char **envp) {
} else {
char *ptr2 = alloc_printf(" + NGRAM-%u", ngram_size);
+ char *ptr3 = alloc_printf(" + K-CTX-%u", ctx_k);
+
ptr = alloc_printf(
- "%s%s%s%s", instrument_mode_string[instrument_mode],
+ "%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_NGRAM) ? ptr2 : "",
+ (instrument_opt_mode & INSTRUMENT_OPT_CTX_K) ? ptr3 : "");
ck_free(ptr2);
+ ck_free(ptr3);
}
@@ -1921,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]);
diff --git a/src/afl-common.c b/src/afl-common.c
index a306fe5e..68f82a5e 100644
--- a/src/afl-common.c
+++ b/src/afl-common.c
@@ -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(
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index 6f08f9f4..68995388 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -481,11 +481,11 @@ 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:"
@@ -498,11 +498,11 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
"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:"
@@ -514,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);
@@ -523,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:"
@@ -536,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);
@@ -821,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"
@@ -848,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"
@@ -914,7 +914,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
"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=4194304\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");
@@ -931,8 +931,9 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
"%s"
- " - Most likely the target has a huge coverage map, retry with setting the\n"
- " environment variable AFL_MAP_SIZE=4194304\n\n"
+ " - 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"
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index 3dbc4c65..ca2f75f1 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -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!");
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index 09aff4fb..8364c1c2 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -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) {
@@ -1560,13 +1569,21 @@ 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);
+ u32 set_env = 0;
+ if (!getenv("AFL_MAP_SIZE")) {
+
+ afl->fsrv.map_size = 8000000; // dummy temporary value
+ setenv("AFL_MAP_SIZE", "8000000", 1);
+ set_env = 1;
+
+ }
+
+ u32 prev_map_size = afl->fsrv.map_size;
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) {
+ if (new_map_size && new_map_size != prev_map_size) {
// only reinitialize when it makes sense
if (map_size < new_map_size ||
@@ -1598,6 +1615,7 @@ int main(int argc, char **argv_orig, char **envp) {
}
map_size = new_map_size;
+ if (set_env) { unsetenv("AFL_MAP_SIZE"); }
}
@@ -1615,13 +1633,22 @@ 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;
+ u32 set_env = 0;
+ if (!getenv("AFL_MAP_SIZE")) {
+
+ afl->fsrv.map_size = 8000000; // dummy temporary value
+ setenv("AFL_MAP_SIZE", "8000000", 1);
+ set_env = 1;
+
+ }
+
+ u32 prev_map_size = afl->fsrv.map_size;
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) {
+ if (new_map_size && new_map_size != prev_map_size) {
// only reinitialize when it needs to be larger
if (map_size < new_map_size) {
@@ -1658,6 +1685,8 @@ int main(int argc, char **argv_orig, char **envp) {
}
+ if (set_env) { unsetenv("AFL_MAP_SIZE"); }
+
}
afl->cmplog_fsrv.map_size = map_size;