mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-24 14:43:22 +00:00
Compare commits
184 Commits
Author | SHA1 | Date | |
---|---|---|---|
2dac4e785f | |||
2b3642aa39 | |||
d68bd656fe | |||
8bd5d7676e | |||
70c1de5d64 | |||
2fef89950f | |||
a908a98225 | |||
82554677a8 | |||
dfe6f7f8c9 | |||
5fcd634f05 | |||
28f1e94ab9 | |||
e1d37a802b | |||
0f9dceff3d | |||
8868648f76 | |||
72a70423c2 | |||
84534ae2e8 | |||
687dd9cb67 | |||
ede03a96ed | |||
33dd2ce021 | |||
bc0ff559f5 | |||
090128b3f8 | |||
d7e121e2c9 | |||
749b03d812 | |||
fc73a18e9a | |||
7e67a735e6 | |||
14e1b0ffba | |||
e98cd00822 | |||
2102264acf | |||
e73c7c59c1 | |||
99525dee38 | |||
848ea17154 | |||
1cdf0a898c | |||
00913bce81 | |||
5be7d9c1cc | |||
44347beff0 | |||
166c8f93b5 | |||
9393452d1c | |||
66fa76a061 | |||
d2e7c4ec05 | |||
10fb46301c | |||
c397becd81 | |||
62508c3b44 | |||
94312796f9 | |||
adeeed9e43 | |||
513bd70384 | |||
cdd30c766b | |||
5e2a5f1110 | |||
a7797f0cb9 | |||
b715050de9 | |||
da5a32792d | |||
f36341b3b4 | |||
dda4757b35 | |||
c6f1c56c15 | |||
413807db01 | |||
f59ef29c26 | |||
65b90001f6 | |||
6840e8fd2a | |||
7c2436c711 | |||
c2df65a0af | |||
175a275a3d | |||
bd64315395 | |||
65e3770bad | |||
f5420e737a | |||
4e567d3f5d | |||
1227776251 | |||
862cb3217f | |||
8e11546536 | |||
73641be796 | |||
ff9f3fbe96 | |||
1dcc3549b6 | |||
23f7bee81c | |||
ac795ae1e1 | |||
aa6a50c2b4 | |||
01ad7610be | |||
d4fb7f8b40 | |||
61c8304f24 | |||
96574854b3 | |||
281cd47c15 | |||
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 |
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
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -65,7 +65,6 @@ qemu_mode/qemu-*
|
||||
qemu_mode/qemuafl
|
||||
unicorn_mode/samples/*/\.test-*
|
||||
unicorn_mode/samples/*/output/
|
||||
unicorn_mode/unicornafl
|
||||
test/unittests/unit_maybe_alloc
|
||||
test/unittests/unit_preallocable
|
||||
test/unittests/unit_list
|
||||
|
@ -24,7 +24,7 @@ BIN_PATH = $(PREFIX)/bin
|
||||
HELPER_PATH = $(PREFIX)/lib/afl
|
||||
DOC_PATH = $(PREFIX)/share/doc/afl
|
||||
MISC_PATH = $(PREFIX)/share/afl
|
||||
MAN_PATH = $(PREFIX)/man/man8
|
||||
MAN_PATH = $(PREFIX)/share/man/man8
|
||||
|
||||
PROGNAME = afl
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
@ -364,7 +364,6 @@ help:
|
||||
@echo NO_PYTHON - disable python support
|
||||
@echo NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
|
||||
@echo AFL_NO_X86 - if compiling on non-intel/amd platforms
|
||||
@echo NO_ARCH_OPT - builds afl++ without machine architecture optimizations
|
||||
@echo "LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g. Debian)"
|
||||
@echo "=========================================="
|
||||
@echo e.g.: make ASAN_BUILD=1
|
||||
@ -559,6 +558,7 @@ clean:
|
||||
-$(MAKE) -f GNUmakefile.gcc_plugin clean
|
||||
$(MAKE) -C utils/libdislocator clean
|
||||
$(MAKE) -C utils/libtokencap clean
|
||||
$(MAKE) -C utils/aflpp_driver clean
|
||||
$(MAKE) -C utils/afl_network_proxy clean
|
||||
$(MAKE) -C utils/socket_fuzzing clean
|
||||
$(MAKE) -C utils/argv_fuzzing clean
|
||||
@ -577,7 +577,11 @@ endif
|
||||
deepclean: clean
|
||||
rm -rf unicorn_mode/unicornafl
|
||||
rm -rf qemu_mode/qemuafl
|
||||
ifeq "$(IN_REPO)" "1"
|
||||
# NEVER EVER ACTIVATE THAT!!!!! git reset --hard >/dev/null 2>&1 || true
|
||||
git checkout unicorn_mode/unicornafl
|
||||
git checkout qemu_mode/qemuafl
|
||||
endif
|
||||
|
||||
.PHONY: distrib
|
||||
distrib: all
|
||||
|
@ -507,6 +507,8 @@ install: all
|
||||
@echo .SH LICENSE >> ./$@
|
||||
@echo Apache License Version 2.0, January 2004 >> ./$@
|
||||
@ln -sf afl-cc.8 ./afl-c++.8
|
||||
@ln -sf afl-cc.8 ./afl-clang-fast.8
|
||||
@ln -sf afl-cc.8 ./afl-clang-fast++.8
|
||||
ifneq "$(AFL_CLANG_FLTO)" ""
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
@ln -sf afl-cc.8 ./afl-clang-lto.8
|
||||
|
55
README.md
55
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.12c](https://github.com/AFLplusplus/AFLplusplus/releases)
|
||||
|
||||
Github Version: 3.11a
|
||||
Github Version: 3.13a
|
||||
|
||||
Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
||||
|
||||
@ -175,7 +175,13 @@ If you want to build afl++ yourself you have many options.
|
||||
The easiest choice is to build and install everything:
|
||||
|
||||
```shell
|
||||
sudo apt install build-essential python3-dev automake flex bison libglib2.0-dev libpixman-1-dev clang python3-setuptools clang llvm llvm-dev libstdc++-dev
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential python3-dev automake git flex bison libglib2.0-dev libpixman-1-dev python3-setuptools
|
||||
# try to install llvm 11 and install the distro default if that fails
|
||||
sudo apt-get install -y lld-11 llvm-11 llvm-11-dev clang-11 || sudo apt-get install -y lld llvm llvm-dev clang
|
||||
sudo apt-get install -y gcc-$(gcc --version|head -n1|sed 's/.* //'|sed 's/\..*//')-plugin-dev libstdc++-$(gcc --version|head -n1|sed 's/.* //'|sed 's/\..*//')-dev
|
||||
git clone https://github.com/AFLplusplus/AFLplusplus && cd AFLplusplus
|
||||
cd AFLplusplus
|
||||
make distrib
|
||||
sudo make install
|
||||
```
|
||||
@ -224,10 +230,9 @@ These build options exist:
|
||||
* NO_PYTHON - disable python support
|
||||
* NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
|
||||
* AFL_NO_X86 - if compiling on non-intel/amd platforms
|
||||
* NO_ARCH_OPT - builds afl++ without machine architecture optimizations
|
||||
* LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g. Debian)
|
||||
|
||||
e.g.: make ASAN_BUILD=1
|
||||
e.g.: `make ASAN_BUILD=1`
|
||||
|
||||
## Good examples and writeups
|
||||
|
||||
@ -239,6 +244,7 @@ Here are some good writeups to show how to effectively use AFL++:
|
||||
* [https://securitylab.github.com/research/fuzzing-software-2](https://securitylab.github.com/research/fuzzing-software-2)
|
||||
* [https://securitylab.github.com/research/fuzzing-sockets-FTP](https://securitylab.github.com/research/fuzzing-sockets-FTP)
|
||||
* [https://securitylab.github.com/research/fuzzing-sockets-FreeRDP](https://securitylab.github.com/research/fuzzing-sockets-FreeRDP)
|
||||
* [https://securitylab.github.com/research/fuzzing-apache-1](https://securitylab.github.com/research/fuzzing-apache-1)
|
||||
|
||||
If you are interested in fuzzing structured data (where you define what the
|
||||
structure is), these links have you covered:
|
||||
@ -304,7 +310,7 @@ Clickable README links for the chosen compiler:
|
||||
* [LTO mode - afl-clang-lto](instrumentation/README.lto.md)
|
||||
* [LLVM mode - afl-clang-fast](instrumentation/README.llvm.md)
|
||||
* [GCC_PLUGIN mode - afl-gcc-fast](instrumentation/README.gcc_plugin.md)
|
||||
* GCC/CLANG mode (afl-gcc/afl-clang) have no README as they have no own features
|
||||
* GCC/CLANG modes (afl-gcc/afl-clang) have no README as they have no own features
|
||||
|
||||
You can select the mode for the afl-cc compiler by:
|
||||
1. use a symlink to afl-cc: afl-gcc, afl-g++, afl-clang, afl-clang++,
|
||||
@ -399,10 +405,19 @@ How to do this is described below.
|
||||
|
||||
Then build the target. (Usually with `make`)
|
||||
|
||||
**NOTE**: sometimes configure and build systems are fickle and do not like
|
||||
stderr output (and think this means a test failure) - which is something
|
||||
afl++ like to do to show statistics. It is recommended to disable them via
|
||||
`export AFL_QUIET=1`.
|
||||
**NOTES**
|
||||
|
||||
1. sometimes configure and build systems are fickle and do not like
|
||||
stderr output (and think this means a test failure) - which is something
|
||||
afl++ likes to do to show statistics. It is recommended to disable them via
|
||||
`export AFL_QUIET=1`.
|
||||
|
||||
2. sometimes configure and build systems error on warnings - these should be
|
||||
disabled (e.g. `--disable-werror` for some configure scripts).
|
||||
|
||||
3. in case the configure/build system complains about afl++'s compiler and
|
||||
aborts then set `export AFL_NOOPT=1` which will then just behave like the
|
||||
real compiler. This option has to be unset again before building the target!
|
||||
|
||||
##### configure
|
||||
|
||||
@ -484,8 +499,9 @@ default.
|
||||
#### c) Minimizing all corpus files
|
||||
|
||||
The shorter the input files that still traverse the same path
|
||||
within the target, the better the fuzzing will be. This is done with `afl-tmin`
|
||||
however it is a long process as this has to be done for every file:
|
||||
within the target, the better the fuzzing will be. This minimization
|
||||
is done with `afl-tmin` however it is a long process as this has to
|
||||
be done for every file:
|
||||
|
||||
```
|
||||
mkdir input
|
||||
@ -536,12 +552,10 @@ If you need to stop and re-start the fuzzing, use the same command line options
|
||||
mutation mode!) and switch the input directory with a dash (`-`):
|
||||
`afl-fuzz -i - -o output -- bin/target -d @@`
|
||||
|
||||
Note that afl-fuzz enforces memory limits to prevent the system to run out
|
||||
of memory. By default this is 50MB for a process. If this is too little for
|
||||
the target (which you can usually see by afl-fuzz bailing with the message
|
||||
that it could not connect to the forkserver), then you can increase this
|
||||
with the `-m` option, the value is in MB. To disable any memory limits
|
||||
(beware!) set `-m none` - which is usually required for ASAN compiled targets.
|
||||
Memory limits are not enforced by afl-fuzz by default and the system may run
|
||||
out of memory. You can decrease the memory with the `-m` option, the value is
|
||||
in MB. If this is too small for the target, you can usually see this by
|
||||
afl-fuzz bailing with the message that it could not connect to the forkserver.
|
||||
|
||||
Adding a dictionary is helpful. See the directory [dictionaries/](dictionaries/) if
|
||||
something is already included for your data format, and tell afl-fuzz to load
|
||||
@ -554,7 +568,9 @@ afl-fuzz has a variety of options that help to workaround target quirks like
|
||||
specific locations for the input file (`-f`), not performing deterministic
|
||||
fuzzing (`-d`) and many more. Check out `afl-fuzz -h`.
|
||||
|
||||
afl-fuzz never stops fuzzing. To terminate afl++ simply press Control-C.
|
||||
By default afl-fuzz never stops fuzzing. To terminate afl++ simply press Control-C
|
||||
or send a signal SIGINT. You can limit the number of executions or approximate runtime
|
||||
in seconds with options also.
|
||||
|
||||
When you start afl-fuzz you will see a user interface that shows what the status
|
||||
is:
|
||||
@ -1168,6 +1184,7 @@ without feedback, bug reports, or patches from:
|
||||
Josephine Calliotte Konrad Welc
|
||||
Thomas Rooijakkers David Carlier
|
||||
Ruben ten Hove Joey Jiao
|
||||
fuzzah
|
||||
```
|
||||
|
||||
Thank you!
|
||||
|
9
TODO.md
9
TODO.md
@ -2,12 +2,16 @@
|
||||
|
||||
## Roadmap 3.00+
|
||||
|
||||
- AFL_MAP_SIZE for qemu_mode and unicorn_mode
|
||||
- Update afl->pending_not_fuzzed for MOpt
|
||||
- CPU affinity for many cores? There seems to be an issue > 96 cores
|
||||
- afl-plot to support multiple plot_data
|
||||
- afl_custom_fuzz_splice_optin()
|
||||
- afl_custom_splice()
|
||||
- intel-pt tracer
|
||||
- better autodetection of shifting runtime timeout values
|
||||
- cmplog: use colorization input for havoc?
|
||||
- cmplog: too much tainted bytes, directly add to dict and skip?
|
||||
|
||||
|
||||
## Further down the road
|
||||
|
||||
@ -23,9 +27,12 @@ qemu_mode:
|
||||
- add/implement AFL_QEMU_INST_LIBLIST and AFL_QEMU_NOINST_PROGRAM
|
||||
- add/implement AFL_QEMU_INST_REGIONS as a list of _START/_END addresses
|
||||
|
||||
|
||||
## Ideas
|
||||
|
||||
- LTO/sancov: write current edge to prev_loc and use that information when
|
||||
using cmplog or __sanitizer_cov_trace_cmp*. maybe we can deduct by follow
|
||||
up edge numbers that both following cmp paths have been found and then
|
||||
disable working on this edge id -> cmplog_intelligence branch
|
||||
- use cmplog colorization taint result for havoc locations?
|
||||
|
||||
|
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,58 @@
|
||||
Want to stay in the loop on major new features? Join our mailing list by
|
||||
sending a mail to <afl-users+subscribe@googlegroups.com>.
|
||||
|
||||
### Version ++3.12c (release)
|
||||
- afl-fuzz:
|
||||
- added AFL_TARGET_ENV variable to pass extra env vars to the target
|
||||
(for things like LD_LIBRARY_PATH)
|
||||
- fix map detection, AFL_MAP_SIZE not needed anymore for most cases
|
||||
- fix counting favorites (just a display thing)
|
||||
- afl-cc:
|
||||
- fix cmplog rtn (rare crash and not being able to gather ptr data)
|
||||
- fix our own PCGUARD implementation to compile with llvm 10.0.1
|
||||
- link runtime not to shared libs
|
||||
- ensure shared libraries are properly built and instrumented
|
||||
- AFL_LLVM_INSTRUMENT_ALLOW/DENY were not implemented for LTO, added
|
||||
- show correct LLVM PCGUARD NATIVE mode when auto switching to it
|
||||
and keep fsanitize-coverage-*list=...
|
||||
Short mnemnonic NATIVE is now also accepted.
|
||||
- qemu_mode (thanks @realmadsci):
|
||||
- move AFL_PRELOAD and AFL_USE_QASAN logic inside afl-qemu-trace
|
||||
- add AFL_QEMU_CUSTOM_BIN
|
||||
- unicorn_mode
|
||||
- accidently removed the subfolder from github, re-added
|
||||
- added DEFAULT_PERMISSION to config.h for all files created, default
|
||||
to 0600
|
||||
|
||||
### Version ++3.11c (release)
|
||||
- afl-fuzz:
|
||||
- better auto detection of map size
|
||||
- fix sanitizer settings (bug since 3.10c)
|
||||
- fix an off-by-one overwrite in cmplog
|
||||
- add non-unicode variants from unicode-looking dictionary entries
|
||||
- Rust custom mutator API improvements
|
||||
- Imported crash stats painted yellow on resume (only new ones are red)
|
||||
- afl-cc:
|
||||
- added AFL_NOOPT that will just pass everything to the normal
|
||||
gcc/clang compiler without any changes - to pass weird configure
|
||||
scripts
|
||||
- fixed a crash that can occur with ASAN + CMPLOG together plus
|
||||
better support for unicode (thanks to @stbergmann for reporting!)
|
||||
- fixed a crash in LAF transform for empty strings
|
||||
- handle erroneous setups in which multiple afl-compiler-rt are
|
||||
compiled into the target. This now also supports dlopen()
|
||||
instrumented libs loaded before the forkserver and even after the
|
||||
forkserver is started (then with collisions though)
|
||||
- the compiler rt was added also in object building (-c) which
|
||||
should have been fixed years ago but somewhere got lost :(
|
||||
- Renamed CTX to CALLER, added correct/real CTX implementation to
|
||||
CLASSIC
|
||||
- qemu_mode:
|
||||
- added AFL_QEMU_EXCLUDE_RANGES env by @realmadsci, thanks!
|
||||
- if no new/updated checkout is wanted, build with:
|
||||
NO_CHECKOUT=1 ./build_qemu_support.sh
|
||||
- we no longer perform a "git drop"
|
||||
- afl-cmin: support filenames with spaces
|
||||
|
||||
### Version ++3.10c (release)
|
||||
- Mac OS ARM64 support
|
||||
|
@ -26,6 +26,17 @@ Because (with the exception of the --afl-MODE command line option) the
|
||||
compile-time tools do not accept afl specific command-line options, they
|
||||
make fairly broad use of environmental variables instead:
|
||||
|
||||
- Some build/configure scripts break with afl++ compilers. To be able to
|
||||
pass them, do:
|
||||
```
|
||||
export CC=afl-cc
|
||||
export CXX=afl-c++
|
||||
export AFL_NOOPT=1
|
||||
./configure --disable-shared --disabler-werror
|
||||
unset AFL_NOOPT
|
||||
make
|
||||
```
|
||||
|
||||
- Most afl tools do not print any output if stdout/stderr are redirected.
|
||||
If you want to get the output into a file then set the `AFL_DEBUG`
|
||||
environment variable.
|
||||
@ -382,6 +393,10 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
|
||||
- In QEMU mode (-Q), `AFL_PATH` will be searched for afl-qemu-trace.
|
||||
|
||||
- In QEMU mode (-Q), setting `AFL_QEMU_CUSTOM_BIN` cause afl-fuzz to skip
|
||||
prepending `afl-qemu-trace` to your command line. Use this if you wish to use a
|
||||
custom afl-qemu-trace or if you need to modify the afl-qemu-trace arguments.
|
||||
|
||||
- Setting `AFL_CYCLE_SCHEDULES` will switch to a different schedule everytime
|
||||
a cycle is finished.
|
||||
|
||||
@ -393,6 +408,12 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
without disrupting the afl-fuzz process itself. This is useful, among other
|
||||
things, for bootstrapping libdislocator.so.
|
||||
|
||||
- Setting `AFL_TARGET_ENV` causes AFL++ to set extra environment variables
|
||||
for the target binary. Example: `AFL_TARGET_ENV="VAR1=1 VAR2='a b c'" afl-fuzz ... `
|
||||
This exists mostly for things like `LD_LIBRARY_PATH` but it would theoretically
|
||||
allow fuzzing of AFL++ itself (with 'target' AFL++ using some AFL_ vars that
|
||||
would disrupt work of 'fuzzer' AFL++).
|
||||
|
||||
- Setting `AFL_NO_UI` inhibits the UI altogether, and just periodically prints
|
||||
some basic stats. This behavior is also automatically triggered when the
|
||||
output from afl-fuzz is redirected to a file or to a pipe.
|
||||
@ -404,7 +425,8 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
no valid terminal was detected (for virtual consoles)
|
||||
|
||||
- If you are Jakub, you may need `AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES`.
|
||||
Others need not apply.
|
||||
Others need not apply, unless they also want to disable the
|
||||
`/proc/sys/kernel/core_pattern` check.
|
||||
|
||||
- Benchmarking only: `AFL_BENCH_JUST_ONE` causes the fuzzer to exit after
|
||||
processing the first queue entry; and `AFL_BENCH_UNTIL_CRASH` causes it to
|
||||
|
@ -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
|
||||
|
||||
|
@ -5,6 +5,43 @@
|
||||
"__afl_auto_init";
|
||||
"__afl_area_initial";
|
||||
"__afl_prev_loc";
|
||||
"__afl_prev_caller";
|
||||
"__afl_prev_ctx";
|
||||
"__afl_final_loc";
|
||||
"__afl_map_addr";
|
||||
"__afl_dictionary";
|
||||
"__afl_dictionary_len";
|
||||
"__afl_selective_coverage";
|
||||
"__afl_selective_coverage_start_off";
|
||||
"__afl_selective_coverage_temp";
|
||||
"__afl_coverage_discard";
|
||||
"__afl_coverage_skip";
|
||||
"__afl_coverage_on";
|
||||
"__afl_coverage_off";
|
||||
"__afl_coverage_interesting";
|
||||
"__afl_fuzz_len";
|
||||
"__afl_fuzz_ptr";
|
||||
"__sanitizer_cov_trace_pc_guard";
|
||||
"__sanitizer_cov_trace_pc_guard_init";
|
||||
"__cmplog_ins_hook1";
|
||||
"__cmplog_ins_hook2";
|
||||
"__cmplog_ins_hook4";
|
||||
"__cmplog_ins_hookN";
|
||||
"__cmplog_ins_hook16";
|
||||
"__sanitizer_cov_trace_cmp1";
|
||||
"__sanitizer_cov_trace_const_cmp1";
|
||||
"__sanitizer_cov_trace_cmp2";
|
||||
"__sanitizer_cov_trace_const_cmp2";
|
||||
"__sanitizer_cov_trace_cmp4";
|
||||
"__sanitizer_cov_trace_const_cmp4";
|
||||
"__sanitizer_cov_trace_cmp8";
|
||||
"__sanitizer_cov_trace_const_cmp8";
|
||||
"__sanitizer_cov_trace_cmp16";
|
||||
"__sanitizer_cov_trace_const_cmp16";
|
||||
"__sanitizer_cov_trace_switch";
|
||||
"__cmplog_rtn_hook";
|
||||
"__cmplog_rtn_gcc_stdstring_cstring";
|
||||
"__cmplog_rtn_gcc_stdstring_stdstring";
|
||||
"__cmplog_rtn_llvm_stdstring_cstring";
|
||||
"__cmplog_rtn_llvm_stdstring_stdstring";
|
||||
};
|
||||
|
@ -390,7 +390,7 @@ typedef struct afl_env_vars {
|
||||
*afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload,
|
||||
*afl_max_det_extras, *afl_statsd_host, *afl_statsd_port,
|
||||
*afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size,
|
||||
*afl_testcache_entries, *afl_kill_signal;
|
||||
*afl_testcache_entries, *afl_kill_signal, *afl_target_env;
|
||||
|
||||
} afl_env_vars_t;
|
||||
|
||||
@ -1062,6 +1062,7 @@ u8 has_new_bits_unclassified(afl_state_t *, u8 *);
|
||||
void load_extras_file(afl_state_t *, u8 *, u32 *, u32 *, u32);
|
||||
void load_extras(afl_state_t *, u8 *);
|
||||
void dedup_extras(afl_state_t *);
|
||||
void deunicode_extras(afl_state_t *);
|
||||
void add_extra(afl_state_t *afl, u8 *mem, u32 len);
|
||||
void maybe_add_auto(afl_state_t *, u8 *, u32);
|
||||
void save_auto(afl_state_t *);
|
||||
|
@ -48,7 +48,10 @@ void argv_cpy_free(char **argv);
|
||||
char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv);
|
||||
char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv);
|
||||
char * get_afl_env(char *env);
|
||||
u8 * get_libqasan_path(u8 *own_loc);
|
||||
|
||||
/* Extract env vars from input string and set them using setenv()
|
||||
For use with AFL_TARGET_ENV, ... */
|
||||
bool extract_and_set_env(u8 *env_str);
|
||||
|
||||
extern u8 be_quiet;
|
||||
extern u8 *doc_path; /* path to documentation dir */
|
||||
@ -58,6 +61,10 @@ extern u8 *doc_path; /* path to documentation dir */
|
||||
|
||||
u8 *find_binary(u8 *fname);
|
||||
|
||||
/* find an afl binary */
|
||||
|
||||
u8 *find_afl_binary(u8 *own_loc, u8 *fname);
|
||||
|
||||
/* Parses the kill signal environment variable, FATALs on error.
|
||||
If the env is not set, sets the env to default_signal for the signal handlers
|
||||
and returns the default_signal. */
|
||||
|
@ -26,7 +26,7 @@
|
||||
/* Version string: */
|
||||
|
||||
// c = release, a = volatile github dev, e = experimental branch
|
||||
#define VERSION "++3.10c"
|
||||
#define VERSION "++3.12c"
|
||||
|
||||
/******************************************************
|
||||
* *
|
||||
@ -34,6 +34,18 @@
|
||||
* *
|
||||
******************************************************/
|
||||
|
||||
/* Default shared memory map size. Most targets just need a coverage map
|
||||
between 20-250kb. Plus there is an auto-detection feature in afl-fuzz.
|
||||
However if a target has problematic constructors and init arrays then
|
||||
this can fail. Hence afl-fuzz deploys a larger default map. The largest
|
||||
map seen so far is the xlsx fuzzer for libreoffice which is 5MB.
|
||||
At runtime this value can be overriden via AFL_MAP_SIZE.
|
||||
Default: 8MB (defined in bytes) */
|
||||
#define DEFAULT_SHMEM_SIZE (8 * 1024 * 1024)
|
||||
|
||||
/* Default file permission umode when creating files (default: 0600) */
|
||||
#define DEFAULT_PERMISSION 0600
|
||||
|
||||
/* CMPLOG/REDQUEEN TUNING
|
||||
*
|
||||
* Here you can modify tuning and solving options for CMPLOG.
|
||||
@ -54,10 +66,10 @@
|
||||
|
||||
/* Number of potential positions from which we decide if cmplog becomes
|
||||
useless, default 8096 */
|
||||
#define CMPLOG_POSITIONS_MAX 8096U
|
||||
#define CMPLOG_POSITIONS_MAX (12 * 1024)
|
||||
|
||||
/* Maximum allowed fails per CMP value. Default: 128 */
|
||||
#define CMPLOG_FAIL_MAX 128
|
||||
#define CMPLOG_FAIL_MAX 96
|
||||
|
||||
/* Now non-cmplog configuration options */
|
||||
|
||||
|
@ -42,6 +42,7 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_DEBUG_CHILD",
|
||||
"AFL_DEBUG_GDB",
|
||||
"AFL_DISABLE_TRIM",
|
||||
"AFL_DISABLE_LLVM_INSTRUMENTATION",
|
||||
"AFL_DONT_OPTIMIZE",
|
||||
"AFL_DRIVER_STDERR_DUPLICATE_FILENAME",
|
||||
"AFL_DUMB_FORKSRV",
|
||||
@ -50,6 +51,7 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_FAST_CAL",
|
||||
"AFL_FORCE_UI",
|
||||
"AFL_FUZZER_ARGS", // oss-fuzz
|
||||
"AFL_GDB",
|
||||
"AFL_GCC_ALLOWLIST",
|
||||
"AFL_GCC_DENYLIST",
|
||||
"AFL_GCC_BLOCKLIST",
|
||||
@ -80,7 +82,9 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_LLVM_BLOCKLIST",
|
||||
"AFL_LLVM_CMPLOG",
|
||||
"AFL_LLVM_INSTRIM",
|
||||
"AFL_LLVM_CALLER",
|
||||
"AFL_LLVM_CTX",
|
||||
"AFL_LLVM_CTX_K",
|
||||
"AFL_LLVM_DICT2FILE",
|
||||
"AFL_LLVM_DOCUMENT_IDS",
|
||||
"AFL_LLVM_INSTRIM_LOOPHEAD",
|
||||
@ -118,14 +122,18 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_NO_PYTHON",
|
||||
"AFL_UNTRACER_FILE",
|
||||
"AFL_LLVM_USE_TRACE_PC",
|
||||
"AFL_NO_X86", // not really an env but we dont want to warn on it
|
||||
"AFL_MAP_SIZE",
|
||||
"AFL_MAPSIZE",
|
||||
"AFL_MAX_DET_EXTRAS",
|
||||
"AFL_NO_X86", // not really an env but we dont want to warn on it
|
||||
"AFL_NOOPT",
|
||||
"AFL_PASSTHROUGH",
|
||||
"AFL_PATH",
|
||||
"AFL_PERFORMANCE_FILE",
|
||||
"AFL_PRELOAD",
|
||||
"AFL_TARGET_ENV",
|
||||
"AFL_PYTHON_MODULE",
|
||||
"AFL_QEMU_CUSTOM_BIN",
|
||||
"AFL_QEMU_COMPCOV",
|
||||
"AFL_QEMU_COMPCOV_DEBUG",
|
||||
"AFL_QEMU_DEBUG_MAPS",
|
||||
@ -141,6 +149,7 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_QEMU_PERSISTENT_RETADDR_OFFSET",
|
||||
"AFL_QEMU_PERSISTENT_EXITS",
|
||||
"AFL_QEMU_INST_RANGES",
|
||||
"AFL_QEMU_EXCLUDE_RANGES",
|
||||
"AFL_QEMU_SNAPSHOT",
|
||||
"AFL_QUIET",
|
||||
"AFL_RANDOM_ALLOC_CANARY",
|
||||
|
@ -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).
|
||||
|
@ -113,7 +113,7 @@ cmake \
|
||||
-DLLVM_LINK_LLVM_DYLIB="ON" \
|
||||
-DLLVM_TARGETS_TO_BUILD="host" \
|
||||
../llvm/
|
||||
cmake --build . --parallel
|
||||
cmake --build . -j4
|
||||
export PATH="$(pwd)/bin:$PATH"
|
||||
export LLVM_CONFIG="$(pwd)/bin/llvm-config"
|
||||
export LD_LIBRARY_PATH="$(llvm-config --libdir)${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
|
||||
|
@ -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!
|
||||
|
@ -507,6 +507,7 @@ bool ModuleSanitizerCoverage::instrumentModule(
|
||||
Zero = ConstantInt::get(Int8Tyi, 0);
|
||||
One = ConstantInt::get(Int8Tyi, 1);
|
||||
|
||||
initInstrumentList();
|
||||
scanForDangerousFunctions(&M);
|
||||
Mo = &M;
|
||||
|
||||
@ -733,7 +734,7 @@ bool ModuleSanitizerCoverage::instrumentModule(
|
||||
Var->getInitializer())) {
|
||||
|
||||
HasStr2 = true;
|
||||
Str2 = Array->getAsString().str();
|
||||
Str2 = Array->getRawDataValues().str();
|
||||
|
||||
}
|
||||
|
||||
@ -809,7 +810,7 @@ bool ModuleSanitizerCoverage::instrumentModule(
|
||||
Var->getInitializer())) {
|
||||
|
||||
HasStr1 = true;
|
||||
Str1 = Array->getAsString().str();
|
||||
Str1 = Array->getRawDataValues().str();
|
||||
|
||||
}
|
||||
|
||||
@ -849,15 +850,18 @@ bool ModuleSanitizerCoverage::instrumentModule(
|
||||
thestring = Str2;
|
||||
|
||||
optLen = thestring.length();
|
||||
if (optLen < 2 || (optLen == 2 && !thestring[1])) { continue; }
|
||||
|
||||
if (isMemcmp || isStrncmp || isStrncasecmp) {
|
||||
|
||||
Value * op2 = callInst->getArgOperand(2);
|
||||
ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
|
||||
|
||||
if (ilen) {
|
||||
|
||||
uint64_t literalLength = optLen;
|
||||
optLen = ilen->getZExtValue();
|
||||
if (optLen < 2) { continue; }
|
||||
if (literalLength + 1 == optLen) { // add null byte
|
||||
thestring.append("\0", 1);
|
||||
addedNull = true;
|
||||
@ -872,17 +876,21 @@ bool ModuleSanitizerCoverage::instrumentModule(
|
||||
// was not already added
|
||||
if (!isMemcmp) {
|
||||
|
||||
if (addedNull == false) {
|
||||
if (addedNull == false && thestring[optLen - 1] != '\0') {
|
||||
|
||||
thestring.append("\0", 1); // add null byte
|
||||
optLen++;
|
||||
|
||||
}
|
||||
|
||||
// ensure we do not have garbage
|
||||
size_t offset = thestring.find('\0', 0);
|
||||
if (offset + 1 < optLen) optLen = offset + 1;
|
||||
thestring = thestring.substr(0, optLen);
|
||||
if (!isStdString) {
|
||||
|
||||
// ensure we do not have garbage
|
||||
size_t offset = thestring.find('\0', 0);
|
||||
if (offset + 1 < optLen) optLen = offset + 1;
|
||||
thestring = thestring.substr(0, optLen);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1222,7 +1230,7 @@ void ModuleSanitizerCoverage::instrumentFunction(
|
||||
|
||||
// afl++ START
|
||||
if (!F.size()) return;
|
||||
if (isIgnoreFunction(&F)) return;
|
||||
if (!isInInstrumentList(&F)) return;
|
||||
// afl++ END
|
||||
|
||||
if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge)
|
||||
@ -1284,10 +1292,17 @@ GlobalVariable *ModuleSanitizerCoverage::CreateFunctionLocalArrayInSection(
|
||||
*CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage,
|
||||
Constant::getNullValue(ArrayTy), "__sancov_gen_");
|
||||
|
||||
#if LLVM_VERSION_MAJOR > 12
|
||||
if (TargetTriple.supportsCOMDAT() &&
|
||||
(TargetTriple.isOSBinFormatELF() || !F.isInterposable()))
|
||||
if (auto Comdat = getOrCreateFunctionComdat(F, TargetTriple))
|
||||
Array->setComdat(Comdat);
|
||||
#else
|
||||
if (TargetTriple.supportsCOMDAT() && !F.isInterposable())
|
||||
if (auto Comdat =
|
||||
GetOrCreateFunctionComdat(F, TargetTriple, CurModuleUniqueId))
|
||||
Array->setComdat(Comdat);
|
||||
#endif
|
||||
Array->setSection(getSectionName(Section));
|
||||
Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedSize()));
|
||||
GlobalsToAppendToUsed.push_back(Array);
|
||||
|
@ -10,6 +10,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Analysis/EHPersonalities.h"
|
||||
@ -34,11 +35,11 @@
|
||||
#include "llvm/InitializePasses.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/SpecialCaseList.h"
|
||||
#if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0)
|
||||
#include "llvm/Support/VirtualFileSystem.h"
|
||||
#endif
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Transforms/Instrumentation.h"
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Transforms/Utils/ModuleUtils.h"
|
||||
@ -47,65 +48,6 @@
|
||||
#include "debug.h"
|
||||
#include "afl-llvm-common.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// This is the ModuleSanitizerCoverage pass used in the new pass manager. The
|
||||
/// pass instruments functions for coverage, adds initialization calls to the
|
||||
/// module for trace PC guards and 8bit counters if they are requested, and
|
||||
/// appends globals to llvm.compiler.used.
|
||||
class ModuleSanitizerCoveragePass
|
||||
: public PassInfoMixin<ModuleSanitizerCoveragePass> {
|
||||
|
||||
public:
|
||||
explicit ModuleSanitizerCoveragePass(
|
||||
SanitizerCoverageOptions Options = SanitizerCoverageOptions(),
|
||||
const std::vector<std::string> &AllowlistFiles =
|
||||
std::vector<std::string>(),
|
||||
const std::vector<std::string> &BlocklistFiles =
|
||||
std::vector<std::string>())
|
||||
: Options(Options) {
|
||||
|
||||
if (AllowlistFiles.size() > 0)
|
||||
Allowlist = SpecialCaseList::createOrDie(AllowlistFiles
|
||||
#if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0)
|
||||
,
|
||||
*vfs::getRealFileSystem()
|
||||
#endif
|
||||
);
|
||||
if (BlocklistFiles.size() > 0)
|
||||
Blocklist = SpecialCaseList::createOrDie(BlocklistFiles
|
||||
#if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0)
|
||||
,
|
||||
*vfs::getRealFileSystem()
|
||||
#endif
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
|
||||
static bool isRequired() {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
SanitizerCoverageOptions Options;
|
||||
|
||||
std::unique_ptr<SpecialCaseList> Allowlist;
|
||||
std::unique_ptr<SpecialCaseList> Blocklist;
|
||||
|
||||
};
|
||||
|
||||
// Insert SanitizerCoverage instrumentation.
|
||||
ModulePass *createModuleSanitizerCoverageLegacyPassPass(
|
||||
const SanitizerCoverageOptions &Options = SanitizerCoverageOptions(),
|
||||
const std::vector<std::string> &AllowlistFiles = std::vector<std::string>(),
|
||||
const std::vector<std::string> &BlocklistFiles =
|
||||
std::vector<std::string>());
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "sancov"
|
||||
@ -156,96 +98,8 @@ static const char *const SanCovLowestStackName = "__sancov_lowest_stack";
|
||||
|
||||
static char *skip_nozero;
|
||||
|
||||
/*
|
||||
static cl::opt<int> ClCoverageLevel(
|
||||
"sanitizer-coverage-level",
|
||||
cl::desc("Sanitizer Coverage. 0: none, 1: entry block, 2: all blocks, "
|
||||
"3: all blocks and critical edges"),
|
||||
cl::Hidden, cl::init(3));
|
||||
|
||||
static cl::opt<bool> ClTracePC("sanitizer-coverage-trace-pc",
|
||||
cl::desc("Experimental pc tracing"), cl::Hidden,
|
||||
cl::init(false));
|
||||
|
||||
static cl::opt<bool> ClTracePCGuard("sanitizer-coverage-trace-pc-guard",
|
||||
cl::desc("pc tracing with a guard"),
|
||||
cl::Hidden, cl::init(true));
|
||||
|
||||
// If true, we create a global variable that contains PCs of all instrumented
|
||||
// BBs, put this global into a named section, and pass this section's bounds
|
||||
// to __sanitizer_cov_pcs_init.
|
||||
// This way the coverage instrumentation does not need to acquire the PCs
|
||||
// at run-time. Works with trace-pc-guard, inline-8bit-counters, and
|
||||
// inline-bool-flag.
|
||||
static cl::opt<bool> ClCreatePCTable("sanitizer-coverage-pc-table",
|
||||
cl::desc("create a static PC table"),
|
||||
cl::Hidden, cl::init(false));
|
||||
|
||||
static cl::opt<bool> ClInline8bitCounters(
|
||||
"sanitizer-coverage-inline-8bit-counters",
|
||||
cl::desc("increments 8-bit counter for every edge"), cl::Hidden,
|
||||
cl::init(false));
|
||||
|
||||
static cl::opt<bool> ClInlineBoolFlag(
|
||||
"sanitizer-coverage-inline-bool-flag",
|
||||
cl::desc("sets a boolean flag for every edge"), cl::Hidden,
|
||||
cl::init(false));
|
||||
|
||||
static cl::opt<bool> ClCMPTracing(
|
||||
"sanitizer-coverage-trace-compares",
|
||||
cl::desc("Tracing of CMP and similar instructions"), cl::Hidden,
|
||||
cl::init(false));
|
||||
|
||||
static cl::opt<bool> ClDIVTracing("sanitizer-coverage-trace-divs",
|
||||
cl::desc("Tracing of DIV instructions"),
|
||||
cl::Hidden, cl::init(false));
|
||||
|
||||
static cl::opt<bool> ClGEPTracing("sanitizer-coverage-trace-geps",
|
||||
cl::desc("Tracing of GEP instructions"),
|
||||
cl::Hidden, cl::init(false));
|
||||
|
||||
static cl::opt<bool> ClPruneBlocks(
|
||||
"sanitizer-coverage-prune-blocks",
|
||||
cl::desc("Reduce the number of instrumented blocks"), cl::Hidden,
|
||||
cl::init(true));
|
||||
|
||||
static cl::opt<bool> ClStackDepth("sanitizer-coverage-stack-depth",
|
||||
cl::desc("max stack depth tracing"),
|
||||
cl::Hidden, cl::init(false));
|
||||
*/
|
||||
namespace {
|
||||
|
||||
/*
|
||||
SanitizerCoverageOptions getOptions(int LegacyCoverageLevel) {
|
||||
|
||||
SanitizerCoverageOptions Res;
|
||||
switch (LegacyCoverageLevel) {
|
||||
|
||||
case 0:
|
||||
Res.CoverageType = SanitizerCoverageOptions::SCK_None;
|
||||
break;
|
||||
case 1:
|
||||
Res.CoverageType = SanitizerCoverageOptions::SCK_Function;
|
||||
break;
|
||||
case 2:
|
||||
Res.CoverageType = SanitizerCoverageOptions::SCK_BB;
|
||||
break;
|
||||
case 3:
|
||||
Res.CoverageType = SanitizerCoverageOptions::SCK_Edge;
|
||||
break;
|
||||
case 4:
|
||||
Res.CoverageType = SanitizerCoverageOptions::SCK_Edge;
|
||||
Res.IndirectCalls = true;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return Res;
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) {
|
||||
|
||||
// Sets CoverageType and IndirectCalls.
|
||||
@ -281,12 +135,14 @@ class ModuleSanitizerCoverage {
|
||||
|
||||
public:
|
||||
ModuleSanitizerCoverage(
|
||||
const SanitizerCoverageOptions &Options = SanitizerCoverageOptions(),
|
||||
const SpecialCaseList * Allowlist = nullptr,
|
||||
const SpecialCaseList * Blocklist = nullptr)
|
||||
: Options(OverrideFromCL(Options)),
|
||||
Allowlist(Allowlist),
|
||||
Blocklist(Blocklist) {
|
||||
const SanitizerCoverageOptions &Options = SanitizerCoverageOptions()
|
||||
#if LLVM_MAJOR > 10
|
||||
,
|
||||
const SpecialCaseList *Allowlist = nullptr,
|
||||
const SpecialCaseList *Blocklist = nullptr
|
||||
#endif
|
||||
)
|
||||
: Options(OverrideFromCL(Options)) {
|
||||
|
||||
}
|
||||
|
||||
@ -356,9 +212,6 @@ class ModuleSanitizerCoverage {
|
||||
|
||||
SanitizerCoverageOptions Options;
|
||||
|
||||
const SpecialCaseList *Allowlist;
|
||||
const SpecialCaseList *Blocklist;
|
||||
|
||||
uint32_t instr = 0;
|
||||
GlobalVariable *AFLMapPtr = NULL;
|
||||
ConstantInt * One = NULL;
|
||||
@ -370,27 +223,17 @@ class ModuleSanitizerCoverageLegacyPass : public ModulePass {
|
||||
|
||||
public:
|
||||
ModuleSanitizerCoverageLegacyPass(
|
||||
const SanitizerCoverageOptions &Options = SanitizerCoverageOptions(),
|
||||
const SanitizerCoverageOptions &Options = SanitizerCoverageOptions()
|
||||
#if LLVM_VERSION_MAJOR > 10
|
||||
,
|
||||
const std::vector<std::string> &AllowlistFiles =
|
||||
std::vector<std::string>(),
|
||||
const std::vector<std::string> &BlocklistFiles =
|
||||
std::vector<std::string>())
|
||||
std::vector<std::string>()
|
||||
#endif
|
||||
)
|
||||
: ModulePass(ID), Options(Options) {
|
||||
|
||||
if (AllowlistFiles.size() > 0)
|
||||
Allowlist = SpecialCaseList::createOrDie(AllowlistFiles
|
||||
#if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0)
|
||||
,
|
||||
*vfs::getRealFileSystem()
|
||||
#endif
|
||||
);
|
||||
if (BlocklistFiles.size() > 0)
|
||||
Blocklist = SpecialCaseList::createOrDie(BlocklistFiles
|
||||
#if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0)
|
||||
,
|
||||
*vfs::getRealFileSystem()
|
||||
#endif
|
||||
);
|
||||
initializeModuleSanitizerCoverageLegacyPassPass(
|
||||
*PassRegistry::getPassRegistry());
|
||||
|
||||
@ -398,8 +241,12 @@ class ModuleSanitizerCoverageLegacyPass : public ModulePass {
|
||||
|
||||
bool runOnModule(Module &M) override {
|
||||
|
||||
ModuleSanitizerCoverage ModuleSancov(Options, Allowlist.get(),
|
||||
Blocklist.get());
|
||||
ModuleSanitizerCoverage ModuleSancov(Options
|
||||
#if LLVM_MAJOR > 10
|
||||
,
|
||||
Allowlist.get(), Blocklist.get()
|
||||
#endif
|
||||
);
|
||||
auto DTCallback = [this](Function &F) -> const DominatorTree * {
|
||||
|
||||
return &this->getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
|
||||
@ -444,8 +291,12 @@ class ModuleSanitizerCoverageLegacyPass : public ModulePass {
|
||||
PreservedAnalyses ModuleSanitizerCoveragePass::run(Module & M,
|
||||
ModuleAnalysisManager &MAM) {
|
||||
|
||||
ModuleSanitizerCoverage ModuleSancov(Options, Allowlist.get(),
|
||||
Blocklist.get());
|
||||
ModuleSanitizerCoverage ModuleSancov(Options
|
||||
#if LLVM_MAJOR > 10
|
||||
,
|
||||
Allowlist.get(), Blocklist.get()
|
||||
#endif
|
||||
);
|
||||
auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
|
||||
auto DTCallback = [&FAM](Function &F) -> const DominatorTree * {
|
||||
|
||||
@ -564,12 +415,6 @@ bool ModuleSanitizerCoverage::instrumentModule(
|
||||
}
|
||||
|
||||
if (Options.CoverageType == SanitizerCoverageOptions::SCK_None) return false;
|
||||
if (Allowlist &&
|
||||
!Allowlist->inSection("coverage", "src", M.getSourceFileName()))
|
||||
return false;
|
||||
if (Blocklist &&
|
||||
Blocklist->inSection("coverage", "src", M.getSourceFileName()))
|
||||
return false;
|
||||
C = &(M.getContext());
|
||||
DL = &M.getDataLayout();
|
||||
CurModule = &M;
|
||||
@ -842,9 +687,6 @@ void ModuleSanitizerCoverage::instrumentFunction(
|
||||
if (F.hasPersonalityFn() &&
|
||||
isAsynchronousEHPersonality(classifyEHPersonality(F.getPersonalityFn())))
|
||||
return;
|
||||
if (Allowlist && !Allowlist->inSection("coverage", "fun", F.getName()))
|
||||
return;
|
||||
if (Blocklist && Blocklist->inSection("coverage", "fun", F.getName())) return;
|
||||
if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge)
|
||||
SplitAllCriticalEdges(
|
||||
F, CriticalEdgeSplittingOptions().setIgnoreUnreachableDests());
|
||||
@ -915,10 +757,18 @@ GlobalVariable *ModuleSanitizerCoverage::CreateFunctionLocalArrayInSection(
|
||||
*CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage,
|
||||
Constant::getNullValue(ArrayTy), "__sancov_gen_");
|
||||
|
||||
#if LLVM_VERSION_MAJOR > 12
|
||||
if (TargetTriple.supportsCOMDAT() &&
|
||||
(TargetTriple.isOSBinFormatELF() || !F.isInterposable()))
|
||||
if (auto Comdat = getOrCreateFunctionComdat(F, TargetTriple))
|
||||
Array->setComdat(Comdat);
|
||||
#else
|
||||
if (TargetTriple.supportsCOMDAT() && !F.isInterposable())
|
||||
if (auto Comdat =
|
||||
GetOrCreateFunctionComdat(F, TargetTriple, CurModuleUniqueId))
|
||||
Array->setComdat(Comdat);
|
||||
#endif
|
||||
|
||||
Array->setSection(getSectionName(Section));
|
||||
#if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0)
|
||||
Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedSize()));
|
||||
@ -1354,12 +1204,20 @@ INITIALIZE_PASS_END(ModuleSanitizerCoverageLegacyPass, "sancov",
|
||||
false)
|
||||
|
||||
ModulePass *llvm::createModuleSanitizerCoverageLegacyPassPass(
|
||||
const SanitizerCoverageOptions &Options,
|
||||
const SanitizerCoverageOptions &Options
|
||||
#if LLVM_MAJOR > 10
|
||||
,
|
||||
const std::vector<std::string> &AllowlistFiles,
|
||||
const std::vector<std::string> &BlocklistFiles) {
|
||||
const std::vector<std::string> &BlocklistFiles
|
||||
#endif
|
||||
) {
|
||||
|
||||
return new ModuleSanitizerCoverageLegacyPass(Options, AllowlistFiles,
|
||||
BlocklistFiles);
|
||||
return new ModuleSanitizerCoverageLegacyPass(Options
|
||||
#if LLVM_MAJOR > 10
|
||||
,
|
||||
AllowlistFiles, BlocklistFiles
|
||||
#endif
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "cmplog.h"
|
||||
#include "llvm-ngram-coverage.h"
|
||||
#include "llvm-alternative-coverage.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -34,6 +34,7 @@
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/syscall.h>
|
||||
#ifndef __HAIKU__
|
||||
#include <sys/shm.h>
|
||||
#endif
|
||||
@ -96,10 +97,12 @@ int __afl_selective_coverage_temp = 1;
|
||||
|
||||
#if defined(__ANDROID__) || defined(__HAIKU__)
|
||||
PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX];
|
||||
PREV_LOC_T __afl_prev_caller[CTX_MAX_K];
|
||||
u32 __afl_prev_ctx;
|
||||
u32 __afl_cmp_counter;
|
||||
#else
|
||||
__thread PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX];
|
||||
__thread PREV_LOC_T __afl_prev_caller[CTX_MAX_K];
|
||||
__thread u32 __afl_prev_ctx;
|
||||
__thread u32 __afl_cmp_counter;
|
||||
#endif
|
||||
@ -122,6 +125,21 @@ static u8 is_persistent;
|
||||
|
||||
static u8 _is_sancov;
|
||||
|
||||
/* Debug? */
|
||||
|
||||
static u32 __afl_debug;
|
||||
|
||||
/* Already initialized markers */
|
||||
|
||||
u32 __afl_already_initialized_shm;
|
||||
u32 __afl_already_initialized_forkserver;
|
||||
u32 __afl_already_initialized_first;
|
||||
u32 __afl_already_initialized_second;
|
||||
|
||||
/* Dummy pipe for area_is_valid() */
|
||||
|
||||
static int __afl_dummy_fd[2] = {2, 2};
|
||||
|
||||
/* ensure we kill the child on termination */
|
||||
|
||||
void at_exit(int signal) {
|
||||
@ -171,7 +189,7 @@ static void __afl_map_shm_fuzz() {
|
||||
|
||||
char *id_str = getenv(SHM_FUZZ_ENV_VAR);
|
||||
|
||||
if (getenv("AFL_DEBUG")) {
|
||||
if (__afl_debug) {
|
||||
|
||||
fprintf(stderr, "DEBUG: fuzzcase shmem %s\n", id_str ? id_str : "none");
|
||||
|
||||
@ -186,7 +204,7 @@ static void __afl_map_shm_fuzz() {
|
||||
int shm_fd = -1;
|
||||
|
||||
/* create the shared memory segment as if it was a file */
|
||||
shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
|
||||
shm_fd = shm_open(shm_file_path, O_RDWR, DEFAULT_PERMISSION);
|
||||
if (shm_fd == -1) {
|
||||
|
||||
fprintf(stderr, "shm_open() failed for fuzz\n");
|
||||
@ -217,7 +235,7 @@ static void __afl_map_shm_fuzz() {
|
||||
__afl_fuzz_len = (u32 *)map;
|
||||
__afl_fuzz_ptr = map + sizeof(u32);
|
||||
|
||||
if (getenv("AFL_DEBUG")) {
|
||||
if (__afl_debug) {
|
||||
|
||||
fprintf(stderr, "DEBUG: successfully got fuzzing shared memory\n");
|
||||
|
||||
@ -237,6 +255,9 @@ static void __afl_map_shm_fuzz() {
|
||||
|
||||
static void __afl_map_shm(void) {
|
||||
|
||||
if (__afl_already_initialized_shm) return;
|
||||
__afl_already_initialized_shm = 1;
|
||||
|
||||
// if we are not running in afl ensure the map exists
|
||||
if (!__afl_area_ptr) { __afl_area_ptr = __afl_area_ptr_dummy; }
|
||||
|
||||
@ -294,18 +315,23 @@ static void __afl_map_shm(void) {
|
||||
early-stage __afl_area_initial region that is needed to allow some really
|
||||
hacky .init code to work correctly in projects such as OpenSSL. */
|
||||
|
||||
if (getenv("AFL_DEBUG"))
|
||||
if (__afl_debug) {
|
||||
|
||||
fprintf(stderr,
|
||||
"DEBUG: id_str %s, __afl_area_ptr %p, __afl_area_initial %p, "
|
||||
"__afl_map_addr 0x%llx, MAP_SIZE %u, __afl_final_loc %u, "
|
||||
"DEBUG: (1) id_str %s, __afl_area_ptr %p, __afl_area_initial %p, "
|
||||
"__afl_area_ptr_dummy 0x%p, __afl_map_addr 0x%llx, MAP_SIZE %u, "
|
||||
"__afl_final_loc %u, "
|
||||
"max_size_forkserver %u/0x%x\n",
|
||||
id_str == NULL ? "<null>" : id_str, __afl_area_ptr,
|
||||
__afl_area_initial, __afl_map_addr, MAP_SIZE, __afl_final_loc,
|
||||
FS_OPT_MAX_MAPSIZE, FS_OPT_MAX_MAPSIZE);
|
||||
__afl_area_initial, __afl_area_ptr_dummy, __afl_map_addr, MAP_SIZE,
|
||||
__afl_final_loc, FS_OPT_MAX_MAPSIZE, FS_OPT_MAX_MAPSIZE);
|
||||
|
||||
}
|
||||
|
||||
if (id_str) {
|
||||
|
||||
if (__afl_area_ptr && __afl_area_ptr != __afl_area_initial) {
|
||||
if (__afl_area_ptr && __afl_area_ptr != __afl_area_initial &&
|
||||
__afl_area_ptr != __afl_area_ptr_dummy) {
|
||||
|
||||
if (__afl_map_addr) {
|
||||
|
||||
@ -327,7 +353,7 @@ static void __afl_map_shm(void) {
|
||||
unsigned char *shm_base = NULL;
|
||||
|
||||
/* create the shared memory segment as if it was a file */
|
||||
shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
|
||||
shm_fd = shm_open(shm_file_path, O_RDWR, DEFAULT_PERMISSION);
|
||||
if (shm_fd == -1) {
|
||||
|
||||
fprintf(stderr, "shm_open() failed\n");
|
||||
@ -350,17 +376,18 @@ static void __afl_map_shm(void) {
|
||||
|
||||
}
|
||||
|
||||
close(shm_fd);
|
||||
shm_fd = -1;
|
||||
|
||||
if (shm_base == MAP_FAILED) {
|
||||
|
||||
close(shm_fd);
|
||||
shm_fd = -1;
|
||||
|
||||
fprintf(stderr, "mmap() failed\n");
|
||||
perror("mmap for map");
|
||||
|
||||
if (__afl_map_addr)
|
||||
send_forkserver_error(FS_ERROR_MAP_ADDR);
|
||||
else
|
||||
send_forkserver_error(FS_ERROR_MMAP);
|
||||
perror("mmap for map");
|
||||
|
||||
exit(2);
|
||||
|
||||
@ -439,6 +466,19 @@ static void __afl_map_shm(void) {
|
||||
|
||||
__afl_area_ptr_backup = __afl_area_ptr;
|
||||
|
||||
if (__afl_debug) {
|
||||
|
||||
fprintf(stderr,
|
||||
"DEBUG: (2) id_str %s, __afl_area_ptr %p, __afl_area_initial %p, "
|
||||
"__afl_area_ptr_dummy 0x%p, __afl_map_addr 0x%llx, MAP_SIZE "
|
||||
"%u, __afl_final_loc %u, "
|
||||
"max_size_forkserver %u/0x%x\n",
|
||||
id_str == NULL ? "<null>" : id_str, __afl_area_ptr,
|
||||
__afl_area_initial, __afl_area_ptr_dummy, __afl_map_addr, MAP_SIZE,
|
||||
__afl_final_loc, FS_OPT_MAX_MAPSIZE, FS_OPT_MAX_MAPSIZE);
|
||||
|
||||
}
|
||||
|
||||
if (__afl_selective_coverage) {
|
||||
|
||||
if (__afl_map_size > MAP_INITIAL_SIZE) {
|
||||
@ -467,7 +507,7 @@ static void __afl_map_shm(void) {
|
||||
|
||||
id_str = getenv(CMPLOG_SHM_ENV_VAR);
|
||||
|
||||
if (getenv("AFL_DEBUG")) {
|
||||
if (__afl_debug) {
|
||||
|
||||
fprintf(stderr, "DEBUG: cmplog id_str %s\n",
|
||||
id_str == NULL ? "<null>" : id_str);
|
||||
@ -476,13 +516,19 @@ static void __afl_map_shm(void) {
|
||||
|
||||
if (id_str) {
|
||||
|
||||
if ((__afl_dummy_fd[1] = open("/dev/null", O_WRONLY)) < 0) {
|
||||
|
||||
if (pipe(__afl_dummy_fd) < 0) { __afl_dummy_fd[1] = 1; }
|
||||
|
||||
}
|
||||
|
||||
#ifdef USEMMAP
|
||||
const char * shm_file_path = id_str;
|
||||
int shm_fd = -1;
|
||||
struct cmp_map *shm_base = NULL;
|
||||
|
||||
/* create the shared memory segment as if it was a file */
|
||||
shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
|
||||
shm_fd = shm_open(shm_file_path, O_RDWR, DEFAULT_PERMISSION);
|
||||
if (shm_fd == -1) {
|
||||
|
||||
perror("shm_open() failed\n");
|
||||
@ -526,6 +572,58 @@ static void __afl_map_shm(void) {
|
||||
|
||||
}
|
||||
|
||||
/* unmap SHM. */
|
||||
|
||||
static void __afl_unmap_shm(void) {
|
||||
|
||||
if (!__afl_already_initialized_shm) return;
|
||||
|
||||
char *id_str = getenv(SHM_ENV_VAR);
|
||||
|
||||
if (id_str) {
|
||||
|
||||
#ifdef USEMMAP
|
||||
|
||||
munmap((void *)__afl_area_ptr, __afl_map_size);
|
||||
|
||||
#else
|
||||
|
||||
shmdt((void *)__afl_area_ptr);
|
||||
|
||||
#endif
|
||||
|
||||
} else if ((!__afl_area_ptr || __afl_area_ptr == __afl_area_initial) &&
|
||||
|
||||
__afl_map_addr) {
|
||||
|
||||
munmap((void *)__afl_map_addr, __afl_map_size);
|
||||
|
||||
}
|
||||
|
||||
__afl_area_ptr = __afl_area_ptr_dummy;
|
||||
|
||||
id_str = getenv(CMPLOG_SHM_ENV_VAR);
|
||||
|
||||
if (id_str) {
|
||||
|
||||
#ifdef USEMMAP
|
||||
|
||||
munmap((void *)__afl_cmp_map, __afl_map_size);
|
||||
|
||||
#else
|
||||
|
||||
shmdt((void *)__afl_cmp_map);
|
||||
|
||||
#endif
|
||||
|
||||
__afl_cmp_map = NULL;
|
||||
|
||||
}
|
||||
|
||||
__afl_already_initialized_shm = 0;
|
||||
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
static void __afl_start_snapshots(void) {
|
||||
|
||||
@ -554,7 +652,7 @@ static void __afl_start_snapshots(void) {
|
||||
|
||||
if (read(FORKSRV_FD, &was_killed, 4) != 4) { _exit(1); }
|
||||
|
||||
if (getenv("AFL_DEBUG")) {
|
||||
if (__afl_debug) {
|
||||
|
||||
fprintf(stderr, "target forkserver recv: %08x\n", was_killed);
|
||||
|
||||
@ -631,7 +729,7 @@ static void __afl_start_snapshots(void) {
|
||||
static uint32_t counter = 0;
|
||||
char fn[32];
|
||||
sprintf(fn, "%09u:forkserver", counter);
|
||||
s32 fd_doc = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||
s32 fd_doc = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
|
||||
if (fd_doc >= 0) {
|
||||
|
||||
if (write(fd_doc, __afl_fuzz_ptr, *__afl_fuzz_len) != *__afl_fuzz_len) {
|
||||
@ -731,6 +829,9 @@ static void __afl_start_snapshots(void) {
|
||||
|
||||
static void __afl_start_forkserver(void) {
|
||||
|
||||
if (__afl_already_initialized_forkserver) return;
|
||||
__afl_already_initialized_forkserver = 1;
|
||||
|
||||
struct sigaction orig_action;
|
||||
sigaction(SIGTERM, NULL, &orig_action);
|
||||
old_sigterm_handler = orig_action.sa_handler;
|
||||
@ -781,7 +882,7 @@ static void __afl_start_forkserver(void) {
|
||||
|
||||
if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
|
||||
|
||||
if (getenv("AFL_DEBUG")) {
|
||||
if (__afl_debug) {
|
||||
|
||||
fprintf(stderr, "target forkserver recv: %08x\n", was_killed);
|
||||
|
||||
@ -859,7 +960,7 @@ static void __afl_start_forkserver(void) {
|
||||
static uint32_t counter = 0;
|
||||
char fn[32];
|
||||
sprintf(fn, "%09u:forkserver", counter);
|
||||
s32 fd_doc = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||
s32 fd_doc = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
|
||||
if (fd_doc >= 0) {
|
||||
|
||||
if (write(fd_doc, __afl_fuzz_ptr, *__afl_fuzz_len) != *__afl_fuzz_len) {
|
||||
@ -1016,11 +1117,14 @@ void __afl_manual_init(void) {
|
||||
__afl_sharedmem_fuzzing = 0;
|
||||
if (__afl_area_ptr == NULL) __afl_area_ptr = __afl_area_ptr_dummy;
|
||||
|
||||
if (getenv("AFL_DEBUG"))
|
||||
if (__afl_debug) {
|
||||
|
||||
fprintf(stderr,
|
||||
"DEBUG: disabled instrumentation because of "
|
||||
"AFL_DISABLE_LLVM_INSTRUMENTATION\n");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!init_done) {
|
||||
@ -1060,6 +1164,11 @@ __attribute__((constructor(CTOR_PRIO))) void __afl_auto_early(void) {
|
||||
|
||||
__attribute__((constructor(1))) void __afl_auto_second(void) {
|
||||
|
||||
if (__afl_already_initialized_second) return;
|
||||
__afl_already_initialized_second = 1;
|
||||
|
||||
if (getenv("AFL_DEBUG")) { __afl_debug = 1; }
|
||||
|
||||
if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
|
||||
u8 *ptr;
|
||||
|
||||
@ -1084,17 +1193,18 @@ __attribute__((constructor(1))) void __afl_auto_second(void) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
} // ptr memleak report is a false positive
|
||||
|
||||
/* preset __afl_area_ptr #1 - at constructor level 0 global variables have
|
||||
not been set */
|
||||
|
||||
__attribute__((constructor(0))) void __afl_auto_first(void) {
|
||||
|
||||
if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
|
||||
u8 *ptr;
|
||||
if (__afl_already_initialized_first) return;
|
||||
__afl_already_initialized_first = 1;
|
||||
|
||||
ptr = (u8 *)malloc(MAP_INITIAL_SIZE);
|
||||
if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
|
||||
u8 *ptr = (u8 *)malloc(MAP_INITIAL_SIZE);
|
||||
|
||||
if (ptr && (ssize_t)ptr != -1) {
|
||||
|
||||
@ -1103,7 +1213,7 @@ __attribute__((constructor(0))) void __afl_auto_first(void) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
} // ptr memleak report is a false positive
|
||||
|
||||
/* The following stuff deals with supporting -fsanitize-coverage=trace-pc-guard.
|
||||
It remains non-operational in the traditional, plugin-backed LLVM mode.
|
||||
@ -1171,11 +1281,13 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
|
||||
|
||||
_is_sancov = 1;
|
||||
|
||||
if (getenv("AFL_DEBUG")) {
|
||||
if (__afl_debug) {
|
||||
|
||||
fprintf(stderr,
|
||||
"Running __sanitizer_cov_trace_pc_guard_init: %p-%p (%lu edges)\n",
|
||||
start, stop, (unsigned long)(stop - start));
|
||||
"Running __sanitizer_cov_trace_pc_guard_init: %p-%p (%lu edges) "
|
||||
"after_fs=%u\n",
|
||||
start, stop, (unsigned long)(stop - start),
|
||||
__afl_already_initialized_forkserver);
|
||||
|
||||
}
|
||||
|
||||
@ -1191,6 +1303,40 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
|
||||
|
||||
}
|
||||
|
||||
/* instrumented code is loaded *after* our forkserver is up. this is a
|
||||
problem. We cannot prevent collisions then :( */
|
||||
if (__afl_already_initialized_forkserver &&
|
||||
__afl_final_loc + 1 + stop - start > __afl_map_size) {
|
||||
|
||||
if (__afl_debug) {
|
||||
|
||||
fprintf(stderr, "Warning: new instrumented code after the forkserver!\n");
|
||||
|
||||
}
|
||||
|
||||
__afl_final_loc = 2;
|
||||
|
||||
if (1 + stop - start > __afl_map_size) {
|
||||
|
||||
*(start++) = ++__afl_final_loc;
|
||||
|
||||
while (start < stop) {
|
||||
|
||||
if (R(100) < inst_ratio)
|
||||
*start = ++__afl_final_loc % __afl_map_size;
|
||||
else
|
||||
*start = 0;
|
||||
|
||||
start++;
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Make sure that the first element in the range is always set - we use that
|
||||
to avoid duplicate calls (which can happen as an artifact of the underlying
|
||||
implementation in LLVM). */
|
||||
@ -1208,6 +1354,28 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
|
||||
|
||||
}
|
||||
|
||||
if (__afl_debug) {
|
||||
|
||||
fprintf(stderr,
|
||||
"Done __sanitizer_cov_trace_pc_guard_init: __afl_final_loc = %u\n",
|
||||
__afl_final_loc);
|
||||
|
||||
}
|
||||
|
||||
if (__afl_already_initialized_shm && __afl_final_loc > __afl_map_size) {
|
||||
|
||||
if (__afl_debug) {
|
||||
|
||||
fprintf(stderr, "Reinit shm necessary (+%u)\n",
|
||||
__afl_final_loc - __afl_map_size);
|
||||
|
||||
}
|
||||
|
||||
__afl_unmap_shm();
|
||||
__afl_map_shm();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///// CmpLog instrumentation
|
||||
@ -1508,6 +1676,12 @@ void __sanitizer_cov_trace_cmp16(uint128_t arg1, uint128_t arg2) {
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_cov_trace_const_cmp16(uint128_t arg1, uint128_t arg2) {
|
||||
|
||||
__cmplog_ins_hook16(arg1, arg2, 0);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
|
||||
@ -1551,17 +1725,43 @@ void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
|
||||
|
||||
}
|
||||
|
||||
__attribute__((weak)) void *__asan_region_is_poisoned(void *beg, size_t size) {
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
// POSIX shenanigan to see if an area is mapped.
|
||||
// If it is mapped as X-only, we have a problem, so maybe we should add a check
|
||||
// to avoid to call it on .text addresses
|
||||
static int area_is_mapped(void *ptr, size_t len) {
|
||||
static int area_is_valid(void *ptr, size_t len) {
|
||||
|
||||
if (unlikely(!ptr || __asan_region_is_poisoned(ptr, len))) { return 0; }
|
||||
|
||||
long r = syscall(SYS_write, __afl_dummy_fd[1], ptr, len);
|
||||
|
||||
if (r <= 0 || r > len) return 0;
|
||||
|
||||
// even if the write succeed this can be a false positive if we cross
|
||||
// a page boundary. who knows why.
|
||||
|
||||
char *p = (char *)ptr;
|
||||
char *page = (char *)((uintptr_t)p & ~(sysconf(_SC_PAGE_SIZE) - 1));
|
||||
long page_size = sysconf(_SC_PAGE_SIZE);
|
||||
char *page = (char *)((uintptr_t)p & ~(page_size - 1)) + page_size;
|
||||
|
||||
int r = msync(page, (p - page) + len, MS_ASYNC);
|
||||
if (r < 0) return errno != ENOMEM;
|
||||
return 1;
|
||||
if (page > p + len) {
|
||||
|
||||
// no, not crossing a page boundary
|
||||
return (int)r;
|
||||
|
||||
} else {
|
||||
|
||||
// yes it crosses a boundary, hence we can only return the length of
|
||||
// rest of the first page, we cannot detect if the next page is valid
|
||||
// or not, neither by SYS_write nor msync() :-(
|
||||
return (int)(page - p);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1569,20 +1769,25 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) {
|
||||
|
||||
/*
|
||||
u32 i;
|
||||
if (!area_is_mapped(ptr1, 32) || !area_is_mapped(ptr2, 32)) return;
|
||||
if (area_is_valid(ptr1, 32) <= 0 || area_is_valid(ptr2, 32) <= 0) return;
|
||||
fprintf(stderr, "rtn arg0=");
|
||||
for (i = 0; i < 24; i++)
|
||||
for (i = 0; i < 32; i++)
|
||||
fprintf(stderr, "%02x", ptr1[i]);
|
||||
fprintf(stderr, " arg1=");
|
||||
for (i = 0; i < 24; i++)
|
||||
for (i = 0; i < 32; i++)
|
||||
fprintf(stderr, "%02x", ptr2[i]);
|
||||
fprintf(stderr, "\n");
|
||||
*/
|
||||
|
||||
if (unlikely(!__afl_cmp_map)) return;
|
||||
// fprintf(stderr, "RTN1 %p %p\n", ptr1, ptr2);
|
||||
int l1, l2;
|
||||
if ((l1 = area_is_valid(ptr1, 32)) <= 0 ||
|
||||
(l2 = area_is_valid(ptr2, 32)) <= 0)
|
||||
return;
|
||||
int len = MIN(l1, l2);
|
||||
|
||||
if (!area_is_mapped(ptr1, 32) || !area_is_mapped(ptr2, 32)) return;
|
||||
|
||||
// fprintf(stderr, "RTN2 %u\n", len);
|
||||
uintptr_t k = (uintptr_t)__builtin_return_address(0);
|
||||
k = (k >> 4) ^ (k << 8);
|
||||
k &= CMP_MAP_W - 1;
|
||||
@ -1592,17 +1797,17 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) {
|
||||
if (__afl_cmp_map->headers[k].type != CMP_TYPE_RTN) {
|
||||
|
||||
__afl_cmp_map->headers[k].type = CMP_TYPE_RTN;
|
||||
hits = 0;
|
||||
__afl_cmp_map->headers[k].hits = 1;
|
||||
__afl_cmp_map->headers[k].shape = 31;
|
||||
__afl_cmp_map->headers[k].shape = len - 1;
|
||||
hits = 0;
|
||||
|
||||
} else {
|
||||
|
||||
hits = __afl_cmp_map->headers[k].hits++;
|
||||
|
||||
if (__afl_cmp_map->headers[k].shape < 31) {
|
||||
if (__afl_cmp_map->headers[k].shape < len) {
|
||||
|
||||
__afl_cmp_map->headers[k].shape = 31;
|
||||
__afl_cmp_map->headers[k].shape = len - 1;
|
||||
|
||||
}
|
||||
|
||||
@ -1610,9 +1815,10 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) {
|
||||
|
||||
hits &= CMP_MAP_RTN_H - 1;
|
||||
__builtin_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v0,
|
||||
ptr1, 32);
|
||||
ptr1, len);
|
||||
__builtin_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v1,
|
||||
ptr2, 32);
|
||||
ptr2, len);
|
||||
// fprintf(stderr, "RTN3\n");
|
||||
|
||||
}
|
||||
|
||||
@ -1658,7 +1864,8 @@ static u8 *get_llvm_stdstring(u8 *string) {
|
||||
void __cmplog_rtn_gcc_stdstring_cstring(u8 *stdstring, u8 *cstring) {
|
||||
|
||||
if (unlikely(!__afl_cmp_map)) return;
|
||||
if (!area_is_mapped(stdstring, 32) || !area_is_mapped(cstring, 32)) return;
|
||||
if (area_is_valid(stdstring, 32) <= 0 || area_is_valid(cstring, 32) <= 0)
|
||||
return;
|
||||
|
||||
__cmplog_rtn_hook(get_gcc_stdstring(stdstring), cstring);
|
||||
|
||||
@ -1667,7 +1874,7 @@ void __cmplog_rtn_gcc_stdstring_cstring(u8 *stdstring, u8 *cstring) {
|
||||
void __cmplog_rtn_gcc_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) {
|
||||
|
||||
if (unlikely(!__afl_cmp_map)) return;
|
||||
if (!area_is_mapped(stdstring1, 32) || !area_is_mapped(stdstring2, 32))
|
||||
if (area_is_valid(stdstring1, 32) <= 0 || area_is_valid(stdstring2, 32) <= 0)
|
||||
return;
|
||||
|
||||
__cmplog_rtn_hook(get_gcc_stdstring(stdstring1),
|
||||
@ -1678,7 +1885,8 @@ void __cmplog_rtn_gcc_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) {
|
||||
void __cmplog_rtn_llvm_stdstring_cstring(u8 *stdstring, u8 *cstring) {
|
||||
|
||||
if (unlikely(!__afl_cmp_map)) return;
|
||||
if (!area_is_mapped(stdstring, 32) || !area_is_mapped(cstring, 32)) return;
|
||||
if (area_is_valid(stdstring, 32) <= 0 || area_is_valid(cstring, 32) <= 0)
|
||||
return;
|
||||
|
||||
__cmplog_rtn_hook(get_llvm_stdstring(stdstring), cstring);
|
||||
|
||||
@ -1687,7 +1895,7 @@ void __cmplog_rtn_llvm_stdstring_cstring(u8 *stdstring, u8 *cstring) {
|
||||
void __cmplog_rtn_llvm_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) {
|
||||
|
||||
if (unlikely(!__afl_cmp_map)) return;
|
||||
if (!area_is_mapped(stdstring1, 32) || !area_is_mapped(stdstring2, 32))
|
||||
if (area_is_valid(stdstring1, 32) <= 0 || area_is_valid(stdstring2, 32) <= 0)
|
||||
return;
|
||||
|
||||
__cmplog_rtn_hook(get_llvm_stdstring(stdstring1),
|
||||
|
@ -60,20 +60,25 @@ bool isIgnoreFunction(const llvm::Function *F) {
|
||||
"asan.",
|
||||
"llvm.",
|
||||
"sancov.",
|
||||
"__ubsan_",
|
||||
"__ubsan",
|
||||
"ign.",
|
||||
"__afl_",
|
||||
"__afl",
|
||||
"_fini",
|
||||
"__libc_csu",
|
||||
"__libc_",
|
||||
"__asan",
|
||||
"__msan",
|
||||
"__cmplog",
|
||||
"__sancov",
|
||||
"__san",
|
||||
"__cxx_",
|
||||
"__decide_deferred",
|
||||
"_GLOBAL",
|
||||
"_ZZN6__asan",
|
||||
"_ZZN6__lsan",
|
||||
"msan.",
|
||||
"LLVMFuzzerM",
|
||||
"LLVMFuzzerC",
|
||||
"LLVMFuzzerI",
|
||||
"__decide_deferred",
|
||||
"maybe_duplicate_stderr",
|
||||
"discard_output",
|
||||
"close_stdout",
|
||||
@ -89,6 +94,20 @@ bool isIgnoreFunction(const llvm::Function *F) {
|
||||
|
||||
}
|
||||
|
||||
static const char *ignoreSubstringList[] = {
|
||||
|
||||
"__asan", "__msan", "__ubsan", "__lsan",
|
||||
"__san", "__sanitize", "__cxx", "_GLOBAL__",
|
||||
"DebugCounter", "DwarfDebug", "DebugLoc"
|
||||
|
||||
};
|
||||
|
||||
for (auto const &ignoreListFunc : ignoreSubstringList) {
|
||||
|
||||
if (F->getName().contains(ignoreListFunc)) { return true; }
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
ddc4a9748d
|
||||
|
@ -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!"
|
||||
|
@ -51,6 +51,7 @@ ssize_t write(int fd, const void *buf, size_t count) {
|
||||
void *rtv = __builtin_return_address(0);
|
||||
|
||||
QASAN_DEBUG("%14p: write(%d, %p, %zu)\n", rtv, fd, buf, count);
|
||||
QASAN_LOAD(buf, count);
|
||||
ssize_t r = __lq_libc_write(fd, buf, count);
|
||||
QASAN_DEBUG("\t\t = %zd\n", r);
|
||||
|
||||
@ -63,6 +64,7 @@ ssize_t read(int fd, void *buf, size_t count) {
|
||||
void *rtv = __builtin_return_address(0);
|
||||
|
||||
QASAN_DEBUG("%14p: read(%d, %p, %zu)\n", rtv, fd, buf, count);
|
||||
QASAN_STORE(buf, count);
|
||||
ssize_t r = __lq_libc_read(fd, buf, count);
|
||||
QASAN_DEBUG("\t\t = %zd\n", r);
|
||||
|
||||
|
@ -159,6 +159,9 @@ size_t __libqasan_malloc_usable_size(void *ptr) {
|
||||
char *p = ptr;
|
||||
p -= sizeof(struct chunk_begin);
|
||||
|
||||
// Validate that the chunk marker is readable (a crude check
|
||||
// to verify that ptr is a valid malloc region before we dereference it)
|
||||
QASAN_LOAD(p, sizeof(struct chunk_begin) - REDZONE_SIZE);
|
||||
return ((struct chunk_begin *)p)->requested_size;
|
||||
|
||||
}
|
||||
@ -225,6 +228,9 @@ void __libqasan_free(void *ptr) {
|
||||
struct chunk_begin *p = ptr;
|
||||
p -= 1;
|
||||
|
||||
// Validate that the chunk marker is readable (a crude check
|
||||
// to verify that ptr is a valid malloc region before we dereference it)
|
||||
QASAN_LOAD(p, sizeof(struct chunk_begin) - REDZONE_SIZE);
|
||||
size_t n = p->requested_size;
|
||||
|
||||
QASAN_STORE(ptr, n);
|
||||
|
Submodule qemu_mode/qemuafl updated: e36a30ebca...0fb212daab
@ -212,7 +212,7 @@ static s32 write_to_file(u8 *path, u8 *mem, u32 len) {
|
||||
|
||||
unlink(path); /* Ignore errors */
|
||||
|
||||
ret = open(path, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||
ret = open(path, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
|
||||
if (ret < 0) { PFATAL("Unable to create '%s'", path); }
|
||||
|
||||
@ -785,6 +785,7 @@ static void set_up_environment(void) {
|
||||
"abort_on_error=1:"
|
||||
"detect_leaks=0:"
|
||||
"allocator_may_return_null=1:"
|
||||
"detect_odr_violation=0:"
|
||||
"symbolize=0:"
|
||||
"handle_segv=0:"
|
||||
"handle_sigbus=0:"
|
||||
@ -821,38 +822,7 @@ static void set_up_environment(void) {
|
||||
|
||||
if (qemu_mode) {
|
||||
|
||||
u8 *qemu_preload = getenv("QEMU_SET_ENV");
|
||||
u8 *afl_preload = getenv("AFL_PRELOAD");
|
||||
u8 *buf;
|
||||
|
||||
s32 i, afl_preload_size = strlen(afl_preload);
|
||||
for (i = 0; i < afl_preload_size; ++i) {
|
||||
|
||||
if (afl_preload[i] == ',') {
|
||||
|
||||
PFATAL(
|
||||
"Comma (',') is not allowed in AFL_PRELOAD when -Q is "
|
||||
"specified!");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (qemu_preload) {
|
||||
|
||||
buf = alloc_printf("%s,LD_PRELOAD=%s,DYLD_INSERT_LIBRARIES=%s",
|
||||
qemu_preload, afl_preload, afl_preload);
|
||||
|
||||
} else {
|
||||
|
||||
buf = alloc_printf("LD_PRELOAD=%s,DYLD_INSERT_LIBRARIES=%s",
|
||||
afl_preload, afl_preload);
|
||||
|
||||
}
|
||||
|
||||
setenv("QEMU_SET_ENV", buf, 1);
|
||||
|
||||
ck_free(buf);
|
||||
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
|
||||
|
||||
} else {
|
||||
|
||||
@ -1078,31 +1048,6 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
if (optind == argc || !in_file) { usage(argv[0]); }
|
||||
|
||||
if (qemu_mode && getenv("AFL_USE_QASAN")) {
|
||||
|
||||
u8 *preload = getenv("AFL_PRELOAD");
|
||||
u8 *libqasan = get_libqasan_path(argv_orig[0]);
|
||||
|
||||
if (!preload) {
|
||||
|
||||
setenv("AFL_PRELOAD", libqasan, 0);
|
||||
|
||||
} else {
|
||||
|
||||
u8 *result = ck_alloc(strlen(libqasan) + strlen(preload) + 2);
|
||||
strcpy(result, libqasan);
|
||||
strcat(result, " ");
|
||||
strcat(result, preload);
|
||||
|
||||
setenv("AFL_PRELOAD", result, 1);
|
||||
ck_free(result);
|
||||
|
||||
}
|
||||
|
||||
ck_free(libqasan);
|
||||
|
||||
}
|
||||
|
||||
map_size = get_map_size();
|
||||
|
||||
use_hex_offsets = !!get_afl_env("AFL_ANALYZE_HEX");
|
||||
|
@ -280,7 +280,7 @@ static void add_instrumentation(void) {
|
||||
|
||||
}
|
||||
|
||||
outfd = open(modified_file, O_WRONLY | O_EXCL | O_CREAT, 0600);
|
||||
outfd = open(modified_file, O_WRONLY | O_EXCL | O_CREAT, DEFAULT_PERMISSION);
|
||||
|
||||
if (outfd < 0) { PFATAL("Unable to write to '%s'", modified_file); }
|
||||
|
||||
|
262
src/afl-cc.c
262
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",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
@ -588,6 +590,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
#if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0)
|
||||
#ifdef __ANDROID__
|
||||
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
|
||||
instrument_mode != INSTRUMENT_LLVMNATIVE;
|
||||
#else
|
||||
if (have_instr_list) {
|
||||
|
||||
@ -597,6 +600,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
"-fsanitize-coverage-allow/denylist, you can use "
|
||||
"AFL_LLVM_ALLOWLIST/AFL_LLMV_DENYLIST instead.\n");
|
||||
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
|
||||
instrument_mode = INSTRUMENT_LLVMNATIVE;
|
||||
|
||||
} else {
|
||||
|
||||
@ -616,6 +620,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
"Using unoptimized trace-pc-guard, upgrade to llvm 10.0.1+ for "
|
||||
"enhanced version.\n");
|
||||
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
|
||||
instrument_mode = INSTRUMENT_LLVMNATIVE;
|
||||
#else
|
||||
FATAL("pcguard instrumentation requires llvm 4.0.1+");
|
||||
#endif
|
||||
@ -680,19 +685,49 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
|
||||
/* Detect stray -v calls from ./configure scripts. */
|
||||
|
||||
u8 skip_next = 0;
|
||||
while (--argc) {
|
||||
|
||||
u8 *cur = *(++argv);
|
||||
|
||||
if (skip_next) {
|
||||
|
||||
skip_next = 0;
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if (!strncmp(cur, "--afl", 5)) continue;
|
||||
if (lto_mode && !strncmp(cur, "-fuse-ld=", 9)) continue;
|
||||
if (lto_mode && !strncmp(cur, "--ld-path=", 10)) continue;
|
||||
if (!strncmp(cur, "-fno-unroll", 11)) continue;
|
||||
if (strstr(cur, "afl-compiler-rt") || strstr(cur, "afl-llvm-rt")) continue;
|
||||
if (!strcmp(cur, "-Wl,-z,defs") || !strcmp(cur, "-Wl,--no-undefined"))
|
||||
if (!strcmp(cur, "-Wl,-z,defs") || !strcmp(cur, "-Wl,--no-undefined") ||
|
||||
!strcmp(cur, "--no-undefined")) {
|
||||
|
||||
continue;
|
||||
if (!strncmp(cur, "-fsanitize=fuzzer-", strlen("-fsanitize=fuzzer-")) ||
|
||||
!strncmp(cur, "-fsanitize-coverage", strlen("-fsanitize-coverage"))) {
|
||||
|
||||
}
|
||||
|
||||
if (!strcmp(cur, "-z")) {
|
||||
|
||||
u8 *param = *(argv + 1);
|
||||
if (!strcmp(param, "defs")) {
|
||||
|
||||
skip_next = 1;
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ((!strncmp(cur, "-fsanitize=fuzzer-", strlen("-fsanitize=fuzzer-")) ||
|
||||
!strncmp(cur, "-fsanitize-coverage", strlen("-fsanitize-coverage"))) &&
|
||||
(strncmp(cur, "sanitize-coverage-allow",
|
||||
strlen("sanitize-coverage-allow")) &&
|
||||
strncmp(cur, "sanitize-coverage-deny",
|
||||
strlen("sanitize-coverage-deny")) &&
|
||||
instrument_mode != INSTRUMENT_LLVMNATIVE)) {
|
||||
|
||||
if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); }
|
||||
continue;
|
||||
@ -938,7 +973,10 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if (preprocessor_only) {
|
||||
// prevent unnecessary build errors
|
||||
cc_params[cc_par_cnt++] = "-Wno-unused-command-line-argument";
|
||||
|
||||
if (preprocessor_only || have_c) {
|
||||
|
||||
/* In the preprocessor_only case (-E), we are not actually compiling at
|
||||
all but requesting the compiler to output preprocessed sources only.
|
||||
@ -957,18 +995,24 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
switch (bit_mode) {
|
||||
|
||||
case 0:
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/afl-compiler-rt.o", obj_path);
|
||||
if (!shared_linking)
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/afl-compiler-rt.o", obj_path);
|
||||
if (lto_mode)
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/afl-llvm-rt-lto.o", obj_path);
|
||||
break;
|
||||
|
||||
case 32:
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/afl-compiler-rt-32.o", obj_path);
|
||||
if (access(cc_params[cc_par_cnt - 1], R_OK))
|
||||
FATAL("-m32 is not supported by your compiler");
|
||||
if (!shared_linking) {
|
||||
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/afl-compiler-rt-32.o", obj_path);
|
||||
if (access(cc_params[cc_par_cnt - 1], R_OK))
|
||||
FATAL("-m32 is not supported by your compiler");
|
||||
|
||||
}
|
||||
|
||||
if (lto_mode) {
|
||||
|
||||
cc_params[cc_par_cnt++] =
|
||||
@ -981,10 +1025,15 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
break;
|
||||
|
||||
case 64:
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/afl-compiler-rt-64.o", obj_path);
|
||||
if (access(cc_params[cc_par_cnt - 1], R_OK))
|
||||
FATAL("-m64 is not supported by your compiler");
|
||||
if (!shared_linking) {
|
||||
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/afl-compiler-rt-64.o", obj_path);
|
||||
if (access(cc_params[cc_par_cnt - 1], R_OK))
|
||||
FATAL("-m64 is not supported by your compiler");
|
||||
|
||||
}
|
||||
|
||||
if (lto_mode) {
|
||||
|
||||
cc_params[cc_par_cnt++] =
|
||||
@ -999,20 +1048,17 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
}
|
||||
|
||||
#if !defined(__APPLE__) && !defined(__sun)
|
||||
if (!shared_linking && !have_c)
|
||||
if (!shared_linking)
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("-Wl,--dynamic-list=%s/dynamic_list.txt", obj_path);
|
||||
#endif
|
||||
|
||||
#if defined(USEMMAP) && !defined(__HAIKU__)
|
||||
if (!have_c) cc_params[cc_par_cnt++] = "-lrt";
|
||||
#endif
|
||||
|
||||
// prevent unnecessary build errors
|
||||
cc_params[cc_par_cnt++] = "-Wno-unused-command-line-argument";
|
||||
|
||||
}
|
||||
|
||||
#if defined(USEMMAP) && !defined(__HAIKU__)
|
||||
cc_params[cc_par_cnt++] = "-lrt";
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
cc_params[cc_par_cnt] = NULL;
|
||||
@ -1023,7 +1069,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
|
||||
int main(int argc, char **argv, char **envp) {
|
||||
|
||||
int i;
|
||||
int i, passthrough = 0;
|
||||
char *callname = argv[0], *ptr = NULL;
|
||||
|
||||
if (getenv("AFL_DEBUG")) {
|
||||
@ -1043,6 +1089,13 @@ int main(int argc, char **argv, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_PASSTHROUGH") || getenv("AFL_NOOPT")) {
|
||||
|
||||
passthrough = 1;
|
||||
if (!debug) { be_quiet = 1; }
|
||||
|
||||
}
|
||||
|
||||
if ((ptr = strrchr(callname, '/')) != NULL) callname = ptr + 1;
|
||||
argvnull = (u8 *)argv[0];
|
||||
check_environment_vars(envp);
|
||||
@ -1211,6 +1264,7 @@ int main(int argc, char **argv, char **envp) {
|
||||
|
||||
} else if (strcasecmp(ptr, "LLVMNATIVE") == 0 ||
|
||||
|
||||
strcasecmp(ptr, "NATIVE") == 0 ||
|
||||
strcasecmp(ptr, "LLVM-NATIVE") == 0) {
|
||||
|
||||
compiler_mode = LLVM;
|
||||
@ -1273,6 +1327,7 @@ int main(int argc, char **argv, char **envp) {
|
||||
}
|
||||
|
||||
if (getenv("AFL_LLVM_CTX")) instrument_opt_mode |= INSTRUMENT_OPT_CTX;
|
||||
if (getenv("AFL_LLVM_CALLER")) instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
|
||||
|
||||
if (getenv("AFL_LLVM_NGRAM_SIZE")) {
|
||||
|
||||
@ -1286,6 +1341,26 @@ int main(int argc, char **argv, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_LLVM_CTX_K")) {
|
||||
|
||||
ctx_k = atoi(getenv("AFL_LLVM_CTX_K"));
|
||||
if (ctx_k < 1 || ctx_k > CTX_MAX_K)
|
||||
FATAL("K-CTX instrumentation mode must be between 1 and CTX_MAX_K (%u)",
|
||||
CTX_MAX_K);
|
||||
if (ctx_k == 1) {
|
||||
|
||||
setenv("AFL_LLVM_CALLER", "1", 1);
|
||||
unsetenv("AFL_LLVM_CTX_K");
|
||||
instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
|
||||
|
||||
} else {
|
||||
|
||||
instrument_opt_mode |= INSTRUMENT_OPT_CTX_K;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_LLVM_INSTRUMENT")) {
|
||||
|
||||
u8 *ptr2 = strtok(getenv("AFL_LLVM_INSTRUMENT"), ":,;");
|
||||
@ -1381,6 +1456,44 @@ int main(int argc, char **argv, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if (strncasecmp(ptr2, "ctx-", strlen("ctx-")) == 0) {
|
||||
|
||||
u8 *ptr3 = ptr2 + strlen("ctx-");
|
||||
while (*ptr3 && (*ptr3 < '0' || *ptr3 > '9'))
|
||||
ptr3++;
|
||||
|
||||
if (!*ptr3) {
|
||||
|
||||
if ((ptr3 = getenv("AFL_LLVM_CTX_K")) == NULL)
|
||||
FATAL(
|
||||
"you must set the K-CTX K with (e.g. for value 2) "
|
||||
"AFL_LLVM_INSTRUMENT=ctx-2");
|
||||
|
||||
}
|
||||
|
||||
ctx_k = atoi(ptr3);
|
||||
if (ctx_k < 1 || ctx_k > CTX_MAX_K)
|
||||
FATAL(
|
||||
"K-CTX instrumentation option must be between 1 and CTX_MAX_K "
|
||||
"(%u)",
|
||||
CTX_MAX_K);
|
||||
|
||||
if (ctx_k == 1) {
|
||||
|
||||
instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
|
||||
setenv("AFL_LLVM_CALLER", "1", 1);
|
||||
unsetenv("AFL_LLVM_CTX_K");
|
||||
|
||||
} else {
|
||||
|
||||
instrument_opt_mode |= (INSTRUMENT_OPT_CTX_K);
|
||||
u8 *ptr4 = alloc_printf("%u", ctx_k);
|
||||
setenv("AFL_LLVM_CTX_K", ptr4, 1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (strncasecmp(ptr2, "ctx", strlen("ctx")) == 0) {
|
||||
|
||||
instrument_opt_mode |= INSTRUMENT_OPT_CTX;
|
||||
@ -1388,6 +1501,13 @@ int main(int argc, char **argv, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if (strncasecmp(ptr2, "caller", strlen("caller")) == 0) {
|
||||
|
||||
instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
|
||||
setenv("AFL_LLVM_CALLER", "1", 1);
|
||||
|
||||
}
|
||||
|
||||
if (strncasecmp(ptr2, "ngram", strlen("ngram")) == 0) {
|
||||
|
||||
u8 *ptr3 = ptr2 + strlen("ngram");
|
||||
@ -1421,6 +1541,27 @@ int main(int argc, char **argv, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if ((instrument_opt_mode & INSTRUMENT_OPT_CTX) &&
|
||||
(instrument_opt_mode & INSTRUMENT_OPT_CALLER)) {
|
||||
|
||||
FATAL("you cannot set CTX and CALLER together");
|
||||
|
||||
}
|
||||
|
||||
if ((instrument_opt_mode & INSTRUMENT_OPT_CTX) &&
|
||||
(instrument_opt_mode & INSTRUMENT_OPT_CTX_K)) {
|
||||
|
||||
FATAL("you cannot set CTX and K-CTX together");
|
||||
|
||||
}
|
||||
|
||||
if ((instrument_opt_mode & INSTRUMENT_OPT_CALLER) &&
|
||||
(instrument_opt_mode & INSTRUMENT_OPT_CTX_K)) {
|
||||
|
||||
FATAL("you cannot set CALLER and K-CTX together");
|
||||
|
||||
}
|
||||
|
||||
if (instrument_opt_mode && instrument_mode == INSTRUMENT_DEFAULT &&
|
||||
(compiler_mode == LLVM || compiler_mode == UNSET)) {
|
||||
|
||||
@ -1498,12 +1639,13 @@ int main(int argc, char **argv, char **envp) {
|
||||
" CLASSIC %s no yes module yes yes "
|
||||
"yes\n"
|
||||
" - NORMAL\n"
|
||||
" - CALLER\n"
|
||||
" - CTX\n"
|
||||
" - NGRAM-{2-16}\n"
|
||||
" INSTRIM no yes module yes yes "
|
||||
" yes\n"
|
||||
" - NORMAL\n"
|
||||
" - CTX\n"
|
||||
" - CALLER\n"
|
||||
" - NGRAM-{2-16}\n"
|
||||
" [GCC_PLUGIN] gcc plugin: %s%s\n"
|
||||
" CLASSIC DEFAULT no yes no no no "
|
||||
@ -1535,8 +1677,8 @@ int main(int argc, char **argv, char **envp) {
|
||||
"of afl-cc.\n\n");
|
||||
|
||||
#if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0)
|
||||
#define NATIVE_MSG \
|
||||
" NATIVE: use llvm's native PCGUARD instrumentation (less " \
|
||||
#define NATIVE_MSG \
|
||||
" LLVM-NATIVE: use llvm's native PCGUARD instrumentation (less " \
|
||||
"performant)\n"
|
||||
#else
|
||||
#define NATIVE_MSG ""
|
||||
@ -1550,7 +1692,10 @@ int main(int argc, char **argv, char **envp) {
|
||||
NATIVE_MSG
|
||||
|
||||
" CLASSIC: decision target instrumentation (README.llvm.md)\n"
|
||||
" CTX: CLASSIC + callee context (instrumentation/README.ctx.md)\n"
|
||||
" CALLER: CLASSIC + single callee context "
|
||||
"(instrumentation/README.ctx.md)\n"
|
||||
" CTX: CLASSIC + full callee context "
|
||||
"(instrumentation/README.ctx.md)\n"
|
||||
" NGRAM-x: CLASSIC + previous path "
|
||||
"((instrumentation/README.ngram.md)\n"
|
||||
" INSTRIM: Dominator tree (for LLVM <= 6.0) "
|
||||
@ -1593,6 +1738,8 @@ int main(int argc, char **argv, char **envp) {
|
||||
" AFL_DONT_OPTIMIZE: disable optimization instead of -O3\n"
|
||||
" AFL_NO_BUILTIN: no builtins for string compare functions (for "
|
||||
"libtokencap.so)\n"
|
||||
" AFL_NOOP: behave like a normal compiler (to pass configure "
|
||||
"tests)\n"
|
||||
" AFL_PATH: path to instrumenting pass and runtime "
|
||||
"(afl-compiler-rt.*o)\n"
|
||||
" AFL_IGNORE_UNKNOWN_ENVS: don't warn on unknown env vars\n"
|
||||
@ -1644,15 +1791,17 @@ int main(int argc, char **argv, char **envp) {
|
||||
" AFL_LLVM_CMPLOG: log operands of comparisons (RedQueen "
|
||||
"mutator)\n"
|
||||
" AFL_LLVM_INSTRUMENT: set instrumentation mode:\n"
|
||||
" CLASSIC, INSTRIM, PCGUARD, LTO, GCC, CLANG, CTX, NGRAM-2 ... "
|
||||
"NGRAM-16\n"
|
||||
" CLASSIC, INSTRIM, PCGUARD, LTO, GCC, CLANG, CALLER, CTX, "
|
||||
"NGRAM-2 ..-16\n"
|
||||
" You can also use the old environment variables instead:\n"
|
||||
" AFL_LLVM_USE_TRACE_PC: use LLVM trace-pc-guard instrumentation\n"
|
||||
" AFL_LLVM_INSTRIM: use light weight instrumentation InsTrim\n"
|
||||
" AFL_LLVM_INSTRIM_LOOPHEAD: optimize loop tracing for speed "
|
||||
"(option to INSTRIM)\n"
|
||||
" AFL_LLVM_CTX: use context sensitive coverage (for CLASSIC and "
|
||||
"INSTRIM)\n"
|
||||
" AFL_LLVM_CALLER: use single context sensitive coverage (for "
|
||||
"CLASSIC)\n"
|
||||
" AFL_LLVM_CTX: use full context sensitive coverage (for "
|
||||
"CLASSIC)\n"
|
||||
" AFL_LLVM_NGRAM_SIZE: use ngram prev_loc count coverage (for "
|
||||
"CLASSIC & INSTRIM)\n");
|
||||
|
||||
@ -1770,7 +1919,7 @@ int main(int argc, char **argv, char **envp) {
|
||||
}
|
||||
|
||||
if (instrument_opt_mode && compiler_mode != LLVM)
|
||||
FATAL("CTX and NGRAM can only be used in LLVM mode");
|
||||
FATAL("CTX, CALLER and NGRAM can only be used in LLVM mode");
|
||||
|
||||
if (!instrument_opt_mode) {
|
||||
|
||||
@ -1780,15 +1929,18 @@ int main(int argc, char **argv, char **envp) {
|
||||
|
||||
} else {
|
||||
|
||||
if (instrument_opt_mode == INSTRUMENT_OPT_CTX)
|
||||
char *ptr2 = alloc_printf(" + NGRAM-%u", ngram_size);
|
||||
char *ptr3 = alloc_printf(" + K-CTX-%u", ctx_k);
|
||||
|
||||
ptr = alloc_printf("%s + CTX", instrument_mode_string[instrument_mode]);
|
||||
else if (instrument_opt_mode == INSTRUMENT_OPT_NGRAM)
|
||||
ptr = alloc_printf("%s + NGRAM-%u",
|
||||
instrument_mode_string[instrument_mode], ngram_size);
|
||||
else
|
||||
ptr = alloc_printf("%s + CTX + NGRAM-%u",
|
||||
instrument_mode_string[instrument_mode], ngram_size);
|
||||
ptr = alloc_printf(
|
||||
"%s%s%s%s%s", instrument_mode_string[instrument_mode],
|
||||
(instrument_opt_mode & INSTRUMENT_OPT_CTX) ? " + CTX" : "",
|
||||
(instrument_opt_mode & INSTRUMENT_OPT_CALLER) ? " + CALLER" : "",
|
||||
(instrument_opt_mode & INSTRUMENT_OPT_NGRAM) ? ptr2 : "",
|
||||
(instrument_opt_mode & INSTRUMENT_OPT_CTX_K) ? ptr3 : "");
|
||||
|
||||
ck_free(ptr2);
|
||||
ck_free(ptr3);
|
||||
|
||||
}
|
||||
|
||||
@ -1799,11 +1951,14 @@ int main(int argc, char **argv, char **envp) {
|
||||
"(requires LLVM 11 or higher)");
|
||||
#endif
|
||||
|
||||
if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC &&
|
||||
instrument_mode != INSTRUMENT_CFG)
|
||||
if (instrument_opt_mode && instrument_mode == INSTRUMENT_CFG &&
|
||||
instrument_opt_mode & INSTRUMENT_OPT_CTX)
|
||||
FATAL("CFG instrumentation mode supports NGRAM and CALLER, but not CTX.");
|
||||
else if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC)
|
||||
// we will drop CFG/INSTRIM in the future so do not advertise
|
||||
FATAL(
|
||||
"CTX and NGRAM instrumentation options can only be used with LLVM and "
|
||||
"CFG or CLASSIC instrumentation modes!");
|
||||
"CALLER, CTX and NGRAM instrumentation options can only be used with "
|
||||
"the LLVM CLASSIC instrumentation mode.");
|
||||
|
||||
if (getenv("AFL_LLVM_SKIP_NEVERZERO") && getenv("AFL_LLVM_NOT_ZERO"))
|
||||
FATAL(
|
||||
@ -1897,7 +2052,16 @@ int main(int argc, char **argv, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
execvp(cc_params[0], (char **)cc_params);
|
||||
if (passthrough) {
|
||||
|
||||
argv[0] = cc_params[0];
|
||||
execvp(cc_params[0], (char **)argv);
|
||||
|
||||
} else {
|
||||
|
||||
execvp(cc_params[0], (char **)cc_params);
|
||||
|
||||
}
|
||||
|
||||
FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]);
|
||||
|
||||
|
394
src/afl-common.c
394
src/afl-common.c
@ -149,9 +149,14 @@ void argv_cpy_free(char **argv) {
|
||||
|
||||
char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
|
||||
|
||||
if (!unlikely(own_loc)) { FATAL("BUG: param own_loc is NULL"); }
|
||||
if (unlikely(getenv("AFL_QEMU_CUSTOM_BIN"))) {
|
||||
|
||||
u8 *tmp, *cp = NULL, *rsl, *own_copy;
|
||||
WARNF(
|
||||
"AFL_QEMU_CUSTOM_BIN is enabled. "
|
||||
"You must run your target under afl-qemu-trace on your own!");
|
||||
return argv;
|
||||
|
||||
}
|
||||
|
||||
char **new_argv = ck_alloc(sizeof(char *) * (argc + 4));
|
||||
if (unlikely(!new_argv)) { FATAL("Illegal amount of arguments specified"); }
|
||||
@ -164,70 +169,8 @@ char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
|
||||
|
||||
/* Now we need to actually find the QEMU binary to put in argv[0]. */
|
||||
|
||||
tmp = getenv("AFL_PATH");
|
||||
|
||||
if (tmp) {
|
||||
|
||||
cp = alloc_printf("%s/afl-qemu-trace", tmp);
|
||||
|
||||
if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); }
|
||||
|
||||
*target_path_p = new_argv[0] = cp;
|
||||
return new_argv;
|
||||
|
||||
}
|
||||
|
||||
own_copy = ck_strdup(own_loc);
|
||||
rsl = strrchr(own_copy, '/');
|
||||
|
||||
if (rsl) {
|
||||
|
||||
*rsl = 0;
|
||||
|
||||
cp = alloc_printf("%s/afl-qemu-trace", own_copy);
|
||||
ck_free(own_copy);
|
||||
|
||||
if (!access(cp, X_OK)) {
|
||||
|
||||
*target_path_p = new_argv[0] = cp;
|
||||
return new_argv;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
ck_free(own_copy);
|
||||
|
||||
}
|
||||
|
||||
if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) {
|
||||
|
||||
if (cp) { ck_free(cp); }
|
||||
*target_path_p = new_argv[0] = ck_strdup(BIN_PATH "/afl-qemu-trace");
|
||||
|
||||
return new_argv;
|
||||
|
||||
}
|
||||
|
||||
SAYF("\n" cLRD "[-] " cRST
|
||||
"Oops, unable to find the 'afl-qemu-trace' binary. The binary must be "
|
||||
"built\n"
|
||||
" separately by following the instructions in "
|
||||
"qemu_mode/README.md. "
|
||||
"If you\n"
|
||||
" already have the binary installed, you may need to specify "
|
||||
"AFL_PATH in the\n"
|
||||
" environment.\n\n"
|
||||
|
||||
" Of course, even without QEMU, afl-fuzz can still work with "
|
||||
"binaries that are\n"
|
||||
" instrumented at compile time with afl-gcc. It is also possible to "
|
||||
"use it as a\n"
|
||||
" traditional non-instrumented fuzzer by specifying '-n' in the "
|
||||
"command "
|
||||
"line.\n");
|
||||
|
||||
FATAL("Failed to locate 'afl-qemu-trace'.");
|
||||
*target_path_p = new_argv[0] = find_afl_binary(own_loc, "afl-qemu-trace");
|
||||
return new_argv;
|
||||
|
||||
}
|
||||
|
||||
@ -235,10 +178,6 @@ char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
|
||||
|
||||
char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
|
||||
|
||||
if (!unlikely(own_loc)) { FATAL("BUG: param own_loc is NULL"); }
|
||||
|
||||
u8 *tmp, *cp = NULL, *rsl, *own_copy;
|
||||
|
||||
char **new_argv = ck_alloc(sizeof(char *) * (argc + 3));
|
||||
if (unlikely(!new_argv)) { FATAL("Illegal amount of arguments specified"); }
|
||||
|
||||
@ -249,152 +188,10 @@ char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
|
||||
|
||||
/* Now we need to actually find the QEMU binary to put in argv[0]. */
|
||||
|
||||
tmp = getenv("AFL_PATH");
|
||||
|
||||
if (tmp) {
|
||||
|
||||
cp = alloc_printf("%s/afl-qemu-trace", tmp);
|
||||
|
||||
if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); }
|
||||
|
||||
ck_free(cp);
|
||||
|
||||
cp = alloc_printf("%s/afl-wine-trace", tmp);
|
||||
|
||||
if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); }
|
||||
|
||||
*target_path_p = new_argv[0] = cp;
|
||||
return new_argv;
|
||||
|
||||
}
|
||||
|
||||
own_copy = ck_strdup(own_loc);
|
||||
rsl = strrchr(own_copy, '/');
|
||||
|
||||
if (rsl) {
|
||||
|
||||
*rsl = 0;
|
||||
|
||||
cp = alloc_printf("%s/afl-qemu-trace", own_copy);
|
||||
|
||||
if (cp && !access(cp, X_OK)) {
|
||||
|
||||
ck_free(cp);
|
||||
|
||||
cp = alloc_printf("%s/afl-wine-trace", own_copy);
|
||||
|
||||
if (!access(cp, X_OK)) {
|
||||
|
||||
*target_path_p = new_argv[0] = cp;
|
||||
return new_argv;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ck_free(own_copy);
|
||||
|
||||
} else {
|
||||
|
||||
ck_free(own_copy);
|
||||
|
||||
}
|
||||
|
||||
u8 *ncp = BIN_PATH "/afl-qemu-trace";
|
||||
|
||||
if (!access(ncp, X_OK)) {
|
||||
|
||||
ncp = BIN_PATH "/afl-wine-trace";
|
||||
|
||||
if (!access(ncp, X_OK)) {
|
||||
|
||||
*target_path_p = new_argv[0] = ck_strdup(ncp);
|
||||
return new_argv;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SAYF("\n" cLRD "[-] " cRST
|
||||
"Oops, unable to find the '%s' binary. The binary must be "
|
||||
"built\n"
|
||||
" separately by following the instructions in "
|
||||
"qemu_mode/README.md. "
|
||||
"If you\n"
|
||||
" already have the binary installed, you may need to specify "
|
||||
"AFL_PATH in the\n"
|
||||
" environment.\n\n"
|
||||
|
||||
" Of course, even without QEMU, afl-fuzz can still work with "
|
||||
"binaries that are\n"
|
||||
" instrumented at compile time with afl-gcc. It is also possible to "
|
||||
"use it as a\n"
|
||||
" traditional non-instrumented fuzzer by specifying '-n' in the "
|
||||
"command "
|
||||
"line.\n",
|
||||
ncp);
|
||||
|
||||
FATAL("Failed to locate '%s'.", ncp);
|
||||
|
||||
}
|
||||
|
||||
/* Get libqasan path. */
|
||||
|
||||
u8 *get_libqasan_path(u8 *own_loc) {
|
||||
|
||||
if (!unlikely(own_loc)) { FATAL("BUG: param own_loc is NULL"); }
|
||||
|
||||
u8 *tmp, *cp = NULL, *rsl, *own_copy;
|
||||
|
||||
tmp = getenv("AFL_PATH");
|
||||
|
||||
if (tmp) {
|
||||
|
||||
cp = alloc_printf("%s/libqasan.so", tmp);
|
||||
|
||||
if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); }
|
||||
|
||||
return cp;
|
||||
|
||||
}
|
||||
|
||||
own_copy = ck_strdup(own_loc);
|
||||
rsl = strrchr(own_copy, '/');
|
||||
|
||||
if (rsl) {
|
||||
|
||||
*rsl = 0;
|
||||
|
||||
cp = alloc_printf("%s/libqasan.so", own_copy);
|
||||
ck_free(own_copy);
|
||||
|
||||
if (!access(cp, X_OK)) { return cp; }
|
||||
|
||||
} else {
|
||||
|
||||
ck_free(own_copy);
|
||||
|
||||
}
|
||||
|
||||
if (!access(AFL_PATH "/libqasan.so", X_OK)) {
|
||||
|
||||
if (cp) { ck_free(cp); }
|
||||
|
||||
return ck_strdup(AFL_PATH "/libqasan.so");
|
||||
|
||||
}
|
||||
|
||||
SAYF("\n" cLRD "[-] " cRST
|
||||
"Oops, unable to find the 'libqasan.so' binary. The binary must be "
|
||||
"built\n"
|
||||
" separately by following the instructions in "
|
||||
"qemu_mode/libqasan/README.md. "
|
||||
"If you\n"
|
||||
" already have the binary installed, you may need to specify "
|
||||
"AFL_PATH in the\n"
|
||||
" environment.\n");
|
||||
|
||||
FATAL("Failed to locate 'libqasan.so'.");
|
||||
u8 *tmp = find_afl_binary(own_loc, "afl-qemu-trace");
|
||||
ck_free(tmp);
|
||||
*target_path_p = new_argv[0] = find_afl_binary(own_loc, "afl-wine-trace");
|
||||
return new_argv;
|
||||
|
||||
}
|
||||
|
||||
@ -488,6 +285,70 @@ u8 *find_binary(u8 *fname) {
|
||||
|
||||
}
|
||||
|
||||
u8 *find_afl_binary(u8 *own_loc, u8 *fname) {
|
||||
|
||||
u8 *afl_path = NULL, *target_path, *own_copy;
|
||||
|
||||
if ((afl_path = getenv("AFL_PATH"))) {
|
||||
|
||||
target_path = alloc_printf("%s/%s", afl_path, fname);
|
||||
if (!access(target_path, X_OK)) {
|
||||
|
||||
return target_path;
|
||||
|
||||
} else {
|
||||
|
||||
ck_free(target_path);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (own_loc) {
|
||||
|
||||
own_copy = ck_strdup(own_loc);
|
||||
u8 *rsl = strrchr(own_copy, '/');
|
||||
|
||||
if (rsl) {
|
||||
|
||||
*rsl = 0;
|
||||
|
||||
target_path = alloc_printf("%s/%s", own_copy, fname);
|
||||
ck_free(own_copy);
|
||||
|
||||
if (!access(target_path, X_OK)) {
|
||||
|
||||
return target_path;
|
||||
|
||||
} else {
|
||||
|
||||
ck_free(target_path);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
ck_free(own_copy);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
target_path = alloc_printf("%s/%s", BIN_PATH, fname);
|
||||
if (!access(target_path, X_OK)) {
|
||||
|
||||
return target_path;
|
||||
|
||||
} else {
|
||||
|
||||
ck_free(target_path);
|
||||
|
||||
}
|
||||
|
||||
return find_binary(fname);
|
||||
|
||||
}
|
||||
|
||||
/* Parses the kill signal environment variable, FATALs on error.
|
||||
If the env is not set, sets the env to default_signal for the signal handlers
|
||||
and returns the default_signal. */
|
||||
@ -682,6 +543,7 @@ void check_environment_vars(char **envp) {
|
||||
env[strlen(afl_environment_variables[i])] == '=') {
|
||||
|
||||
match = 1;
|
||||
|
||||
if ((val = getenv(afl_environment_variables[i])) && !*val) {
|
||||
|
||||
WARNF(
|
||||
@ -756,6 +618,98 @@ char *get_afl_env(char *env) {
|
||||
|
||||
}
|
||||
|
||||
bool extract_and_set_env(u8 *env_str) {
|
||||
|
||||
if (!env_str) { return false; }
|
||||
|
||||
bool ret = false; // return false by default
|
||||
|
||||
u8 *p = ck_strdup(env_str);
|
||||
u8 *end = p + strlen((char *)p);
|
||||
u8 *rest = p;
|
||||
|
||||
u8 closing_sym = ' ';
|
||||
u8 c;
|
||||
|
||||
size_t num_pairs = 0;
|
||||
|
||||
while (rest < end) {
|
||||
|
||||
while (*rest == ' ') {
|
||||
|
||||
rest++;
|
||||
|
||||
}
|
||||
|
||||
if (rest + 1 >= end) break;
|
||||
|
||||
u8 *key = rest;
|
||||
// env variable names may not start with numbers or '='
|
||||
if (*key == '=' || (*key >= '0' && *key <= '9')) { goto free_and_return; }
|
||||
|
||||
while (rest < end && *rest != '=' && *rest != ' ') {
|
||||
|
||||
c = *rest;
|
||||
// lowercase is bad but we may still allow it
|
||||
if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') &&
|
||||
(c < '0' || c > '9') && c != '_') {
|
||||
|
||||
goto free_and_return;
|
||||
|
||||
}
|
||||
|
||||
rest++;
|
||||
|
||||
}
|
||||
|
||||
if (*rest != '=') { goto free_and_return; }
|
||||
|
||||
*rest = '\0'; // done with variable name
|
||||
|
||||
rest += 1;
|
||||
if (rest >= end || *rest == ' ') { goto free_and_return; }
|
||||
|
||||
u8 *val = rest;
|
||||
if (*val == '\'' || *val == '"') {
|
||||
|
||||
closing_sym = *val;
|
||||
val += 1;
|
||||
rest += 1;
|
||||
if (rest >= end) { goto free_and_return; }
|
||||
|
||||
} else {
|
||||
|
||||
closing_sym = ' ';
|
||||
|
||||
}
|
||||
|
||||
while (rest < end && *rest != closing_sym) {
|
||||
|
||||
rest++;
|
||||
|
||||
}
|
||||
|
||||
if (closing_sym != ' ' && *rest != closing_sym) { goto free_and_return; }
|
||||
|
||||
*rest = '\0'; // done with variable value
|
||||
|
||||
rest += 1;
|
||||
if (rest < end && *rest != ' ') { goto free_and_return; }
|
||||
|
||||
num_pairs++;
|
||||
|
||||
setenv(key, val, 1);
|
||||
|
||||
}
|
||||
|
||||
if (num_pairs) { ret = true; }
|
||||
|
||||
free_and_return:
|
||||
ck_free(p);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* Read mask bitmap from file. This is for the -B option. */
|
||||
|
||||
void read_bitmap(u8 *fname, u8 *map, size_t len) {
|
||||
@ -1122,7 +1076,7 @@ u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms) {
|
||||
/* Reads the map size from ENV */
|
||||
u32 get_map_size(void) {
|
||||
|
||||
uint32_t map_size = (MAP_SIZE << 2); // needed for target ctors :(
|
||||
uint32_t map_size = DEFAULT_SHMEM_SIZE;
|
||||
char * ptr;
|
||||
|
||||
if ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE"))) {
|
||||
@ -1130,7 +1084,7 @@ u32 get_map_size(void) {
|
||||
map_size = atoi(ptr);
|
||||
if (!map_size || map_size > (1 << 29)) {
|
||||
|
||||
FATAL("illegal AFL_MAP_SIZE %u, must be between %u and %u", map_size, 32U,
|
||||
FATAL("illegal AFL_MAP_SIZE %u, must be between %u and %u", map_size, 64U,
|
||||
1U << 29);
|
||||
|
||||
}
|
||||
@ -1150,7 +1104,7 @@ FILE *create_ffile(u8 *fn) {
|
||||
s32 fd;
|
||||
FILE *f;
|
||||
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
|
||||
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
|
||||
|
||||
@ -1168,7 +1122,7 @@ s32 create_file(u8 *fn) {
|
||||
|
||||
s32 fd;
|
||||
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
|
||||
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
|
||||
|
||||
|
@ -481,27 +481,28 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
/* This should improve performance a bit, since it stops the linker from
|
||||
doing extra work post-fork(). */
|
||||
|
||||
if (!getenv("LD_BIND_LAZY")) { setenv("LD_BIND_NOW", "1", 0); }
|
||||
if (!getenv("LD_BIND_LAZY")) { setenv("LD_BIND_NOW", "1", 1); }
|
||||
|
||||
/* Set sane defaults for ASAN if nothing else specified. */
|
||||
|
||||
if (fsrv->debug == true && !getenv("ASAN_OPTIONS"))
|
||||
if (!getenv("ASAN_OPTIONS"))
|
||||
setenv("ASAN_OPTIONS",
|
||||
"abort_on_error=1:"
|
||||
"detect_leaks=0:"
|
||||
"malloc_context_size=0:"
|
||||
"symbolize=0:"
|
||||
"allocator_may_return_null=1:"
|
||||
"detect_odr_violation=0:"
|
||||
"handle_segv=0:"
|
||||
"handle_sigbus=0:"
|
||||
"handle_abort=0:"
|
||||
"handle_sigfpe=0:"
|
||||
"handle_sigill=0",
|
||||
0);
|
||||
1);
|
||||
|
||||
/* Set sane defaults for UBSAN if nothing else specified. */
|
||||
|
||||
if (fsrv->debug == true && !getenv("UBSAN_OPTIONS"))
|
||||
if (!getenv("UBSAN_OPTIONS"))
|
||||
setenv("UBSAN_OPTIONS",
|
||||
"halt_on_error=1:"
|
||||
"abort_on_error=1:"
|
||||
@ -513,7 +514,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
"handle_abort=0:"
|
||||
"handle_sigfpe=0:"
|
||||
"handle_sigill=0",
|
||||
0);
|
||||
1);
|
||||
|
||||
/* Envs for QASan */
|
||||
setenv("QASAN_MAX_CALL_STACK", "0", 0);
|
||||
@ -522,7 +523,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
/* MSAN is tricky, because it doesn't support abort_on_error=1 at this
|
||||
point. So, we do this in a very hacky way. */
|
||||
|
||||
if (fsrv->debug == true && !getenv("MSAN_OPTIONS"))
|
||||
if (!getenv("MSAN_OPTIONS"))
|
||||
setenv("MSAN_OPTIONS",
|
||||
"exit_code=" STRINGIFY(MSAN_ERROR) ":"
|
||||
"symbolize=0:"
|
||||
@ -535,7 +536,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
"handle_abort=0:"
|
||||
"handle_sigfpe=0:"
|
||||
"handle_sigill=0",
|
||||
0);
|
||||
1);
|
||||
|
||||
fsrv->init_child_func(fsrv, argv);
|
||||
|
||||
@ -808,7 +809,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
"have a\n"
|
||||
" restrictive memory limit configured, this is expected; please "
|
||||
"read\n"
|
||||
" %s/notes_for_asan.md for help.\n",
|
||||
" %s/notes_for_asan.md for help and run with '-m 0'.\n",
|
||||
doc_path);
|
||||
|
||||
} else if (!fsrv->mem_limit) {
|
||||
@ -816,18 +817,21 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
SAYF("\n" cLRD "[-] " cRST
|
||||
"Whoops, the target binary crashed suddenly, "
|
||||
"before receiving any input\n"
|
||||
" from the fuzzer! There are several probable explanations:\n\n"
|
||||
" from the fuzzer! You can try the following:\n\n"
|
||||
|
||||
" - The target binary requires a large map and crashes before "
|
||||
"reporting.\n"
|
||||
" Set a high value (e.g. AFL_MAP_SIZE=1024000) or use "
|
||||
"AFL_DEBUG=1 to see the\n"
|
||||
" message from the target binary\n\n"
|
||||
" - The target binary crashes because necessary runtime "
|
||||
"conditions it needs\n"
|
||||
" are not met. Try to:\n"
|
||||
" 1. Run again with AFL_DEBUG=1 set and check the output of "
|
||||
"the target\n"
|
||||
" binary for clues.\n"
|
||||
" 2. Run again with AFL_DEBUG=1 and 'ulimit -c unlimited' and "
|
||||
"analyze the\n"
|
||||
" generated core dump.\n\n"
|
||||
|
||||
" - The binary is just buggy and explodes entirely on its own. "
|
||||
"If so, you\n"
|
||||
" need to fix the underlying problem or find a better "
|
||||
"replacement.\n\n"
|
||||
" - Possibly the target requires a huge coverage map and has "
|
||||
"CTORS.\n"
|
||||
" Retry with setting AFL_MAP_SIZE=10000000.\n\n"
|
||||
|
||||
MSG_FORK_ON_APPLE
|
||||
|
||||
@ -843,13 +847,17 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
SAYF("\n" cLRD "[-] " cRST
|
||||
"Whoops, the target binary crashed suddenly, "
|
||||
"before receiving any input\n"
|
||||
" from the fuzzer! There are several probable explanations:\n\n"
|
||||
" from the fuzzer! You can try the following:\n\n"
|
||||
|
||||
" - The target binary requires a large map and crashes before "
|
||||
"reporting.\n"
|
||||
" Set a high value (e.g. AFL_MAP_SIZE=1024000) or use "
|
||||
"AFL_DEBUG=1 to see the\n"
|
||||
" message from the target binary\n\n"
|
||||
" - The target binary crashes because necessary runtime "
|
||||
"conditions it needs\n"
|
||||
" are not met. Try to:\n"
|
||||
" 1. Run again with AFL_DEBUG=1 set and check the output of "
|
||||
"the target\n"
|
||||
" binary for clues.\n"
|
||||
" 2. Run again with AFL_DEBUG=1 and 'ulimit -c unlimited' and "
|
||||
"analyze the\n"
|
||||
" generated core dump.\n\n"
|
||||
|
||||
" - The current memory limit (%s) is too restrictive, causing "
|
||||
"the\n"
|
||||
@ -867,13 +875,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
" estimate the required amount of virtual memory for the "
|
||||
"binary.\n\n"
|
||||
|
||||
" - The binary is just buggy and explodes entirely on its own. "
|
||||
"If so, you\n"
|
||||
" need to fix the underlying problem or find a better "
|
||||
"replacement.\n\n"
|
||||
|
||||
MSG_FORK_ON_APPLE
|
||||
|
||||
" - Possibly the target requires a huge coverage map and has "
|
||||
"CTORS.\n"
|
||||
" Retry with setting AFL_MAP_SIZE=10000000.\n\n"
|
||||
|
||||
" - Less likely, there is a horrible bug in the fuzzer. If other "
|
||||
"options\n"
|
||||
" fail, poke <afl-users@googlegroups.com> for troubleshooting "
|
||||
@ -902,16 +909,30 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
"with ASAN and\n"
|
||||
" you have a restrictive memory limit configured, this is "
|
||||
"expected; please\n"
|
||||
" read %s/notes_for_asan.md for help.\n",
|
||||
" read %s/notes_for_asan.md for help and run with '-m 0'.\n",
|
||||
doc_path);
|
||||
|
||||
} else if (!fsrv->mem_limit) {
|
||||
|
||||
SAYF("\n" cLRD "[-] " cRST
|
||||
"Hmm, looks like the target binary terminated before we could"
|
||||
" complete a handshake with the injected code.\n"
|
||||
"If the target was compiled with afl-clang-lto and AFL_LLVM_MAP_ADDR"
|
||||
" then recompiling without this parameter.\n"
|
||||
"Hmm, looks like the target binary terminated before we could complete"
|
||||
" a\n"
|
||||
"handshake with the injected code. You can try the following:\n\n"
|
||||
|
||||
" - The target binary crashes because necessary runtime conditions "
|
||||
"it needs\n"
|
||||
" are not met. Try to:\n"
|
||||
" 1. Run again with AFL_DEBUG=1 set and check the output of the "
|
||||
"target\n"
|
||||
" binary for clues.\n"
|
||||
" 2. Run again with AFL_DEBUG=1 and 'ulimit -c unlimited' and "
|
||||
"analyze the\n"
|
||||
" generated core dump.\n\n"
|
||||
|
||||
" - Possibly the target requires a huge coverage map and has "
|
||||
"CTORS.\n"
|
||||
" Retry with setting AFL_MAP_SIZE=10000000.\n\n"
|
||||
|
||||
"Otherwise there is a horrible bug in the fuzzer.\n"
|
||||
"Poke <afl-users@googlegroups.com> for troubleshooting tips.\n");
|
||||
|
||||
@ -923,10 +944,24 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
"\n" cLRD "[-] " cRST
|
||||
"Hmm, looks like the target binary terminated "
|
||||
"before we could complete a\n"
|
||||
" handshake with the injected code. There are %s probable "
|
||||
"explanations:\n\n"
|
||||
" handshake with the injected code. You can try the following:\n\n"
|
||||
|
||||
"%s"
|
||||
|
||||
" - The target binary crashes because necessary runtime conditions "
|
||||
"it needs\n"
|
||||
" are not met. Try to:\n"
|
||||
" 1. Run again with AFL_DEBUG=1 set and check the output of the "
|
||||
"target\n"
|
||||
" binary for clues.\n"
|
||||
" 2. Run again with AFL_DEBUG=1 and 'ulimit -c unlimited' and "
|
||||
"analyze the\n"
|
||||
" generated core dump.\n\n"
|
||||
|
||||
" - Possibly the target requires a huge coverage map and has "
|
||||
"CTORS.\n"
|
||||
" Retry with setting AFL_MAP_SIZE=10000000.\n\n"
|
||||
|
||||
" - The current memory limit (%s) is too restrictive, causing an "
|
||||
"OOM\n"
|
||||
" fault in the dynamic linker. This can be fixed with the -m "
|
||||
@ -950,7 +985,6 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
"options\n"
|
||||
" fail, poke <afl-users@googlegroups.com> for troubleshooting "
|
||||
"tips.\n",
|
||||
getenv(DEFER_ENV_VAR) ? "three" : "two",
|
||||
getenv(DEFER_ENV_VAR)
|
||||
? " - You are using deferred forkserver, but __AFL_INIT() is "
|
||||
"never\n"
|
||||
@ -1030,12 +1064,14 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) {
|
||||
|
||||
if (unlikely(fsrv->no_unlink)) {
|
||||
|
||||
fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||
fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
DEFAULT_PERMISSION);
|
||||
|
||||
} else {
|
||||
|
||||
unlink(fsrv->out_file); /* Ignore errors. */
|
||||
fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
||||
fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_EXCL,
|
||||
DEFAULT_PERMISSION);
|
||||
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ void write_bitmap(afl_state_t *afl) {
|
||||
afl->bitmap_changed = 0;
|
||||
|
||||
snprintf(fname, PATH_MAX, "%s/fuzz_bitmap", afl->out_dir);
|
||||
fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||
fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
|
||||
|
||||
if (fd < 0) { PFATAL("Unable to open '%s'", fname); }
|
||||
|
||||
@ -407,7 +407,7 @@ static void write_crash_readme(afl_state_t *afl) {
|
||||
|
||||
sprintf(fn, "%s/crashes/README.txt", afl->out_dir);
|
||||
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
|
||||
/* Do not die on errors here - that would be impolite. */
|
||||
|
||||
@ -509,7 +509,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
|
||||
alloc_printf("%s/queue/id_%06u", afl->out_dir, afl->queued_paths);
|
||||
|
||||
#endif /* ^!SIMPLE_FILES */
|
||||
fd = open(queue_fn, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
||||
fd = open(queue_fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", queue_fn); }
|
||||
ck_write(fd, mem, len, queue_fn);
|
||||
close(fd);
|
||||
@ -783,7 +783,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
|
||||
/* If we're here, we apparently want to save the crash or hang
|
||||
test case, too. */
|
||||
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", fn); }
|
||||
ck_write(fd, mem, len, fn);
|
||||
close(fd);
|
||||
|
@ -387,6 +387,130 @@ static inline u8 memcmp_nocase(u8 *m1, u8 *m2, u32 len) {
|
||||
|
||||
}
|
||||
|
||||
/* add an extra/dict/token - no checks performed, no sorting */
|
||||
|
||||
static void add_extra_nocheck(afl_state_t *afl, u8 *mem, u32 len) {
|
||||
|
||||
afl->extras = afl_realloc((void **)&afl->extras,
|
||||
(afl->extras_cnt + 1) * sizeof(struct extra_data));
|
||||
|
||||
if (unlikely(!afl->extras)) { PFATAL("alloc"); }
|
||||
|
||||
afl->extras[afl->extras_cnt].data = ck_alloc(len);
|
||||
afl->extras[afl->extras_cnt].len = len;
|
||||
memcpy(afl->extras[afl->extras_cnt].data, mem, len);
|
||||
afl->extras_cnt++;
|
||||
|
||||
/* We only want to print this once */
|
||||
|
||||
if (afl->extras_cnt == afl->max_det_extras + 1) {
|
||||
|
||||
WARNF("More than %u tokens - will use them probabilistically.",
|
||||
afl->max_det_extras);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Sometimes strings in input is transformed to unicode internally, so for
|
||||
fuzzing we should attempt to de-unicode if it looks like simple unicode */
|
||||
|
||||
void deunicode_extras(afl_state_t *afl) {
|
||||
|
||||
if (!afl->extras_cnt) return;
|
||||
|
||||
u32 i, j, orig_cnt = afl->extras_cnt;
|
||||
u8 buf[64];
|
||||
|
||||
for (i = 0; i < orig_cnt; ++i) {
|
||||
|
||||
if (afl->extras[i].len < 6 || afl->extras[i].len > 64 ||
|
||||
afl->extras[i].len % 2) {
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
u32 k = 0, z1 = 0, z2 = 0, z3 = 0, z4 = 0, half = afl->extras[i].len >> 1;
|
||||
u32 quarter = half >> 1;
|
||||
|
||||
for (j = 0; j < afl->extras[i].len; ++j) {
|
||||
|
||||
switch (j % 4) {
|
||||
|
||||
case 2:
|
||||
if (!afl->extras[i].data[j]) { ++z3; }
|
||||
// fall through
|
||||
case 0:
|
||||
if (!afl->extras[i].data[j]) { ++z1; }
|
||||
break;
|
||||
case 3:
|
||||
if (!afl->extras[i].data[j]) { ++z4; }
|
||||
// fall through
|
||||
case 1:
|
||||
if (!afl->extras[i].data[j]) { ++z2; }
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ((z1 < half && z2 < half) || z1 + z2 == afl->extras[i].len) { continue; }
|
||||
|
||||
// also maybe 32 bit unicode?
|
||||
if (afl->extras[i].len % 4 == 0 && afl->extras[i].len >= 12 &&
|
||||
(z3 == quarter || z4 == quarter) && z1 + z2 == quarter * 3) {
|
||||
|
||||
for (j = 0; j < afl->extras[i].len; ++j) {
|
||||
|
||||
if (z4 < quarter) {
|
||||
|
||||
if (j % 4 == 3) { buf[k++] = afl->extras[i].data[j]; }
|
||||
|
||||
} else if (z3 < quarter) {
|
||||
|
||||
if (j % 4 == 2) { buf[k++] = afl->extras[i].data[j]; }
|
||||
|
||||
} else if (z2 < half) {
|
||||
|
||||
if (j % 4 == 1) { buf[k++] = afl->extras[i].data[j]; }
|
||||
|
||||
} else {
|
||||
|
||||
if (j % 4 == 0) { buf[k++] = afl->extras[i].data[j]; }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
add_extra_nocheck(afl, buf, k);
|
||||
k = 0;
|
||||
|
||||
}
|
||||
|
||||
for (j = 0; j < afl->extras[i].len; ++j) {
|
||||
|
||||
if (z1 < half) {
|
||||
|
||||
if (j % 2 == 0) { buf[k++] = afl->extras[i].data[j]; }
|
||||
|
||||
} else {
|
||||
|
||||
if (j % 2 == 1) { buf[k++] = afl->extras[i].data[j]; }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
add_extra_nocheck(afl, buf, k);
|
||||
|
||||
}
|
||||
|
||||
qsort(afl->extras, afl->extras_cnt, sizeof(struct extra_data),
|
||||
compare_extras_len);
|
||||
|
||||
}
|
||||
|
||||
/* Removes duplicates from the loaded extras. This can happen if multiple files
|
||||
are loaded */
|
||||
|
||||
@ -396,9 +520,9 @@ void dedup_extras(afl_state_t *afl) {
|
||||
|
||||
u32 i, j, orig_cnt = afl->extras_cnt;
|
||||
|
||||
for (i = 0; i < afl->extras_cnt - 1; i++) {
|
||||
for (i = 0; i < afl->extras_cnt - 1; ++i) {
|
||||
|
||||
for (j = i + 1; j < afl->extras_cnt; j++) {
|
||||
for (j = i + 1; j < afl->extras_cnt; ++j) {
|
||||
|
||||
restart_dedup:
|
||||
|
||||
@ -462,30 +586,11 @@ void add_extra(afl_state_t *afl, u8 *mem, u32 len) {
|
||||
|
||||
}
|
||||
|
||||
afl->extras = afl_realloc((void **)&afl->extras,
|
||||
(afl->extras_cnt + 1) * sizeof(struct extra_data));
|
||||
|
||||
if (unlikely(!afl->extras)) { PFATAL("alloc"); }
|
||||
|
||||
afl->extras[afl->extras_cnt].data = ck_alloc(len);
|
||||
afl->extras[afl->extras_cnt].len = len;
|
||||
|
||||
memcpy(afl->extras[afl->extras_cnt].data, mem, len);
|
||||
|
||||
afl->extras_cnt++;
|
||||
add_extra_nocheck(afl, mem, len);
|
||||
|
||||
qsort(afl->extras, afl->extras_cnt, sizeof(struct extra_data),
|
||||
compare_extras_len);
|
||||
|
||||
/* We only want to print this once */
|
||||
|
||||
if (afl->extras_cnt == afl->max_det_extras + 1) {
|
||||
|
||||
WARNF("More than %u tokens - will use them probabilistically.",
|
||||
afl->max_det_extras);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Maybe add automatic extra. */
|
||||
@ -626,7 +731,7 @@ void save_auto(afl_state_t *afl) {
|
||||
alloc_printf("%s/queue/.state/auto_extras/auto_%06u", afl->out_dir, i);
|
||||
s32 fd;
|
||||
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
|
||||
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
|
||||
|
||||
|
@ -152,7 +152,8 @@ void bind_to_free_cpu(afl_state_t *afl) {
|
||||
|
||||
do {
|
||||
|
||||
if ((lockfd = open(lockfile, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0) {
|
||||
if ((lockfd = open(lockfile, O_RDWR | O_CREAT | O_EXCL,
|
||||
DEFAULT_PERMISSION)) < 0) {
|
||||
|
||||
if (first) {
|
||||
|
||||
@ -828,7 +829,7 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
for (idx = 0; idx < afl->queued_paths; idx++) {
|
||||
|
||||
q = afl->queue_buf[idx];
|
||||
if (unlikely(q->disabled)) { continue; }
|
||||
if (unlikely(!q || q->disabled)) { continue; }
|
||||
|
||||
u8 res;
|
||||
s32 fd;
|
||||
@ -1069,7 +1070,7 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
}
|
||||
|
||||
afl->max_depth = 0;
|
||||
for (i = 0; i < afl->queued_paths; i++) {
|
||||
for (i = 0; i < afl->queued_paths && likely(afl->queue_buf[i]); i++) {
|
||||
|
||||
if (!afl->queue_buf[i]->disabled &&
|
||||
afl->queue_buf[i]->depth > afl->max_depth)
|
||||
@ -1136,10 +1137,11 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
for (idx = 0; idx < afl->queued_paths; idx++) {
|
||||
|
||||
q = afl->queue_buf[idx];
|
||||
if (q->disabled || q->cal_failed || !q->exec_cksum) { continue; }
|
||||
if (!q || q->disabled || q->cal_failed || !q->exec_cksum) { continue; }
|
||||
|
||||
u32 done = 0;
|
||||
for (i = idx + 1; i < afl->queued_paths && !done; i++) {
|
||||
for (i = idx + 1;
|
||||
i < afl->queued_paths && !done && likely(afl->queue_buf[i]); i++) {
|
||||
|
||||
struct queue_entry *p = afl->queue_buf[i];
|
||||
if (p->disabled || p->cal_failed || !p->exec_cksum) { continue; }
|
||||
@ -1191,7 +1193,7 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
|
||||
for (idx = 0; idx < afl->queued_paths; idx++) {
|
||||
|
||||
if (!afl->queue_buf[idx]->disabled &&
|
||||
if (afl->queue_buf[idx] && !afl->queue_buf[idx]->disabled &&
|
||||
afl->queue_buf[idx]->depth > afl->max_depth)
|
||||
afl->max_depth = afl->queue_buf[idx]->depth;
|
||||
|
||||
@ -1218,7 +1220,7 @@ static void link_or_copy(u8 *old_path, u8 *new_path) {
|
||||
sfd = open(old_path, O_RDONLY);
|
||||
if (sfd < 0) { PFATAL("Unable to open '%s'", old_path); }
|
||||
|
||||
dfd = open(new_path, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
||||
dfd = open(new_path, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
if (dfd < 0) { PFATAL("Unable to create '%s'", new_path); }
|
||||
|
||||
tmp = ck_alloc(64 * 1024);
|
||||
@ -1247,7 +1249,7 @@ void pivot_inputs(afl_state_t *afl) {
|
||||
|
||||
ACTF("Creating hard links for all input files...");
|
||||
|
||||
for (i = 0; i < afl->queued_paths; i++) {
|
||||
for (i = 0; i < afl->queued_paths && likely(afl->queue_buf[i]); i++) {
|
||||
|
||||
q = afl->queue_buf[i];
|
||||
|
||||
@ -1811,9 +1813,13 @@ static void handle_existing_out_dir(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
fn = alloc_printf("%s/plot_data", afl->out_dir);
|
||||
if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
|
||||
ck_free(fn);
|
||||
if (!afl->in_place_resume) {
|
||||
|
||||
fn = alloc_printf("%s/plot_data", afl->out_dir);
|
||||
if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
|
||||
ck_free(fn);
|
||||
|
||||
}
|
||||
|
||||
fn = alloc_printf("%s/cmdline", afl->out_dir);
|
||||
if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
|
||||
@ -2007,17 +2013,35 @@ void setup_dirs_fds(afl_state_t *afl) {
|
||||
/* Gnuplot output file. */
|
||||
|
||||
tmp = alloc_printf("%s/plot_data", afl->out_dir);
|
||||
int fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", tmp); }
|
||||
ck_free(tmp);
|
||||
|
||||
afl->fsrv.plot_file = fdopen(fd, "w");
|
||||
if (!afl->fsrv.plot_file) { PFATAL("fdopen() failed"); }
|
||||
if (!afl->in_place_resume) {
|
||||
|
||||
int fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", tmp); }
|
||||
ck_free(tmp);
|
||||
|
||||
afl->fsrv.plot_file = fdopen(fd, "w");
|
||||
if (!afl->fsrv.plot_file) { PFATAL("fdopen() failed"); }
|
||||
|
||||
fprintf(
|
||||
afl->fsrv.plot_file,
|
||||
"# unix_time, cycles_done, cur_path, paths_total, "
|
||||
"pending_total, pending_favs, map_size, unique_crashes, "
|
||||
"unique_hangs, max_depth, execs_per_sec, total_execs, edges_found\n");
|
||||
|
||||
} else {
|
||||
|
||||
int fd = open(tmp, O_WRONLY | O_CREAT, DEFAULT_PERMISSION);
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", tmp); }
|
||||
ck_free(tmp);
|
||||
|
||||
afl->fsrv.plot_file = fdopen(fd, "w");
|
||||
if (!afl->fsrv.plot_file) { PFATAL("fdopen() failed"); }
|
||||
|
||||
fseek(afl->fsrv.plot_file, 0, SEEK_END);
|
||||
|
||||
}
|
||||
|
||||
fprintf(afl->fsrv.plot_file,
|
||||
"# unix_time, cycles_done, cur_path, paths_total, "
|
||||
"pending_total, pending_favs, map_size, unique_crashes, "
|
||||
"unique_hangs, max_depth, execs_per_sec, total_execs, edges_found\n");
|
||||
fflush(afl->fsrv.plot_file);
|
||||
|
||||
/* ignore errors */
|
||||
@ -2034,7 +2058,7 @@ void setup_cmdline_file(afl_state_t *afl, char **argv) {
|
||||
|
||||
/* Store the command line to reproduce our findings */
|
||||
tmp = alloc_printf("%s/cmdline", afl->out_dir);
|
||||
fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
||||
fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", tmp); }
|
||||
ck_free(tmp);
|
||||
|
||||
@ -2069,7 +2093,8 @@ void setup_stdio_file(afl_state_t *afl) {
|
||||
|
||||
unlink(afl->fsrv.out_file); /* Ignore errors */
|
||||
|
||||
afl->fsrv.out_fd = open(afl->fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||
afl->fsrv.out_fd =
|
||||
open(afl->fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
|
||||
if (afl->fsrv.out_fd < 0) {
|
||||
|
||||
@ -2457,7 +2482,7 @@ void check_asan_opts(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
if (!strstr(x, "symbolize=0")) {
|
||||
if (!afl->debug && !strstr(x, "symbolize=0")) {
|
||||
|
||||
FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!");
|
||||
|
||||
@ -2591,6 +2616,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
|
||||
}
|
||||
|
||||
if (afl->afl_env.afl_skip_bin_check || afl->use_wine || afl->unicorn_mode ||
|
||||
(afl->fsrv.qemu_mode && getenv("AFL_QEMU_CUSTOM_BIN")) ||
|
||||
afl->non_instrumented_mode) {
|
||||
|
||||
return;
|
||||
|
@ -465,7 +465,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
|
||||
|
||||
unlink(q->fname); /* ignore errors */
|
||||
|
||||
fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
||||
fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); }
|
||||
|
||||
|
@ -5119,14 +5119,23 @@ pacemaker_fuzzing:
|
||||
|
||||
/* Update afl->pending_not_fuzzed count if we made it through the
|
||||
calibration cycle and have not seen this entry before. */
|
||||
/*
|
||||
// TODO FIXME: I think we need this plus need an -L -1 check
|
||||
if (!afl->stop_soon && !afl->queue_cur->cal_failed &&
|
||||
(afl->queue_cur->was_fuzzed == 0 || afl->queue_cur->fuzz_level == 0)
|
||||
&& !afl->queue_cur->disabled) {
|
||||
|
||||
// if (!afl->stop_soon && !afl->queue_cur->cal_failed &&
|
||||
// !afl->queue_cur->was_fuzzed) {
|
||||
if (!afl->queue_cur->was_fuzzed) {
|
||||
|
||||
// afl->queue_cur->was_fuzzed = 1;
|
||||
// --afl->pending_not_fuzzed;
|
||||
// if (afl->queue_cur->favored) --afl->pending_favored;
|
||||
// }
|
||||
--afl->pending_not_fuzzed;
|
||||
afl->queue_cur->was_fuzzed = 1;
|
||||
if (afl->queue_cur->favored) { --afl->pending_favored; }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
orig_in = NULL;
|
||||
|
||||
|
@ -198,34 +198,35 @@ void create_alias_table(afl_state_t *afl) {
|
||||
while (nS)
|
||||
afl->alias_probability[S[--nS]] = 1;
|
||||
|
||||
#ifdef INTROSPECTION
|
||||
u8 fn[PATH_MAX];
|
||||
snprintf(fn, PATH_MAX, "%s/introspection_corpus.txt", afl->out_dir);
|
||||
FILE *f = fopen(fn, "a");
|
||||
if (f) {
|
||||
/*
|
||||
#ifdef INTROSPECTION
|
||||
u8 fn[PATH_MAX];
|
||||
snprintf(fn, PATH_MAX, "%s/introspection_corpus.txt", afl->out_dir);
|
||||
FILE *f = fopen(fn, "a");
|
||||
if (f) {
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
for (i = 0; i < n; i++) {
|
||||
|
||||
struct queue_entry *q = afl->queue_buf[i];
|
||||
fprintf(
|
||||
f,
|
||||
"entry=%u name=%s favored=%s variable=%s disabled=%s len=%u "
|
||||
"exec_us=%u "
|
||||
"bitmap_size=%u bitsmap_size=%u tops=%u weight=%f perf_score=%f\n",
|
||||
i, q->fname, q->favored ? "true" : "false",
|
||||
q->var_behavior ? "true" : "false", q->disabled ? "true" : "false",
|
||||
q->len, (u32)q->exec_us, q->bitmap_size, q->bitsmap_size, q->tc_ref,
|
||||
q->weight, q->perf_score);
|
||||
struct queue_entry *q = afl->queue_buf[i];
|
||||
fprintf(
|
||||
f,
|
||||
"entry=%u name=%s favored=%s variable=%s disabled=%s len=%u "
|
||||
"exec_us=%u "
|
||||
"bitmap_size=%u bitsmap_size=%u tops=%u weight=%f perf_score=%f\n",
|
||||
i, q->fname, q->favored ? "true" : "false",
|
||||
q->var_behavior ? "true" : "false", q->disabled ? "true" : "false",
|
||||
q->len, (u32)q->exec_us, q->bitmap_size, q->bitsmap_size, q->tc_ref,
|
||||
q->weight, q->perf_score);
|
||||
|
||||
}
|
||||
|
||||
fprintf(f, "\n");
|
||||
fclose(f);
|
||||
|
||||
}
|
||||
|
||||
fprintf(f, "\n");
|
||||
fclose(f);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
*/
|
||||
/*
|
||||
fprintf(stderr, " entry alias probability perf_score weight
|
||||
filename\n"); for (u32 i = 0; i < n; ++i) fprintf(stderr, " %5u %5u %11u
|
||||
@ -248,7 +249,7 @@ void mark_as_det_done(afl_state_t *afl, struct queue_entry *q) {
|
||||
snprintf(fn, PATH_MAX, "%s/queue/.state/deterministic_done/%s", afl->out_dir,
|
||||
strrchr(q->fname, '/') + 1);
|
||||
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
|
||||
close(fd);
|
||||
|
||||
@ -271,7 +272,7 @@ void mark_as_variable(afl_state_t *afl, struct queue_entry *q) {
|
||||
|
||||
if (symlink(ldest, fn)) {
|
||||
|
||||
s32 fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
||||
s32 fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
|
||||
close(fd);
|
||||
|
||||
@ -299,7 +300,7 @@ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) {
|
||||
|
||||
s32 fd;
|
||||
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
|
||||
close(fd);
|
||||
|
||||
@ -324,7 +325,7 @@ static u8 check_if_text(afl_state_t *afl, struct queue_entry *q) {
|
||||
|
||||
if (len >= MAX_FILE) len = MAX_FILE - 1;
|
||||
if ((fd = open(q->fname, O_RDONLY)) < 0) return 0;
|
||||
buf = afl_realloc(AFL_BUF_PARAM(in_scratch), len);
|
||||
buf = afl_realloc(AFL_BUF_PARAM(in_scratch), len + 1);
|
||||
comp = read(fd, buf, len);
|
||||
close(fd);
|
||||
if (comp != (ssize_t)len) return 0;
|
||||
@ -679,13 +680,17 @@ void cull_queue(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
afl->top_rated[i]->favored = 1;
|
||||
++afl->queued_favored;
|
||||
if (!afl->top_rated[i]->favored) {
|
||||
|
||||
if (afl->top_rated[i]->fuzz_level == 0 ||
|
||||
!afl->top_rated[i]->was_fuzzed) {
|
||||
afl->top_rated[i]->favored = 1;
|
||||
++afl->queued_favored;
|
||||
|
||||
++afl->pending_favored;
|
||||
if (afl->top_rated[i]->fuzz_level == 0 ||
|
||||
!afl->top_rated[i]->was_fuzzed) {
|
||||
|
||||
++afl->pending_favored;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -83,7 +83,8 @@ write_to_testcase(afl_state_t *afl, void *mem, u32 len) {
|
||||
afl->document_counter++,
|
||||
describe_op(afl, 0, NAME_MAX - strlen("000000000:")));
|
||||
|
||||
if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600)) >= 0) {
|
||||
if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION)) >=
|
||||
0) {
|
||||
|
||||
if (write(doc_fd, mem, len) != len)
|
||||
PFATAL("write to mutation file failed: %s", fn);
|
||||
@ -247,12 +248,14 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at,
|
||||
|
||||
if (unlikely(afl->no_unlink)) {
|
||||
|
||||
fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||
fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
DEFAULT_PERMISSION);
|
||||
|
||||
} else {
|
||||
|
||||
unlink(afl->fsrv.out_file); /* Ignore errors. */
|
||||
fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
||||
fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_EXCL,
|
||||
DEFAULT_PERMISSION);
|
||||
|
||||
}
|
||||
|
||||
@ -564,7 +567,8 @@ void sync_fuzzers(afl_state_t *afl) {
|
||||
/* document the attempt to sync to this instance */
|
||||
|
||||
sprintf(qd_synced_path, "%s/.synced/%s.last", afl->out_dir, sd_ent->d_name);
|
||||
id_fd = open(qd_synced_path, O_RDWR | O_CREAT | O_TRUNC, 0600);
|
||||
id_fd =
|
||||
open(qd_synced_path, O_RDWR | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
|
||||
if (id_fd >= 0) close(id_fd);
|
||||
|
||||
/* Skip anything that doesn't have a queue/ subdirectory. */
|
||||
@ -587,7 +591,7 @@ void sync_fuzzers(afl_state_t *afl) {
|
||||
|
||||
sprintf(qd_synced_path, "%s/.synced/%s", afl->out_dir, sd_ent->d_name);
|
||||
|
||||
id_fd = open(qd_synced_path, O_RDWR | O_CREAT, 0600);
|
||||
id_fd = open(qd_synced_path, O_RDWR | O_CREAT, DEFAULT_PERMISSION);
|
||||
|
||||
if (id_fd < 0) { PFATAL("Unable to create '%s'", qd_synced_path); }
|
||||
|
||||
@ -851,7 +855,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
|
||||
|
||||
if (unlikely(afl->no_unlink)) {
|
||||
|
||||
fd = open(q->fname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||
fd = open(q->fname, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
|
||||
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); }
|
||||
|
||||
@ -866,7 +870,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
|
||||
} else {
|
||||
|
||||
unlink(q->fname); /* ignore errors */
|
||||
fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
||||
fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); }
|
||||
|
||||
|
@ -433,6 +433,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
|
||||
afl->afl_env.afl_kill_signal =
|
||||
(u8 *)get_afl_env(afl_environment_variables[i]);
|
||||
|
||||
} else if (!strncmp(env, "AFL_TARGET_ENV",
|
||||
|
||||
afl_environment_variable_len)) {
|
||||
|
||||
afl->afl_env.afl_target_env =
|
||||
(u8 *)get_afl_env(afl_environment_variables[i]);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -391,10 +391,11 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
|
||||
fprintf(afl->fsrv.plot_file,
|
||||
"%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f, %llu, "
|
||||
"%u\n",
|
||||
get_cur_time() / 1000, afl->queue_cycle - 1, afl->current_entry,
|
||||
afl->queued_paths, afl->pending_not_fuzzed, afl->pending_favored,
|
||||
bitmap_cvg, afl->unique_crashes, afl->unique_hangs, afl->max_depth,
|
||||
eps, afl->plot_prev_ed, t_bytes); /* ignore errors */
|
||||
(afl->prev_run_time + get_cur_time() - afl->start_time),
|
||||
afl->queue_cycle - 1, afl->current_entry, afl->queued_paths,
|
||||
afl->pending_not_fuzzed, afl->pending_favored, bitmap_cvg,
|
||||
afl->unique_crashes, afl->unique_hangs, afl->max_depth, eps,
|
||||
afl->plot_prev_ed, t_bytes); /* ignore errors */
|
||||
|
||||
fflush(afl->fsrv.plot_file);
|
||||
|
||||
@ -645,6 +646,13 @@ void show_stats(afl_state_t *afl) {
|
||||
#define SP10 SP5 SP5
|
||||
#define SP20 SP10 SP10
|
||||
|
||||
/* Since `total_crashes` does not get reloaded from disk on restart,
|
||||
it indicates if we found crashes this round already -> paint red.
|
||||
If it's 0, but `unique_crashes` is set from a past run, paint in yellow. */
|
||||
char *crash_color = afl->total_crashes ? cLRD
|
||||
: afl->unique_crashes ? cYEL
|
||||
: cRST;
|
||||
|
||||
/* Lord, forgive me this. */
|
||||
|
||||
SAYF(SET_G1 bSTG bLT bH bSTOP cCYA
|
||||
@ -732,7 +740,7 @@ void show_stats(afl_state_t *afl) {
|
||||
u_stringify_time_diff(time_tmp, cur_ms, afl->last_crash_time);
|
||||
SAYF(bV bSTOP " last uniq crash : " cRST "%-33s " bSTG bV bSTOP
|
||||
" uniq crashes : %s%-6s" bSTG bV "\n",
|
||||
time_tmp, afl->unique_crashes ? cLRD : cRST, tmp);
|
||||
time_tmp, crash_color, tmp);
|
||||
|
||||
sprintf(tmp, "%s%s", u_stringify_int(IB(0), afl->unique_hangs),
|
||||
(afl->unique_hangs >= KEEP_UNIQUE_HANG) ? "+" : "");
|
||||
@ -815,15 +823,13 @@ void show_stats(afl_state_t *afl) {
|
||||
|
||||
SAYF(bV bSTOP " total execs : " cRST "%-20s " bSTG bV bSTOP
|
||||
" new crashes : %s%-22s" bSTG bV "\n",
|
||||
u_stringify_int(IB(0), afl->fsrv.total_execs),
|
||||
afl->unique_crashes ? cLRD : cRST, tmp);
|
||||
u_stringify_int(IB(0), afl->fsrv.total_execs), crash_color, tmp);
|
||||
|
||||
} else {
|
||||
|
||||
SAYF(bV bSTOP " total execs : " cRST "%-20s " bSTG bV bSTOP
|
||||
" total crashes : %s%-22s" bSTG bV "\n",
|
||||
u_stringify_int(IB(0), afl->fsrv.total_execs),
|
||||
afl->unique_crashes ? cLRD : cRST, tmp);
|
||||
u_stringify_int(IB(0), afl->fsrv.total_execs), crash_color, tmp);
|
||||
|
||||
}
|
||||
|
||||
|
258
src/afl-fuzz.c
258
src/afl-fuzz.c
@ -223,6 +223,7 @@ static void usage(u8 *argv0, int more_help) {
|
||||
"AFL_PYTHON_MODULE: mutate and trim inputs with the specified Python module\n"
|
||||
"AFL_QUIET: suppress forkserver status messages\n"
|
||||
"AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
|
||||
"AFL_TARGET_ENV: pass extra environment variables to target\n"
|
||||
"AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n"
|
||||
"AFL_SKIP_BIN_CHECK: skip the check, if the target is an executable\n"
|
||||
"AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n"
|
||||
@ -351,7 +352,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
exit_1 = !!afl->afl_env.afl_bench_just_one;
|
||||
|
||||
SAYF(cCYA "afl-fuzz" VERSION cRST
|
||||
" based on afl by Michal Zalewski and a big online community\n");
|
||||
" based on afl by Michal Zalewski and a large online community\n");
|
||||
|
||||
doc_path = access(DOC_PATH, F_OK) != 0 ? (u8 *)"docs" : (u8 *)DOC_PATH;
|
||||
|
||||
@ -1022,32 +1023,6 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if (afl->fsrv.qemu_mode && getenv("AFL_USE_QASAN")) {
|
||||
|
||||
u8 *preload = getenv("AFL_PRELOAD");
|
||||
u8 *libqasan = get_libqasan_path(argv_orig[0]);
|
||||
|
||||
if (!preload) {
|
||||
|
||||
setenv("AFL_PRELOAD", libqasan, 0);
|
||||
|
||||
} else {
|
||||
|
||||
u8 *result = ck_alloc(strlen(libqasan) + strlen(preload) + 2);
|
||||
strcpy(result, libqasan);
|
||||
strcat(result, " ");
|
||||
strcat(result, preload);
|
||||
|
||||
setenv("AFL_PRELOAD", result, 1);
|
||||
ck_free(result);
|
||||
|
||||
}
|
||||
|
||||
afl->afl_env.afl_preload = (u8 *)getenv("AFL_PRELOAD");
|
||||
ck_free(libqasan);
|
||||
|
||||
}
|
||||
|
||||
if (afl->fsrv.mem_limit && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260;
|
||||
|
||||
OKF("afl++ is maintained by Marc \"van Hauser\" Heuse, Heiko \"hexcoder\" "
|
||||
@ -1312,38 +1287,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
if (afl->fsrv.qemu_mode) {
|
||||
|
||||
u8 *qemu_preload = getenv("QEMU_SET_ENV");
|
||||
u8 *afl_preload = getenv("AFL_PRELOAD");
|
||||
u8 *buf;
|
||||
|
||||
s32 j, afl_preload_size = strlen(afl_preload);
|
||||
for (j = 0; j < afl_preload_size; ++j) {
|
||||
|
||||
if (afl_preload[j] == ',') {
|
||||
|
||||
PFATAL(
|
||||
"Comma (',') is not allowed in AFL_PRELOAD when -Q is "
|
||||
"specified!");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (qemu_preload) {
|
||||
|
||||
buf = alloc_printf("%s,LD_PRELOAD=%s,DYLD_INSERT_LIBRARIES=%s",
|
||||
qemu_preload, afl_preload, afl_preload);
|
||||
|
||||
} else {
|
||||
|
||||
buf = alloc_printf("LD_PRELOAD=%s,DYLD_INSERT_LIBRARIES=%s",
|
||||
afl_preload, afl_preload);
|
||||
|
||||
}
|
||||
|
||||
setenv("QEMU_SET_ENV", buf, 1);
|
||||
|
||||
ck_free(buf);
|
||||
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
|
||||
|
||||
} else {
|
||||
|
||||
@ -1360,6 +1304,13 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if (afl->afl_env.afl_target_env &&
|
||||
!extract_and_set_env(afl->afl_env.afl_target_env)) {
|
||||
|
||||
FATAL("Bad value of AFL_TARGET_ENV");
|
||||
|
||||
}
|
||||
|
||||
save_cmdline(afl, argc, argv);
|
||||
|
||||
fix_up_banner(afl, argv[optind]);
|
||||
@ -1403,6 +1354,15 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
set_scheduler_mode(SCHEDULER_MODE_LOW_LATENCY);
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
if (pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0) != 0) {
|
||||
|
||||
WARNF("general thread priority settings failed");
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
init_count_class16();
|
||||
|
||||
if (afl->is_main_node && check_main_node_exists(afl) == 1) {
|
||||
@ -1437,23 +1397,8 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
// read_foreign_testcases(afl, 1); for the moment dont do this
|
||||
OKF("Loaded a total of %u seeds.", afl->queued_paths);
|
||||
|
||||
load_auto(afl);
|
||||
|
||||
pivot_inputs(afl);
|
||||
|
||||
if (extras_dir_cnt) {
|
||||
|
||||
for (i = 0; i < extras_dir_cnt; i++) {
|
||||
|
||||
load_extras(afl, extras_dir[i]);
|
||||
|
||||
}
|
||||
|
||||
dedup_extras(afl);
|
||||
OKF("Loaded a total of %u extras.", afl->extras_cnt);
|
||||
|
||||
}
|
||||
|
||||
if (!afl->timeout_given) { find_timeout(afl); } // only for resumes!
|
||||
|
||||
if ((afl->tmp_dir = afl->afl_env.afl_tmpdir) != NULL &&
|
||||
@ -1568,6 +1513,21 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if (afl->non_instrumented_mode || afl->fsrv.qemu_mode || afl->unicorn_mode) {
|
||||
|
||||
map_size = afl->fsrv.map_size = MAP_SIZE;
|
||||
afl->virgin_bits = ck_realloc(afl->virgin_bits, map_size);
|
||||
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, map_size);
|
||||
afl->virgin_crash = ck_realloc(afl->virgin_crash, map_size);
|
||||
afl->var_bytes = ck_realloc(afl->var_bytes, map_size);
|
||||
afl->top_rated = ck_realloc(afl->top_rated, map_size * sizeof(void *));
|
||||
afl->clean_trace = ck_realloc(afl->clean_trace, map_size);
|
||||
afl->clean_trace_custom = ck_realloc(afl->clean_trace_custom, map_size);
|
||||
afl->first_trace = ck_realloc(afl->first_trace, map_size);
|
||||
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, map_size);
|
||||
|
||||
}
|
||||
|
||||
afl->argv = use_argv;
|
||||
afl->fsrv.trace_bits =
|
||||
afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->non_instrumented_mode);
|
||||
@ -1575,49 +1535,49 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
if (!afl->non_instrumented_mode && !afl->fsrv.qemu_mode &&
|
||||
!afl->unicorn_mode) {
|
||||
|
||||
afl->fsrv.map_size = 4194304; // dummy temporary value
|
||||
setenv("AFL_MAP_SIZE", "4194304", 1);
|
||||
if (map_size <= DEFAULT_SHMEM_SIZE && !afl->non_instrumented_mode &&
|
||||
!afl->fsrv.qemu_mode && !afl->unicorn_mode) {
|
||||
|
||||
afl->fsrv.map_size = DEFAULT_SHMEM_SIZE; // dummy temporary value
|
||||
char vbuf[16];
|
||||
snprintf(vbuf, sizeof(vbuf), "%u", DEFAULT_SHMEM_SIZE);
|
||||
setenv("AFL_MAP_SIZE", vbuf, 1);
|
||||
|
||||
}
|
||||
|
||||
u32 new_map_size = afl_fsrv_get_mapsize(
|
||||
&afl->fsrv, afl->argv, &afl->stop_soon, afl->afl_env.afl_debug_child);
|
||||
|
||||
if (new_map_size && new_map_size != 4194304) {
|
||||
// only reinitialize if the map needs to be larger than what we have.
|
||||
if (map_size < new_map_size) {
|
||||
|
||||
// only reinitialize when it makes sense
|
||||
if (map_size < new_map_size ||
|
||||
(new_map_size > map_size && new_map_size - map_size > MAP_SIZE)) {
|
||||
OKF("Re-initializing maps to %u bytes", new_map_size);
|
||||
|
||||
OKF("Re-initializing maps to %u bytes", new_map_size);
|
||||
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
|
||||
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
|
||||
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
|
||||
afl->var_bytes = ck_realloc(afl->var_bytes, new_map_size);
|
||||
afl->top_rated =
|
||||
ck_realloc(afl->top_rated, new_map_size * sizeof(void *));
|
||||
afl->clean_trace = ck_realloc(afl->clean_trace, new_map_size);
|
||||
afl->clean_trace_custom =
|
||||
ck_realloc(afl->clean_trace_custom, new_map_size);
|
||||
afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
|
||||
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
|
||||
|
||||
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
|
||||
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
|
||||
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
|
||||
afl->var_bytes = ck_realloc(afl->var_bytes, new_map_size);
|
||||
afl->top_rated =
|
||||
ck_realloc(afl->top_rated, new_map_size * sizeof(void *));
|
||||
afl->clean_trace = ck_realloc(afl->clean_trace, new_map_size);
|
||||
afl->clean_trace_custom =
|
||||
ck_realloc(afl->clean_trace_custom, new_map_size);
|
||||
afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
|
||||
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
|
||||
|
||||
afl_fsrv_kill(&afl->fsrv);
|
||||
afl_shm_deinit(&afl->shm);
|
||||
afl->fsrv.map_size = new_map_size;
|
||||
afl->fsrv.trace_bits =
|
||||
afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode);
|
||||
setenv("AFL_NO_AUTODICT", "1", 1); // loaded already
|
||||
afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
|
||||
afl->afl_env.afl_debug_child);
|
||||
|
||||
}
|
||||
afl_fsrv_kill(&afl->fsrv);
|
||||
afl_shm_deinit(&afl->shm);
|
||||
afl->fsrv.map_size = new_map_size;
|
||||
afl->fsrv.trace_bits =
|
||||
afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode);
|
||||
setenv("AFL_NO_AUTODICT", "1", 1); // loaded already
|
||||
afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
|
||||
afl->afl_env.afl_debug_child);
|
||||
|
||||
map_size = new_map_size;
|
||||
|
||||
}
|
||||
|
||||
afl->fsrv.map_size = map_size;
|
||||
|
||||
}
|
||||
|
||||
if (afl->cmplog_binary) {
|
||||
@ -1630,57 +1590,77 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary;
|
||||
afl->cmplog_fsrv.init_child_func = cmplog_exec_child;
|
||||
|
||||
afl->cmplog_fsrv.map_size = 4194304;
|
||||
if ((map_size <= DEFAULT_SHMEM_SIZE ||
|
||||
afl->cmplog_fsrv.map_size < map_size) &&
|
||||
!afl->non_instrumented_mode && !afl->fsrv.qemu_mode &&
|
||||
!afl->unicorn_mode) {
|
||||
|
||||
afl->cmplog_fsrv.map_size = MAX(map_size, (u32)DEFAULT_SHMEM_SIZE);
|
||||
char vbuf[16];
|
||||
snprintf(vbuf, sizeof(vbuf), "%u", afl->cmplog_fsrv.map_size);
|
||||
setenv("AFL_MAP_SIZE", vbuf, 1);
|
||||
|
||||
}
|
||||
|
||||
u32 new_map_size =
|
||||
afl_fsrv_get_mapsize(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon,
|
||||
afl->afl_env.afl_debug_child);
|
||||
|
||||
if (new_map_size && new_map_size != 4194304) {
|
||||
// only reinitialize when it needs to be larger
|
||||
if (map_size < new_map_size) {
|
||||
|
||||
// only reinitialize when it needs to be larger
|
||||
if (map_size < new_map_size) {
|
||||
OKF("Re-initializing maps to %u bytes due cmplog", new_map_size);
|
||||
|
||||
OKF("Re-initializing maps to %u bytes due cmplog", new_map_size);
|
||||
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
|
||||
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
|
||||
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
|
||||
afl->var_bytes = ck_realloc(afl->var_bytes, new_map_size);
|
||||
afl->top_rated =
|
||||
ck_realloc(afl->top_rated, new_map_size * sizeof(void *));
|
||||
afl->clean_trace = ck_realloc(afl->clean_trace, new_map_size);
|
||||
afl->clean_trace_custom =
|
||||
ck_realloc(afl->clean_trace_custom, new_map_size);
|
||||
afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
|
||||
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
|
||||
|
||||
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
|
||||
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
|
||||
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
|
||||
afl->var_bytes = ck_realloc(afl->var_bytes, new_map_size);
|
||||
afl->top_rated =
|
||||
ck_realloc(afl->top_rated, new_map_size * sizeof(void *));
|
||||
afl->clean_trace = ck_realloc(afl->clean_trace, new_map_size);
|
||||
afl->clean_trace_custom =
|
||||
ck_realloc(afl->clean_trace_custom, new_map_size);
|
||||
afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
|
||||
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
|
||||
afl_fsrv_kill(&afl->fsrv);
|
||||
afl_fsrv_kill(&afl->cmplog_fsrv);
|
||||
afl_shm_deinit(&afl->shm);
|
||||
|
||||
afl_fsrv_kill(&afl->fsrv);
|
||||
afl_fsrv_kill(&afl->cmplog_fsrv);
|
||||
afl_shm_deinit(&afl->shm);
|
||||
afl->cmplog_fsrv.map_size = new_map_size; // non-cmplog stays the same
|
||||
afl->cmplog_fsrv.map_size = new_map_size; // non-cmplog stays the same
|
||||
map_size = new_map_size;
|
||||
|
||||
afl->fsrv.trace_bits =
|
||||
afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode);
|
||||
setenv("AFL_NO_AUTODICT", "1", 1); // loaded already
|
||||
afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
|
||||
afl->afl_env.afl_debug_child);
|
||||
|
||||
afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon,
|
||||
afl->afl_env.afl_debug_child);
|
||||
|
||||
map_size = new_map_size;
|
||||
|
||||
}
|
||||
setenv("AFL_NO_AUTODICT", "1", 1); // loaded already
|
||||
afl->fsrv.trace_bits =
|
||||
afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode);
|
||||
afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits;
|
||||
afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
|
||||
afl->afl_env.afl_debug_child);
|
||||
afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon,
|
||||
afl->afl_env.afl_debug_child);
|
||||
|
||||
}
|
||||
|
||||
afl->cmplog_fsrv.map_size = map_size;
|
||||
|
||||
OKF("Cmplog forkserver successfully started");
|
||||
|
||||
}
|
||||
|
||||
load_auto(afl);
|
||||
|
||||
if (extras_dir_cnt) {
|
||||
|
||||
for (i = 0; i < extras_dir_cnt; i++) {
|
||||
|
||||
load_extras(afl, extras_dir[i]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
deunicode_extras(afl);
|
||||
dedup_extras(afl);
|
||||
if (afl->extras_cnt) { OKF("Loaded a total of %u extras.", afl->extras_cnt); }
|
||||
|
||||
// after we have the correct bitmap size we can read the bitmap -B option
|
||||
// and set the virgin maps
|
||||
if (afl->in_bitmap) {
|
||||
|
@ -162,8 +162,8 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
|
||||
snprintf(shm->g_shm_file_path, L_tmpnam, "/afl_%d_%ld", getpid(), random());
|
||||
|
||||
/* create the shared memory segment as if it was a file */
|
||||
shm->g_shm_fd =
|
||||
shm_open(shm->g_shm_file_path, O_CREAT | O_RDWR | O_EXCL, 0600);
|
||||
shm->g_shm_fd = shm_open(shm->g_shm_file_path, O_CREAT | O_RDWR | O_EXCL,
|
||||
DEFAULT_PERMISSION);
|
||||
if (shm->g_shm_fd == -1) { PFATAL("shm_open() failed"); }
|
||||
|
||||
/* configure the size of the shared memory segment */
|
||||
@ -202,7 +202,8 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
|
||||
|
||||
/* create the shared memory segment as if it was a file */
|
||||
shm->cmplog_g_shm_fd =
|
||||
shm_open(shm->cmplog_g_shm_file_path, O_CREAT | O_RDWR | O_EXCL, 0600);
|
||||
shm_open(shm->cmplog_g_shm_file_path, O_CREAT | O_RDWR | O_EXCL,
|
||||
DEFAULT_PERMISSION);
|
||||
if (shm->cmplog_g_shm_fd == -1) { PFATAL("shm_open() failed"); }
|
||||
|
||||
/* configure the size of the shared memory segment */
|
||||
@ -241,13 +242,14 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
|
||||
#else
|
||||
u8 *shm_str;
|
||||
|
||||
shm->shm_id = shmget(IPC_PRIVATE, map_size, IPC_CREAT | IPC_EXCL | 0600);
|
||||
shm->shm_id =
|
||||
shmget(IPC_PRIVATE, map_size, IPC_CREAT | IPC_EXCL | DEFAULT_PERMISSION);
|
||||
if (shm->shm_id < 0) { PFATAL("shmget() failed"); }
|
||||
|
||||
if (shm->cmplog_mode) {
|
||||
|
||||
shm->cmplog_shm_id = shmget(IPC_PRIVATE, sizeof(struct cmp_map),
|
||||
IPC_CREAT | IPC_EXCL | 0600);
|
||||
IPC_CREAT | IPC_EXCL | DEFAULT_PERMISSION);
|
||||
|
||||
if (shm->cmplog_shm_id < 0) {
|
||||
|
||||
|
@ -252,7 +252,7 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
|
||||
} else {
|
||||
|
||||
unlink(outfile); /* Ignore errors */
|
||||
fd = open(outfile, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
||||
fd = open(outfile, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", outfile); }
|
||||
|
||||
}
|
||||
@ -563,6 +563,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
|
||||
"detect_leaks=0:"
|
||||
"allocator_may_return_null=1:"
|
||||
"symbolize=0:"
|
||||
"detect_odr_violation=0:"
|
||||
"handle_segv=0:"
|
||||
"handle_sigbus=0:"
|
||||
"handle_abort=0:"
|
||||
@ -598,38 +599,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
|
||||
|
||||
if (fsrv->qemu_mode) {
|
||||
|
||||
u8 *qemu_preload = getenv("QEMU_SET_ENV");
|
||||
u8 *afl_preload = getenv("AFL_PRELOAD");
|
||||
u8 *buf;
|
||||
|
||||
s32 i, afl_preload_size = strlen(afl_preload);
|
||||
for (i = 0; i < afl_preload_size; ++i) {
|
||||
|
||||
if (afl_preload[i] == ',') {
|
||||
|
||||
PFATAL(
|
||||
"Comma (',') is not allowed in AFL_PRELOAD when -Q is "
|
||||
"specified!");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (qemu_preload) {
|
||||
|
||||
buf = alloc_printf("%s,LD_PRELOAD=%s,DYLD_INSERT_LIBRARIES=%s",
|
||||
qemu_preload, afl_preload, afl_preload);
|
||||
|
||||
} else {
|
||||
|
||||
buf = alloc_printf("LD_PRELOAD=%s,DYLD_INSERT_LIBRARIES=%s",
|
||||
afl_preload, afl_preload);
|
||||
|
||||
}
|
||||
|
||||
setenv("QEMU_SET_ENV", buf, 1);
|
||||
|
||||
ck_free(buf);
|
||||
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
|
||||
|
||||
} else {
|
||||
|
||||
@ -945,31 +915,6 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
if (optind == argc || !out_file) { usage(argv[0]); }
|
||||
|
||||
if (fsrv->qemu_mode && getenv("AFL_USE_QASAN")) {
|
||||
|
||||
u8 *preload = getenv("AFL_PRELOAD");
|
||||
u8 *libqasan = get_libqasan_path(argv_orig[0]);
|
||||
|
||||
if (!preload) {
|
||||
|
||||
setenv("AFL_PRELOAD", libqasan, 0);
|
||||
|
||||
} else {
|
||||
|
||||
u8 *result = ck_alloc(strlen(libqasan) + strlen(preload) + 2);
|
||||
strcpy(result, libqasan);
|
||||
strcat(result, " ");
|
||||
strcat(result, preload);
|
||||
|
||||
setenv("AFL_PRELOAD", result, 1);
|
||||
ck_free(result);
|
||||
|
||||
}
|
||||
|
||||
ck_free(libqasan);
|
||||
|
||||
}
|
||||
|
||||
if (in_dir) {
|
||||
|
||||
if (!out_file && !collect_coverage)
|
||||
@ -1174,7 +1119,8 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
unlink(stdin_file);
|
||||
atexit(at_exit_handler);
|
||||
fsrv->out_file = stdin_file;
|
||||
fsrv->out_fd = open(stdin_file, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||
fsrv->out_fd =
|
||||
open(stdin_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); }
|
||||
|
||||
if (arg_offset && use_argv[arg_offset] != stdin_file) {
|
||||
|
@ -244,7 +244,7 @@ static s32 write_to_file(u8 *path, u8 *mem, u32 len) {
|
||||
|
||||
unlink(path); /* Ignore errors */
|
||||
|
||||
ret = open(path, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||
ret = open(path, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
|
||||
if (ret < 0) { PFATAL("Unable to create '%s'", path); }
|
||||
|
||||
@ -666,7 +666,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
|
||||
unlink(out_file);
|
||||
|
||||
fsrv->out_file = out_file;
|
||||
fsrv->out_fd = open(out_file, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||
fsrv->out_fd = open(out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
|
||||
if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); }
|
||||
|
||||
@ -717,6 +717,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
|
||||
"detect_leaks=0:"
|
||||
"allocator_may_return_null=1:"
|
||||
"symbolize=0:"
|
||||
"detect_odr_violation=0:"
|
||||
"handle_segv=0:"
|
||||
"handle_sigbus=0:"
|
||||
"handle_abort=0:"
|
||||
@ -752,38 +753,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
|
||||
|
||||
if (fsrv->qemu_mode) {
|
||||
|
||||
u8 *qemu_preload = getenv("QEMU_SET_ENV");
|
||||
u8 *afl_preload = getenv("AFL_PRELOAD");
|
||||
u8 *buf;
|
||||
|
||||
s32 i, afl_preload_size = strlen(afl_preload);
|
||||
for (i = 0; i < afl_preload_size; ++i) {
|
||||
|
||||
if (afl_preload[i] == ',') {
|
||||
|
||||
PFATAL(
|
||||
"Comma (',') is not allowed in AFL_PRELOAD when -Q is "
|
||||
"specified!");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (qemu_preload) {
|
||||
|
||||
buf = alloc_printf("%s,LD_PRELOAD=%s,DYLD_INSERT_LIBRARIES=%s",
|
||||
qemu_preload, afl_preload, afl_preload);
|
||||
|
||||
} else {
|
||||
|
||||
buf = alloc_printf("LD_PRELOAD=%s,DYLD_INSERT_LIBRARIES=%s",
|
||||
afl_preload, afl_preload);
|
||||
|
||||
}
|
||||
|
||||
setenv("QEMU_SET_ENV", buf, 1);
|
||||
|
||||
ck_free(buf);
|
||||
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
|
||||
|
||||
} else {
|
||||
|
||||
@ -1078,31 +1048,6 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
check_environment_vars(envp);
|
||||
setenv("AFL_NO_AUTODICT", "1", 1);
|
||||
|
||||
if (fsrv->qemu_mode && getenv("AFL_USE_QASAN")) {
|
||||
|
||||
u8 *preload = getenv("AFL_PRELOAD");
|
||||
u8 *libqasan = get_libqasan_path(argv_orig[0]);
|
||||
|
||||
if (!preload) {
|
||||
|
||||
setenv("AFL_PRELOAD", libqasan, 0);
|
||||
|
||||
} else {
|
||||
|
||||
u8 *result = ck_alloc(strlen(libqasan) + strlen(preload) + 2);
|
||||
strcpy(result, libqasan);
|
||||
strcat(result, " ");
|
||||
strcat(result, preload);
|
||||
|
||||
setenv("AFL_PRELOAD", result, 1);
|
||||
ck_free(result);
|
||||
|
||||
}
|
||||
|
||||
ck_free(libqasan);
|
||||
|
||||
}
|
||||
|
||||
/* initialize cmplog_mode */
|
||||
shm.cmplog_mode = 0;
|
||||
|
||||
|
@ -18,6 +18,10 @@
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef TEST_SHARED_OBJECT
|
||||
#define main main_exported
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
int fd = 0;
|
||||
|
@ -37,9 +37,9 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && {
|
||||
echo "00000" > in/in
|
||||
|
||||
# Run afl-fuzz w/ the C mutator
|
||||
$ECHO "$GREY[*] running afl-fuzz for the C mutator, this will take approx 5 seconds"
|
||||
$ECHO "$GREY[*] running afl-fuzz for the C mutator, this will take approx 10 seconds"
|
||||
{
|
||||
AFL_CUSTOM_MUTATOR_LIBRARY=./libexamplemutator.so AFL_CUSTOM_MUTATOR_ONLY=1 ../afl-fuzz -V1 -m ${MEM_LIMIT} -i in -o out -- ./test-custom-mutator >>errors 2>&1
|
||||
AFL_CUSTOM_MUTATOR_LIBRARY=./libexamplemutator.so AFL_CUSTOM_MUTATOR_ONLY=1 ../afl-fuzz -V10 -m ${MEM_LIMIT} -i in -o out -- ./test-custom-mutator >>errors 2>&1
|
||||
} >>errors 2>&1
|
||||
|
||||
# Check results
|
||||
@ -57,9 +57,9 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && {
|
||||
rm -rf out errors core.*
|
||||
|
||||
# Run afl-fuzz w/ multiple C mutators
|
||||
$ECHO "$GREY[*] running afl-fuzz with multiple custom C mutators, this will take approx 5 seconds"
|
||||
$ECHO "$GREY[*] running afl-fuzz with multiple custom C mutators, this will take approx 10 seconds"
|
||||
{
|
||||
AFL_CUSTOM_MUTATOR_LIBRARY="./libexamplemutator.so;./libexamplemutator2.so" AFL_CUSTOM_MUTATOR_ONLY=1 ../afl-fuzz -V1 -m ${MEM_LIMIT} -i in -o out -- ./test-multiple-mutators >>errors 2>&1
|
||||
AFL_CUSTOM_MUTATOR_LIBRARY="./libexamplemutator.so;./libexamplemutator2.so" AFL_CUSTOM_MUTATOR_ONLY=1 ../afl-fuzz -V10 -m ${MEM_LIMIT} -i in -o out -- ./test-multiple-mutators >>errors 2>&1
|
||||
} >>errors 2>&1
|
||||
|
||||
test -n "$( ls out/default/crashes/id:000000* 2>/dev/null )" && { # TODO: update here
|
||||
@ -76,11 +76,11 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && {
|
||||
rm -rf out errors core.*
|
||||
|
||||
# Run afl-fuzz w/ the Python mutator
|
||||
$ECHO "$GREY[*] running afl-fuzz for the Python mutator, this will take approx 5 seconds"
|
||||
$ECHO "$GREY[*] running afl-fuzz for the Python mutator, this will take approx 10 seconds"
|
||||
{
|
||||
export PYTHONPATH=${CUSTOM_MUTATOR_PATH}
|
||||
export AFL_PYTHON_MODULE=example
|
||||
AFL_CUSTOM_MUTATOR_ONLY=1 ../afl-fuzz -V5 -m ${MEM_LIMIT} -i in -o out -- ./test-custom-mutator >>errors 2>&1
|
||||
AFL_CUSTOM_MUTATOR_ONLY=1 ../afl-fuzz -V10 -m ${MEM_LIMIT} -i in -o out -- ./test-custom-mutator >>errors 2>&1
|
||||
unset PYTHONPATH
|
||||
unset AFL_PYTHON_MODULE
|
||||
} >>errors 2>&1
|
||||
|
23
test/test-dlopen.c
Normal file
23
test/test-dlopen.c
Normal file
@ -0,0 +1,23 @@
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
if (!getenv("TEST_DLOPEN_TARGET")) return 1;
|
||||
void *lib = dlopen(getenv("TEST_DLOPEN_TARGET"), RTLD_LAZY);
|
||||
if (!lib) {
|
||||
|
||||
perror(dlerror());
|
||||
return 2;
|
||||
|
||||
}
|
||||
|
||||
int (*func)(int, char **) = dlsym(lib, "main_exported");
|
||||
if (!func) return 3;
|
||||
|
||||
return func(argc, argv);
|
||||
|
||||
}
|
||||
|
@ -43,6 +43,48 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
|
||||
$ECHO "$RED[!] llvm_mode failed"
|
||||
CODE=1
|
||||
}
|
||||
../afl-clang-fast -DTEST_SHARED_OBJECT=1 -z defs -fPIC -shared -o test-instr.so ../test-instr.c > /dev/null 2>&1
|
||||
test -e test-instr.so && {
|
||||
$ECHO "$GREEN[+] llvm_mode shared object with -z defs compilation succeeded"
|
||||
../afl-clang-fast -o test-dlopen.plain test-dlopen.c -ldl > /dev/null 2>&1
|
||||
test -e test-dlopen.plain && {
|
||||
$ECHO "$GREEN[+] llvm_mode test-dlopen compilation succeeded"
|
||||
echo 0 | TEST_DLOPEN_TARGET=./test-instr.so AFL_QUIET=1 ./test-dlopen.plain > /dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
$ECHO "$RED[!] llvm_mode test-dlopen exits with an error"
|
||||
CODE=1
|
||||
fi
|
||||
echo 0 | TEST_DLOPEN_TARGET=./test-instr.so AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-dlopen.plain.0 -r -- ./test-dlopen.plain > /dev/null 2>&1
|
||||
TEST_DLOPEN_TARGET=./test-instr.so AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-dlopen.plain.1 -r -- ./test-dlopen.plain < /dev/null > /dev/null 2>&1
|
||||
test -e test-dlopen.plain.0 -a -e test-dlopen.plain.1 && {
|
||||
diff test-dlopen.plain.0 test-dlopen.plain.1 > /dev/null 2>&1 && {
|
||||
$ECHO "$RED[!] llvm_mode test-dlopen instrumentation should be different on different input but is not"
|
||||
CODE=1
|
||||
} || {
|
||||
$ECHO "$GREEN[+] llvm_mode test-dlopen instrumentation present and working correctly"
|
||||
TUPLES=`echo 0|TEST_DLOPEN_TARGET=./test-instr.so AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- ./test-dlopen.plain 2>&1 | grep Captur | awk '{print$3}'`
|
||||
test "$TUPLES" -gt 3 -a "$TUPLES" -lt 12 && {
|
||||
$ECHO "$GREEN[+] llvm_mode test-dlopen run reported $TUPLES instrumented locations which is fine"
|
||||
} || {
|
||||
$ECHO "$RED[!] llvm_mode test-dlopen instrumentation produces weird numbers: $TUPLES"
|
||||
CODE=1
|
||||
}
|
||||
test "$TUPLES" -lt 3 && SKIP=1
|
||||
true
|
||||
}
|
||||
} || {
|
||||
$ECHO "$RED[!] llvm_mode test-dlopen instrumentation failed"
|
||||
CODE=1
|
||||
}
|
||||
} || {
|
||||
$ECHO "$RED[!] llvm_mode test-dlopen compilation failed"
|
||||
CODE=1
|
||||
}
|
||||
rm -f test-dlopen.plain test-dlopen.plain.0 test-dlopen.plain.1 test-instr.so
|
||||
} || {
|
||||
$ECHO "$RED[!] llvm_mode shared object with -z defs compilation failed"
|
||||
CODE=1
|
||||
}
|
||||
test -e test-compcov.harden && test_compcov_binary_functionality ./test-compcov.harden && {
|
||||
grep -Eq$GREPAOPTION 'stack_chk_fail|fstack-protector-all|fortified' test-compcov.harden > /dev/null 2>&1 && {
|
||||
$ECHO "$GREEN[+] llvm_mode hardened mode succeeded and is working"
|
||||
@ -162,9 +204,9 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
|
||||
test -e test-floatingpoint && {
|
||||
mkdir -p in
|
||||
echo ZZZZ > in/in
|
||||
$ECHO "$GREY[*] running afl-fuzz with floating point splitting, this will take max. 30 seconds"
|
||||
$ECHO "$GREY[*] running afl-fuzz with floating point splitting, this will take max. 45 seconds"
|
||||
{
|
||||
AFL_BENCH_UNTIL_CRASH=1 AFL_NO_UI=1 ../afl-fuzz -s 1 -V30 -m ${MEM_LIMIT} -i in -o out -D -- ./test-floatingpoint >>errors 2>&1
|
||||
AFL_BENCH_UNTIL_CRASH=1 AFL_NO_UI=1 ../afl-fuzz -Z -s 123 -V50 -m ${MEM_LIMIT} -i in -o out -D -- ./test-floatingpoint >>errors 2>&1
|
||||
} >>errors 2>&1
|
||||
test -n "$( ls out/default/crashes/id:* 2>/dev/null )" && {
|
||||
$ECHO "$GREEN[+] llvm_mode laf-intel floatingpoint splitting feature works correctly"
|
||||
|
@ -1,45 +0,0 @@
|
||||
# This is the Dockerfile for testing problems in Travis build
|
||||
# configuration #1.
|
||||
# This needs not to be rebuild everytime, most of the time it needs just to
|
||||
# be build once and then started when debugging issues and execute:
|
||||
# cd /AFLplusplus/
|
||||
# git pull
|
||||
# make distrib
|
||||
#
|
||||
FROM ubuntu:bionic
|
||||
LABEL "about"="travis image 1"
|
||||
RUN apt-get update && apt-get -y install \
|
||||
automake \
|
||||
bison \
|
||||
build-essential \
|
||||
clang \
|
||||
flex \
|
||||
git \
|
||||
python3.7 python3.7-dev \
|
||||
python3-setuptools \
|
||||
libtool libtool-bin \
|
||||
libglib2.0-dev \
|
||||
python-setuptools \
|
||||
wget \
|
||||
ca-certificates \
|
||||
libpixman-1-dev \
|
||||
gcc-7 gcc-7-plugin-dev libc++-7-dev \
|
||||
findutils \
|
||||
libcmocka-dev \
|
||||
joe nano vim locate \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV AFL_NO_UI=1
|
||||
ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
|
||||
ENV LLVM_CONFIG=llvm-config-6.0
|
||||
|
||||
RUN cd / && \
|
||||
git clone https://github.com/AFLplusplus/AFLplusplus && \
|
||||
cd AFLplusplus && \
|
||||
git checkout dev && \
|
||||
cd qemu_mode && wget http://download.qemu-project.org/qemu-3.1.1.tar.xz && \
|
||||
cd ../unicorn_mode && git submodule init && git submodule update || true && \
|
||||
cd /AFLplusplus && ASAN_BUILD=1 make source-only || true
|
||||
|
||||
WORKDIR /AFLplusplus
|
||||
CMD ["/bin/bash"]
|
@ -1,45 +0,0 @@
|
||||
# This is the Dockerfile for testing problems in Travis build
|
||||
# configuration #1.
|
||||
# This needs not to be rebuild everytime, most of the time it needs just to
|
||||
# be build once and then started when debugging issues and execute:
|
||||
# cd /AFLplusplus/
|
||||
# git pull
|
||||
# make distrib
|
||||
#
|
||||
FROM ubuntu:focal
|
||||
LABEL "about"="travis image 4"
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update && apt-get -y install \
|
||||
automake \
|
||||
bison \
|
||||
build-essential \
|
||||
clang \
|
||||
flex \
|
||||
git \
|
||||
python3 python3-dev \
|
||||
python3-setuptools \
|
||||
libtool libtool-bin \
|
||||
libglib2.0-dev \
|
||||
python-setuptools \
|
||||
wget \
|
||||
ca-certificates \
|
||||
libpixman-1-dev \
|
||||
gcc-9 gcc-9-plugin-dev libc++-9-dev \
|
||||
findutils \
|
||||
libcmocka-dev \
|
||||
joe nano vim locate \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV AFL_NO_UI=1
|
||||
ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
|
||||
|
||||
RUN cd / && \
|
||||
git clone https://github.com/AFLplusplus/AFLplusplus && \
|
||||
cd AFLplusplus && \
|
||||
git checkout dev && \
|
||||
cd qemu_mode && wget http://download.qemu-project.org/qemu-3.1.1.tar.xz && \
|
||||
cd ../unicorn_mode && git submodule init && git submodule update || true && \
|
||||
cd /AFLplusplus && ASAN_BUILD=1 make source-only || true
|
||||
|
||||
WORKDIR /AFLplusplus
|
||||
CMD ["/bin/bash"]
|
@ -1,49 +0,0 @@
|
||||
# This is the Dockerfile for testing problems in Travis builds
|
||||
# configuration #3.
|
||||
# This needs not to be rebuild everytime, most of the time it needs just to
|
||||
# be build once and then started when debugging issues and execute:
|
||||
# cd /AFLplusplus/
|
||||
# git pull
|
||||
# make distrib
|
||||
#
|
||||
FROM ubuntu:trusty
|
||||
LABEL "about"="travis image 3"
|
||||
RUN apt-get update && apt-get -y install \
|
||||
automake \
|
||||
bison \
|
||||
build-essential \
|
||||
clang \
|
||||
flex \
|
||||
git \
|
||||
python2.7 python2.7-dev \
|
||||
python3-setuptools \
|
||||
libtool \
|
||||
libglib2.0-dev \
|
||||
python-setuptools \
|
||||
wget \
|
||||
ca-certificates \
|
||||
libpixman-1-dev \
|
||||
gcc-4.8 gcc-4.8-plugin-dev \
|
||||
libc++-dev \
|
||||
findutils \
|
||||
libcmocka-dev \
|
||||
joe nano vim locate \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV TERM linux
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
ENV LLVM_CONFIG=llvm-config-3.4
|
||||
ENV AFL_NO_UI=1
|
||||
ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
|
||||
|
||||
RUN cd / && \
|
||||
git clone https://github.com/AFLplusplus/AFLplusplus && \
|
||||
cd AFLplusplus && \
|
||||
git checkout dev && \
|
||||
cd qemu_mode && wget http://download.qemu-project.org/qemu-3.1.1.tar.xz && \
|
||||
cd ../unicorn_mode && git submodule init && git submodule update || true && \
|
||||
cd /AFLplusplus && ASAN_BUILD=1 make source-only || true
|
||||
|
||||
WORKDIR /AFLplusplus
|
||||
CMD ["/bin/bash"]
|
||||
|
@ -1,46 +0,0 @@
|
||||
# This is the Dockerfile for testing problems in Travis builds
|
||||
# configuration #2.
|
||||
# This needs not to be rebuild everytime, most of the time it needs just to
|
||||
# be build once and then started when debugging issues and execute:
|
||||
# cd /AFLplusplus/
|
||||
# git pull
|
||||
# make distrib
|
||||
#
|
||||
FROM ubuntu:xenial
|
||||
LABEL "about"="travis image 2"
|
||||
RUN apt-get update && apt-get -y install \
|
||||
automake \
|
||||
bison \
|
||||
build-essential \
|
||||
clang-6.0 \
|
||||
flex \
|
||||
git \
|
||||
python3 python3-dev \
|
||||
python3-setuptools \
|
||||
libtool libtool-bin \
|
||||
libglib2.0-dev \
|
||||
python-setuptools \
|
||||
wget \
|
||||
ca-certificates \
|
||||
libpixman-1-dev \
|
||||
gcc-5 gcc-5-plugin-dev \
|
||||
libc++-dev \
|
||||
findutils \
|
||||
libcmocka-dev \
|
||||
joe nano vim locate \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV LLVM_CONFIG=llvm-config-6.0
|
||||
ENV AFL_NO_UI=1
|
||||
ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
|
||||
|
||||
RUN cd / && \
|
||||
git clone https://github.com/AFLplusplus/AFLplusplus && \
|
||||
cd AFLplusplus && \
|
||||
git checkout dev && \
|
||||
cd qemu_mode && wget http://download.qemu-project.org/qemu-3.1.1.tar.xz && \
|
||||
cd ../unicorn_mode && git submodule init && git submodule update || true && \
|
||||
cd /AFLplusplus && ASAN_BUILD=1 make source-only || true
|
||||
|
||||
WORKDIR /AFLplusplus
|
||||
CMD ["/bin/bash"]
|
197
unicorn_mode/helper_scripts/ida_context_loader.py
Normal file
197
unicorn_mode/helper_scripts/ida_context_loader.py
Normal file
@ -0,0 +1,197 @@
|
||||
# Copyright (c) 2021 Brandon Miller (zznop)
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
|
||||
"""IDA script for loading state that was dumped from a running process using unicorn AFL's GDB
|
||||
plugin (unicorn_dumper_gdb.py). The dumper script can be found in the AFL++ repository at:
|
||||
https://github.com/AFLplusplus/AFLplusplus/blob/stable/unicorn_mode/helper_scripts/unicorn_dumper_gdb.py
|
||||
"""
|
||||
|
||||
import json
|
||||
from pathlib import Path, PurePath
|
||||
import zlib
|
||||
import idaapi
|
||||
import ida_bytes
|
||||
import ida_kernwin
|
||||
import ida_nalt
|
||||
import ida_segment
|
||||
|
||||
|
||||
class ContextLoaderError(Exception):
|
||||
"""Base "catch all" exception for this script
|
||||
"""
|
||||
|
||||
|
||||
class ArchNotSupportedError(ContextLoaderError):
|
||||
"""Exception raised if the input file CPU architecture isn't supported fully
|
||||
"""
|
||||
|
||||
|
||||
def parse_mapping_index(filepath: str):
|
||||
"""Open and unmarshal the _index.json file
|
||||
|
||||
:param filepath: Path to the JSON file
|
||||
:return: Dict representing index file contents
|
||||
"""
|
||||
|
||||
if filepath is None:
|
||||
raise ContextLoaderError('_index.json file was not selected')
|
||||
|
||||
try:
|
||||
with open(filepath, 'rb') as _file:
|
||||
return json.load(_file)
|
||||
except Exception as ex:
|
||||
raise ContextLoaderError('Failed to parse json file {}'.format(filepath)) from ex
|
||||
|
||||
def get_input_name():
|
||||
"""Get the name of the input file
|
||||
|
||||
:retrun: Name of the input file
|
||||
"""
|
||||
|
||||
input_filepath = ida_nalt.get_input_file_path()
|
||||
return Path(input_filepath).name
|
||||
|
||||
def write_segment_bytes(start: int, filepath: str):
|
||||
""""Read data from context file and write it to the IDA segment
|
||||
|
||||
:param start: Start address
|
||||
:param filepath: Path to context file
|
||||
"""
|
||||
|
||||
with open(filepath, 'rb') as _file:
|
||||
data = _file.read()
|
||||
|
||||
decompressed_data = zlib.decompress(data)
|
||||
ida_bytes.put_bytes(start, decompressed_data)
|
||||
|
||||
def create_segment(context_dir: str, segment: dict, is_be: bool):
|
||||
"""Create segment in IDA and map in the data from the file
|
||||
|
||||
:param context_dir: Parent directory of the context files
|
||||
:param segment: Segment information from _index.json
|
||||
:param is_be: True if processor is big endian, otherwise False
|
||||
"""
|
||||
|
||||
input_name = get_input_name()
|
||||
if Path(segment['name']).name != input_name:
|
||||
ida_seg = idaapi.segment_t()
|
||||
ida_seg.start_ea = segment['start']
|
||||
ida_seg.end_ea = segment['end']
|
||||
ida_seg.bitness = 1 if is_be else 0
|
||||
if segment['permissions']['r']:
|
||||
ida_seg.perm |= ida_segment.SEGPERM_READ
|
||||
if segment['permissions']['w']:
|
||||
ida_seg.perm |= ida_segment.SEGPERM_WRITE
|
||||
if segment['permissions']['x']:
|
||||
ida_seg.perm |= ida_segment.SEGPERM_EXEC
|
||||
idaapi.add_segm_ex(ida_seg, Path(segment['name']).name, 'CODE', idaapi.ADDSEG_OR_DIE)
|
||||
else:
|
||||
idaapi.add_segm_ex(ida_seg, Path(segment['name']).name, 'DATA', idaapi.ADDSEG_OR_DIE)
|
||||
|
||||
if segment['content_file']:
|
||||
write_segment_bytes(segment['start'], PurePath(context_dir, segment['content_file']))
|
||||
|
||||
def create_segments(index: dict, context_dir: str):
|
||||
"""Iterate segments in index JSON, create the segment in IDA, and map in the data from the file
|
||||
|
||||
:param index: _index.json JSON data
|
||||
:param context_dir: Parent directory of the context files
|
||||
"""
|
||||
|
||||
info = idaapi.get_inf_structure()
|
||||
is_be = info.is_be()
|
||||
for segment in index['segments']:
|
||||
create_segment(context_dir, segment, is_be)
|
||||
|
||||
def rebase_program(index: dict):
|
||||
"""Rebase the program to the offset specified in the context _index.json
|
||||
|
||||
:param index: _index.json JSON data
|
||||
"""
|
||||
|
||||
input_name = get_input_name()
|
||||
new_base = None
|
||||
for segment in index['segments']:
|
||||
if not segment['name']:
|
||||
continue
|
||||
|
||||
segment_name = Path(segment['name']).name
|
||||
if input_name == segment_name:
|
||||
new_base = segment['start']
|
||||
break
|
||||
|
||||
if not new_base:
|
||||
raise ContextLoaderError('Input file is not in _index.json')
|
||||
|
||||
current_base = idaapi.get_imagebase()
|
||||
ida_segment.rebase_program(new_base-current_base, 8)
|
||||
|
||||
def get_pc_by_arch(index: dict) -> int:
|
||||
"""Queries the input file CPU architecture and attempts to lookup the address of the program
|
||||
counter in the _index.json by register name
|
||||
|
||||
:param index: _index.json JSON data
|
||||
:return: Program counter value or None
|
||||
"""
|
||||
|
||||
progctr = None
|
||||
info = idaapi.get_inf_structure()
|
||||
if info.procname == 'metapc':
|
||||
if info.is_64bit():
|
||||
progctr = index['regs']['rax']
|
||||
elif info.is_32bit():
|
||||
progctr = index['regs']['eax']
|
||||
return progctr
|
||||
|
||||
def write_reg_info(index: dict):
|
||||
"""Write register info as line comment at instruction pointed to by the program counter and
|
||||
change focus to that location
|
||||
|
||||
:param index: _index.json JSON data
|
||||
"""
|
||||
|
||||
cmt = ''
|
||||
for reg, val in index['regs'].items():
|
||||
cmt += f"{reg.ljust(6)} : {hex(val)}\n"
|
||||
|
||||
progctr = get_pc_by_arch(index)
|
||||
if progctr is None:
|
||||
raise ArchNotSupportedError(
|
||||
'Architecture not fully supported, skipping register status comment')
|
||||
ida_bytes.set_cmt(progctr, cmt, 0)
|
||||
ida_kernwin.jumpto(progctr)
|
||||
|
||||
def main(filepath):
|
||||
"""Main - parse _index.json input and map context files into the database
|
||||
|
||||
:param filepath: Path to the _index.json file
|
||||
"""
|
||||
|
||||
try:
|
||||
index = parse_mapping_index(filepath)
|
||||
context_dir = Path(filepath).parent
|
||||
rebase_program(index)
|
||||
create_segments(index, context_dir)
|
||||
write_reg_info(index)
|
||||
except ContextLoaderError as ex:
|
||||
print(ex)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(ida_kernwin.ask_file(1, '*.json', 'Import file name'))
|
0
unicorn_mode/samples/speedtest/get_offsets.py
Normal file → Executable file
0
unicorn_mode/samples/speedtest/get_offsets.py
Normal file → Executable file
@ -237,38 +237,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
|
||||
|
||||
if (fsrv->qemu_mode) {
|
||||
|
||||
u8 *qemu_preload = getenv("QEMU_SET_ENV");
|
||||
u8 *afl_preload = getenv("AFL_PRELOAD");
|
||||
u8 *buf;
|
||||
|
||||
s32 i, afl_preload_size = strlen(afl_preload);
|
||||
for (i = 0; i < afl_preload_size; ++i) {
|
||||
|
||||
if (afl_preload[i] == ',') {
|
||||
|
||||
PFATAL(
|
||||
"Comma (',') is not allowed in AFL_PRELOAD when -Q is "
|
||||
"specified!");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (qemu_preload) {
|
||||
|
||||
buf = alloc_printf("%s,LD_PRELOAD=%s,DYLD_INSERT_LIBRARIES=%s",
|
||||
qemu_preload, afl_preload, afl_preload);
|
||||
|
||||
} else {
|
||||
|
||||
buf = alloc_printf("LD_PRELOAD=%s,DYLD_INSERT_LIBRARIES=%s",
|
||||
afl_preload, afl_preload);
|
||||
|
||||
}
|
||||
|
||||
setenv("QEMU_SET_ENV", buf, 1);
|
||||
|
||||
afl_free(buf);
|
||||
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -187,6 +187,8 @@ static int ExecuteFilesOnyByOne(int argc, char **argv) {
|
||||
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
}
|
||||
|
||||
free(buf);
|
||||
@ -204,10 +206,20 @@ int main(int argc, char **argv) {
|
||||
"To fuzz with afl-fuzz execute this:\n"
|
||||
" afl-fuzz [afl-flags] -- %s [-N]\n"
|
||||
"afl-fuzz will run N iterations before re-spawning the process (default: "
|
||||
"1000)\n"
|
||||
"INT_MAX)\n"
|
||||
"======================================================\n",
|
||||
argv[0], argv[0]);
|
||||
|
||||
if (getenv("AFL_GDB")) {
|
||||
|
||||
char cmd[64];
|
||||
snprintf(cmd, sizeof(cmd), "cat /proc/%d/maps", getpid());
|
||||
system(cmd);
|
||||
fprintf(stderr, "DEBUG: aflpp_driver pid is %d\n", getpid());
|
||||
sleep(1);
|
||||
|
||||
}
|
||||
|
||||
output_file = stderr;
|
||||
maybe_duplicate_stderr();
|
||||
maybe_close_fd_mask();
|
||||
|
@ -60,12 +60,12 @@ if
|
||||
fi
|
||||
|
||||
if [ ! -f "$BIN" -o ! -x "$BIN" ]; then
|
||||
echo "[-] Error: binary '$2' not found or is not executable." 1>&2
|
||||
echo "[-] Error: binary '$BIN' not found or is not executable." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d "$DIR/queue" ]; then
|
||||
echo "[-] Error: directory '$1' not found or not created by afl-fuzz." 1>&2
|
||||
echo "[-] Error: directory '$DIR' not found or not created by afl-fuzz." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
@ -168,7 +168,7 @@ static void *__dislocator_alloc(size_t len) {
|
||||
|
||||
u8 * ret, *base;
|
||||
size_t tlen;
|
||||
int flags, fd, sp;
|
||||
int flags, protflags, fd, sp;
|
||||
|
||||
if (total_mem + len > max_mem || total_mem + len < total_mem) {
|
||||
|
||||
@ -191,8 +191,14 @@ static void *__dislocator_alloc(size_t len) {
|
||||
|
||||
base = NULL;
|
||||
tlen = (1 + PG_COUNT(rlen + 8)) * PAGE_SIZE;
|
||||
protflags = PROT_READ | PROT_WRITE;
|
||||
flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
fd = -1;
|
||||
#if defined(PROT_MAX)
|
||||
// apply when sysctl vm.imply_prot_max is set to 1
|
||||
// no-op otherwise
|
||||
protflags |= PROT_MAX(PROT_READ | PROT_WRITE);
|
||||
#endif
|
||||
#if defined(USEHUGEPAGE)
|
||||
sp = (rlen >= SUPER_PAGE_SIZE && !(rlen % SUPER_PAGE_SIZE));
|
||||
|
||||
@ -215,7 +221,7 @@ static void *__dislocator_alloc(size_t len) {
|
||||
(void)sp;
|
||||
#endif
|
||||
|
||||
ret = (u8 *)mmap(base, tlen, PROT_READ | PROT_WRITE, flags, fd, 0);
|
||||
ret = (u8 *)mmap(base, tlen, protflags, flags, fd, 0);
|
||||
#if defined(USEHUGEPAGE)
|
||||
/* We try one more time with regular call */
|
||||
if (ret == MAP_FAILED) {
|
||||
@ -229,7 +235,7 @@ static void *__dislocator_alloc(size_t len) {
|
||||
#elif defined(__sun)
|
||||
flags &= -MAP_ALIGN;
|
||||
#endif
|
||||
ret = (u8 *)mmap(NULL, tlen, PROT_READ | PROT_WRITE, flags, fd, 0);
|
||||
ret = (u8 *)mmap(NULL, tlen, protflags, flags, fd, 0);
|
||||
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user