mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-24 14:43:22 +00:00
Compare commits
110 Commits
Author | SHA1 | Date | |
---|---|---|---|
23f7bee81c | |||
ac795ae1e1 | |||
aa6a50c2b4 | |||
61c8304f24 | |||
01ad0f3c6a | |||
db342c9c81 | |||
f1d8a01047 | |||
3753f56c25 | |||
d32b1d6b0c | |||
e5bdba4b9f | |||
c725cb71de | |||
8ff5063545 | |||
e549102563 | |||
b7d90a9e31 | |||
adeb0d18b1 | |||
16e3e2a7f7 | |||
0484d9b024 | |||
d60bbff0d9 | |||
966eba50a6 | |||
ffd8fae22a | |||
cb0fe044dd | |||
4f3b5f8adc | |||
3bb12b456f | |||
a10a627622 | |||
2777784f4f | |||
4bd0d4cbaf | |||
2d92bb483e | |||
071edb1a2d | |||
7f36290703 | |||
6cc59a38be | |||
87eb44abe4 | |||
a0c3011673 | |||
69f3095045 | |||
d678d59372 | |||
b2feada293 | |||
bff02dae0d | |||
851231c846 | |||
f21a5c42c1 | |||
d471fc9509 | |||
9f22a151f3 | |||
0c2478cae6 | |||
b865fc6080 | |||
d44b650cd4 | |||
aa12e46013 | |||
2c18fbbb2e | |||
4131965d48 | |||
5fab0fa51f | |||
9c9232b4e8 | |||
0d6e571237 | |||
40ba8814b3 | |||
a0a917ad87 | |||
8628839c55 | |||
5001779984 | |||
93d91dd7a1 | |||
791c5c171d | |||
a723156740 | |||
0868ea8348 | |||
5a6ad71f3f | |||
47f2650a32 | |||
74a6044b3f | |||
e82ce95251 | |||
e226d1bbb3 | |||
54c1087340 | |||
eb1e8619eb | |||
c96fca6833 | |||
976cb3e36c | |||
9b3d8c327d | |||
7b907e45ad | |||
e8d580f54d | |||
2dd5a02061 | |||
9844e1a856 | |||
44be521ab8 | |||
c9819e3b94 | |||
16d6f35aa6 | |||
c9854ec8cb | |||
c429021de1 | |||
41ad23041b | |||
3e5ac0af52 | |||
f848562732 | |||
3342aa751d | |||
a2f40aa285 | |||
f34a860d5f | |||
af9aeb89d4 | |||
be5274d4a9 | |||
b6dc529bc3 | |||
0aa93afeb8 | |||
79d75d8e42 | |||
96c526cb78 | |||
02f3319256 | |||
8f538e77ed | |||
1e76079e93 | |||
0e736276e6 | |||
08ef8d6b78 | |||
3977d50b55 | |||
3bcfbf5038 | |||
f0c7967fbf | |||
8bdb40b763 | |||
f0bc2e0e8b | |||
108e588e88 | |||
333509bb0a | |||
c269c3977c | |||
c3a8052a16 | |||
d0a61279b8 | |||
7259075b71 | |||
14fd477147 | |||
05e2f577f6 | |||
a29b360d55 | |||
75d6a8b701 | |||
ad7a7fcf07 | |||
82c05630ba |
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -3,8 +3,8 @@ name: CI
|
||||
on:
|
||||
push:
|
||||
branches: [ stable, dev ]
|
||||
pull_request:
|
||||
branches: [ stable, dev ]
|
||||
# pull_request:
|
||||
# branches: [ stable, dev ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
4
.github/workflows/codeql-analysis.yml
vendored
4
.github/workflows/codeql-analysis.yml
vendored
@ -3,8 +3,8 @@ name: "CodeQL"
|
||||
on:
|
||||
push:
|
||||
branches: [ stable, dev ]
|
||||
pull_request:
|
||||
branches: [ stable, dev ]
|
||||
# pull_request:
|
||||
# branches: [ stable, dev ]
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
|
30
.github/workflows/rust_custom_mutator.yml
vendored
Normal file
30
.github/workflows/rust_custom_mutator.yml
vendored
Normal 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
|
@ -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
|
||||
|
48
README.md
48
README.md
@ -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:
|
||||
|
8
TODO.md
8
TODO.md
@ -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?
|
||||
|
||||
|
18
afl-cmin
18
afl-cmin
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
#![cfg(unix)]
|
||||
#![allow(unused_variables)]
|
||||
|
||||
use custom_mutator::{export_mutator, CustomMutator};
|
||||
|
@ -1,3 +1,5 @@
|
||||
#![cfg(unix)]
|
||||
|
||||
use custom_mutator::{export_mutator, CustomMutator};
|
||||
use lain::{
|
||||
mutator::Mutator,
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 *);
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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.
|
||||
|
@ -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).
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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`
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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!
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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",
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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) {
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
||||
|
@ -1 +1 @@
|
||||
e36a30ebca
|
||||
d1ca56b84e
|
||||
|
@ -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.
|
||||
|
@ -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!"
|
||||
|
Submodule qemu_mode/qemuafl updated: e36a30ebca...d1ca56b84e
@ -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:"
|
||||
|
181
src/afl-cc.c
181
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;
|
||||
@ -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]);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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 "
|
||||
|
@ -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. */
|
||||
|
@ -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!");
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
185
src/afl-fuzz.c
185
src/afl-fuzz.c
@ -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) {
|
||||
|
@ -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:"
|
||||
|
@ -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:"
|
||||
|
@ -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
|
||||
|
@ -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
0
unicorn_mode/samples/speedtest/get_offsets.py
Normal file → Executable file
Submodule unicorn_mode/unicornafl deleted from fb2fc9f25d
@ -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]);
|
||||
|
||||
|
Reference in New Issue
Block a user