mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-24 22:53:24 +00:00
Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
fe218d65ea | |||
c504fb2189 | |||
a6bcd99aec |
18
GNUmakefile
18
GNUmakefile
@ -31,7 +31,7 @@ PROGNAME = afl
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
|
||||
PROGS = afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
|
||||
SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-cmin.py afl-whatsup afl-addseeds afl-system-config afl-persistent-config afl-cc
|
||||
SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-addseeds afl-system-config afl-persistent-config afl-cc
|
||||
HEADERS = include/afl-fuzz.h include/afl-mutations.h include/afl-persistent-replay.h include/afl-prealloc.h include/afl-record-compat.h include/alloc-inl.h include/android-ashmem.h include/cmplog.h include/common.h include/config.h include/coverage-32.h include/coverage-64.h include/debug.h include/envs.h include/forkserver.h include/hash.h include/list.h include/sharedmem.h include/snapshot-inl.h include/t1ha.h include/t1ha0_ia32aes_b.h include/t1ha_bits.h include/t1ha_selfcheck.h include/types.h include/xxhash.h
|
||||
MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8)
|
||||
ASAN_OPTIONS=detect_leaks=0
|
||||
@ -76,16 +76,14 @@ ifdef IS_IOS
|
||||
endif
|
||||
|
||||
ifeq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
ifndef ASAN_BUILD
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto=full
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto=thin
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@ -315,8 +313,8 @@ ifeq "$(shell command -v svn >/dev/null && svn proplist . 2>/dev/null && echo 1
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo 'int main() { return 0;}' | $(CC) $(CFLAGS) -fsanitize=address -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -DASAN_BUILD -fno-lto
|
||||
ASAN_LDFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -fno-lto
|
||||
ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -DASAN_BUILD
|
||||
ASAN_LDFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
|
@ -148,7 +148,7 @@ afl-common.o: ./src/afl-common.c
|
||||
$(PASSES): instrumentation/afl-gcc-common.h
|
||||
|
||||
./afl-gcc-pass.so: instrumentation/afl-gcc-pass.so.cc | test_deps
|
||||
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@ $(LDFLAGS)
|
||||
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
|
||||
ln -sf afl-cc afl-gcc-fast
|
||||
ln -sf afl-cc afl-g++-fast
|
||||
ln -sf afl-cc.8 afl-gcc-fast.8
|
||||
|
@ -32,8 +32,8 @@ VERSION = $(shell grep '^ *$(HASH)define VERSION ' ./config.h | cut -d '"' -
|
||||
|
||||
SYS = $(shell uname -s)
|
||||
|
||||
override LLVM_TOO_NEW_DEFAULT := 21
|
||||
override LLVM_TOO_OLD_DEFAULT := 14
|
||||
override LLVM_TOO_NEW_DEFAULT := 19
|
||||
override LLVM_TOO_OLD_DEFAULT := 13
|
||||
|
||||
ifeq "$(SYS)" "OpenBSD"
|
||||
LLVM_CONFIG ?= $(BIN_PATH)/llvm-config
|
||||
@ -69,7 +69,7 @@ endif
|
||||
|
||||
LLVM_STDCXX := gnu++11
|
||||
LLVM_LTO := 0
|
||||
LLVM_UNSUPPORTED := $(shell echo "$(LLVMVER)" | grep -E -q '^[0-2]\.|^3\.[0-7]\.|^2[2-9]\.' && echo 1 || echo 0)
|
||||
LLVM_UNSUPPORTED := $(shell echo "$(LLVMVER)" | grep -E -q '^[0-2]\.|^3\.[0-7]\.|^2[1-9]\.' && echo 1 || echo 0)
|
||||
# Uncomment to see the values assigned above
|
||||
# $(foreach var,_CLANG_VERSIONS_TO_TEST LLVM_CONFIG LLVMVER LLVM_MAJOR LLVM_MINOR LLVM_TOO_NEW LLVM_TOO_OLD LLVM_TOO_NEW_DEFAULT LLVM_TOO_OLD_DEFAULT LLVM_NEW_API LLVM_NEWER_API LLVM_13_OK LLVM_HAVE_LTO LLVM_BINDIR LLVM_LIBDIR LLVM_STDCXX LLVM_APPLE_XCODE LLVM_LTO LLVM_UNSUPPORTED,$(warning $(var) = $($(var))))
|
||||
|
||||
@ -470,7 +470,7 @@ endif
|
||||
|
||||
./afl-ld-lto: src/afl-ld-lto.c
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ $(LDFLAGS)
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
|
19
README.G2.md
Normal file
19
README.G2.md
Normal file
@ -0,0 +1,19 @@
|
||||
# Description
|
||||
Modern software often accepts inputs with highly complex grammars. To conduct greybox fuzzing and uncover security bugs in such software, it is essential to generate inputs that conform to the software input grammar. However, this is a well-known challenging task because it requires a deep understanding of the grammar, which is often not available and hard to infer. Recent advances in large language models (LLMs) have shown that they can be used to synthesize high-quality natural language text and code that conforms to the grammar of a given input format. Nevertheless, LLMs are often incapable or too costly to generate non-textual outputs, such as images, videos, and PDF files. This limitation hinders the application of LLMs in grammar-aware fuzzing.
|
||||
|
||||
This paper presents a novel approach to enabling grammar-aware fuzzing over non-textual inputs. We employ LLMs (e.g., GPT-3.5) to synthesize and further mutate input generators, often in the format of Python scripts, that generate data that conform to the grammar of a given input format. Then, non-textual data yielded by the input generators are further mutated by traditional fuzzers (e.g., AFL++) to explore the software input space more effectively. Holistically, our approach, namely G2FUZZ, features a hybrid strategy that combines a “holistic search” driven by LLMs and a “local search” driven by industrial quality fuzzers. Two key advantages of G2FUZZ are: (1) LLMs are good at synthesizing and mutating input generators and enabling jumping out of local optima, thus achieving a synergistic effect when combined with mutation-based fuzzers; (2) LLMs are less frequently invoked unless really needed, thus significantly reducing the cost of LLM usage.
|
||||
|
||||
|
||||
|
||||
# How to use it
|
||||
## The setting of LLM
|
||||
In default, we use the GPT-3.5 to get the generator. To use it, you’ll need to define your OpenAI API key in both `program_gen.py` and `generator_mutation_gpt_3_5.py`. If you wish to use other large language models (LLMs), you can modify the code in these two files accordingly.
|
||||
|
||||
To run the fuzzer, use the following command:
|
||||
```
|
||||
./afl-fuzz -i input -o output -c PROGRAM_CMP -m 1024 -J PROGRAM_NAME -k G2FUZZ_LOC -- PROGRAM_AFL @@
|
||||
```
|
||||
`-J`: Specifies the target program name.
|
||||
`-k`: Specifies the path to G2FUZZ.
|
||||
|
||||
G2FUZZ will generate diverse input structures. These inputs help the fuzzer explore untested code regions more effectively.
|
10
README.md
10
README.md
@ -2,9 +2,9 @@
|
||||
|
||||
<img align="right" src="https://raw.githubusercontent.com/AFLplusplus/Website/main/static/aflpp_bg.svg" alt="AFL++ logo" width="250" height="250">
|
||||
|
||||
Release version: [4.32c](https://github.com/AFLplusplus/AFLplusplus/releases)
|
||||
Release version: [4.31c](https://github.com/AFLplusplus/AFLplusplus/releases)
|
||||
|
||||
GitHub version: 4.33a
|
||||
GitHub version: 4.32a
|
||||
|
||||
Repository:
|
||||
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
||||
@ -16,6 +16,7 @@ AFL++ is maintained by:
|
||||
* Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
* Heiko "hexcoder-" Eissfeldt <heiko.eissfeldt@hexco.de>
|
||||
* frida_mode is maintained by @Worksbutnottested
|
||||
* Documentation: Jana Aydinbas <jana.aydinbas@gmail.com>
|
||||
|
||||
Originally developed by Michal "lcamtuf" Zalewski.
|
||||
|
||||
@ -229,8 +230,7 @@ Thank you! (For people sending pull requests - please add yourself to this list
|
||||
Ruben ten Hove Joey Jiao
|
||||
fuzzah @intrigus-lgtm
|
||||
Yaakov Saxon Sergej Schumilo
|
||||
Ziqiao Kong Ryan Berger
|
||||
Sangjun Park Scott Guest
|
||||
Ziqiao Kong
|
||||
```
|
||||
|
||||
</details>
|
||||
@ -259,5 +259,3 @@ presented at WOOT'20:
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
[](https://deepwiki.com/AFLplusplus/AFLplusplus)
|
||||
|
11
afl-cmin
11
afl-cmin
@ -1,19 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
THISPATH=`dirname ${0}`
|
||||
|
||||
# call afl-cmin.py if it can be executed successfully.
|
||||
if $THISPATH/afl-cmin.py --help > /dev/null 2>&1; then
|
||||
exec $THISPATH/afl-cmin.py "$@"
|
||||
fi
|
||||
|
||||
SYS=$(uname -s)
|
||||
test "$SYS" = "Darwin" && {
|
||||
echo Error: afl-cmin does not work on Apple currently. please use afl-cmin.bash instead.
|
||||
exit 1
|
||||
}
|
||||
|
||||
export AFL_QUIET=1
|
||||
export ASAN_OPTIONS=detect_leaks=0
|
||||
THISPATH=`dirname ${0}`
|
||||
export PATH="${THISPATH}:$PATH"
|
||||
awk -f - -- ${@+"$@"} <<'EOF'
|
||||
#!/usr/bin/awk -f
|
||||
@ -338,7 +331,7 @@ BEGIN {
|
||||
}
|
||||
|
||||
if (0 == system ( "grep -aq AFL_DUMP_MAP_SIZE " target_bin )) {
|
||||
print "[!] Trying to obtain the map size of the target ..."
|
||||
echo "[!] Trying to obtain the map size of the target ..."
|
||||
get_map_size = "AFL_DUMP_MAP_SIZE=1 " target_bin
|
||||
get_map_size | getline mapsize
|
||||
close(get_map_size)
|
||||
|
760
afl-cmin.py
760
afl-cmin.py
@ -1,760 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright 2016-2025 Google Inc.
|
||||
# Copyright 2025 AFLplusplus Project. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
import argparse
|
||||
import array
|
||||
import base64
|
||||
import collections
|
||||
import glob
|
||||
import hashlib
|
||||
import itertools
|
||||
import logging
|
||||
import multiprocessing
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
# https://more-itertools.readthedocs.io/en/stable/_modules/more_itertools/recipes.html#batched
|
||||
from sys import hexversion
|
||||
|
||||
def _batched(iterable, n, *, strict=False):
|
||||
"""Batch data into tuples of length *n*. If the number of items in
|
||||
*iterable* is not divisible by *n*:
|
||||
* The last batch will be shorter if *strict* is ``False``.
|
||||
* :exc:`ValueError` will be raised if *strict* is ``True``.
|
||||
|
||||
>>> list(batched('ABCDEFG', 3))
|
||||
[('A', 'B', 'C'), ('D', 'E', 'F'), ('G',)]
|
||||
|
||||
On Python 3.13 and above, this is an alias for :func:`itertools.batched`.
|
||||
"""
|
||||
if n < 1:
|
||||
raise ValueError('n must be at least one')
|
||||
iterator = iter(iterable)
|
||||
while batch := tuple(itertools.islice(iterator, n)):
|
||||
if strict and len(batch) != n:
|
||||
raise ValueError('batched(): incomplete batch')
|
||||
yield batch
|
||||
|
||||
|
||||
if hexversion >= 0x30D00A2: # pragma: no cover
|
||||
from itertools import batched as itertools_batched
|
||||
def batched(iterable, n, *, strict=False):
|
||||
return itertools_batched(iterable, n, strict=strict)
|
||||
else:
|
||||
batched = _batched
|
||||
|
||||
batched.__doc__ = _batched.__doc__
|
||||
|
||||
try:
|
||||
from tqdm import tqdm
|
||||
except ImportError:
|
||||
print('Hint: install python module "tqdm" to show progress bar')
|
||||
|
||||
class tqdm:
|
||||
|
||||
def __init__(self, data=None, *args, **argd):
|
||||
self.data = data
|
||||
|
||||
def __iter__(self):
|
||||
yield from self.data
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
pass
|
||||
|
||||
def update(self, *args):
|
||||
pass
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
cpu_count = multiprocessing.cpu_count()
|
||||
group = parser.add_argument_group("Required parameters")
|
||||
group.add_argument(
|
||||
"-i",
|
||||
dest="input",
|
||||
action="append",
|
||||
metavar="dir",
|
||||
required=True,
|
||||
help="input directory with the starting corpus",
|
||||
)
|
||||
group.add_argument(
|
||||
"-o",
|
||||
dest="output",
|
||||
metavar="dir",
|
||||
required=True,
|
||||
help="output directory for minimized files",
|
||||
)
|
||||
|
||||
group = parser.add_argument_group("Execution control settings")
|
||||
group.add_argument(
|
||||
"-f",
|
||||
dest="stdin_file",
|
||||
metavar="file",
|
||||
help="location read by the fuzzed program (stdin)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-m",
|
||||
dest="memory_limit",
|
||||
default="none",
|
||||
metavar="megs",
|
||||
type=lambda x: x if x == "none" else int(x),
|
||||
help="memory limit for child process (default: %(default)s)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-t",
|
||||
dest="time_limit",
|
||||
default=5000,
|
||||
metavar="msec",
|
||||
type=lambda x: x if x == "none" else int(x),
|
||||
help="timeout for each run (default: %(default)s)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-O",
|
||||
dest="frida_mode",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="use binary-only instrumentation (FRIDA mode)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-Q",
|
||||
dest="qemu_mode",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="use binary-only instrumentation (QEMU mode)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-U",
|
||||
dest="unicorn_mode",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="use unicorn-based instrumentation (Unicorn mode)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-X", dest="nyx_mode", action="store_true", default=False, help="use Nyx mode"
|
||||
)
|
||||
|
||||
group = parser.add_argument_group("Minimization settings")
|
||||
group.add_argument(
|
||||
"--crash-dir",
|
||||
dest="crash_dir",
|
||||
metavar="dir",
|
||||
default=None,
|
||||
help="move crashes to a separate dir, always deduplicated",
|
||||
)
|
||||
group.add_argument(
|
||||
"-A",
|
||||
dest="allow_any",
|
||||
action="store_true",
|
||||
help="allow crashes and timeouts (not recommended)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-C",
|
||||
dest="crash_only",
|
||||
action="store_true",
|
||||
help="keep crashing inputs, reject everything else",
|
||||
)
|
||||
group.add_argument(
|
||||
"-e",
|
||||
dest="edge_mode",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="solve for edge coverage only, ignore hit counts",
|
||||
)
|
||||
|
||||
group = parser.add_argument_group("Misc")
|
||||
group.add_argument(
|
||||
"-T",
|
||||
dest="workers",
|
||||
type=lambda x: cpu_count if x == "all" else int(x),
|
||||
default=1,
|
||||
help="number of concurrent worker (default: %(default)d)",
|
||||
)
|
||||
group.add_argument(
|
||||
"--as_queue",
|
||||
action="store_true",
|
||||
help='output file name like "id:000000,hash:value"',
|
||||
)
|
||||
group.add_argument(
|
||||
"--no-dedup", action="store_true", help="skip deduplication step for corpus files"
|
||||
)
|
||||
group.add_argument("--debug", action="store_true")
|
||||
|
||||
parser.add_argument("exe", metavar="/path/to/target_app")
|
||||
parser.add_argument("args", nargs="*")
|
||||
|
||||
args = parser.parse_args()
|
||||
logger = None
|
||||
afl_showmap_bin = None
|
||||
tuple_index_type_code = "I"
|
||||
file_index_type_code = None
|
||||
|
||||
|
||||
def init():
|
||||
global logger
|
||||
log_level = logging.DEBUG if args.debug else logging.INFO
|
||||
logging.basicConfig(
|
||||
level=log_level, format="%(asctime)s - %(levelname)s - %(message)s"
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
if args.stdin_file and args.workers > 1:
|
||||
logger.error("-f is only supported with one worker (-T 1)")
|
||||
sys.exit(1)
|
||||
|
||||
if args.memory_limit != "none" and args.memory_limit < 5:
|
||||
logger.error("dangerously low memory limit")
|
||||
sys.exit(1)
|
||||
|
||||
if args.time_limit != "none" and args.time_limit < 10:
|
||||
logger.error("dangerously low timeout")
|
||||
sys.exit(1)
|
||||
|
||||
if not os.path.isfile(args.exe):
|
||||
logger.error('binary "%s" not found or not regular file', args.exe)
|
||||
sys.exit(1)
|
||||
|
||||
if not os.environ.get("AFL_SKIP_BIN_CHECK") and not any(
|
||||
[args.qemu_mode, args.frida_mode, args.unicorn_mode, args.nyx_mode]
|
||||
):
|
||||
if b"__AFL_SHM_ID" not in open(args.exe, "rb").read():
|
||||
logger.error("binary '%s' doesn't appear to be instrumented", args.exe)
|
||||
sys.exit(1)
|
||||
|
||||
for dn in args.input:
|
||||
if not os.path.isdir(dn) and not glob.glob(dn):
|
||||
logger.error('directory "%s" not found', dn)
|
||||
sys.exit(1)
|
||||
|
||||
global afl_showmap_bin
|
||||
searches = [
|
||||
None,
|
||||
os.path.dirname(__file__),
|
||||
os.getcwd(),
|
||||
]
|
||||
if os.environ.get("AFL_PATH"):
|
||||
searches.append(os.environ["AFL_PATH"])
|
||||
|
||||
for search in searches:
|
||||
afl_showmap_bin = shutil.which("afl-showmap", path=search)
|
||||
if afl_showmap_bin:
|
||||
break
|
||||
if not afl_showmap_bin:
|
||||
logger.fatal("cannot find afl-showmap, please set AFL_PATH")
|
||||
sys.exit(1)
|
||||
|
||||
trace_dir = os.path.join(args.output, ".traces")
|
||||
shutil.rmtree(trace_dir, ignore_errors=True)
|
||||
try:
|
||||
os.rmdir(args.output)
|
||||
except OSError:
|
||||
pass
|
||||
if os.path.exists(args.output):
|
||||
logger.error(
|
||||
'directory "%s" exists and is not empty - delete it first', args.output
|
||||
)
|
||||
sys.exit(1)
|
||||
if args.crash_dir and not os.path.exists(args.crash_dir):
|
||||
os.makedirs(args.crash_dir)
|
||||
os.makedirs(trace_dir)
|
||||
|
||||
logger.info("use %d workers (-T)", args.workers)
|
||||
|
||||
|
||||
def detect_type_code(size):
|
||||
for type_code in ["B", "H", "I", "L", "Q"]:
|
||||
if 256 ** array.array(type_code).itemsize > size:
|
||||
return type_code
|
||||
|
||||
|
||||
def afl_showmap(input_path=None, batch=None, afl_map_size=None, first=False):
|
||||
assert input_path or batch
|
||||
# yapf: disable
|
||||
cmd = [
|
||||
afl_showmap_bin,
|
||||
'-m', str(args.memory_limit),
|
||||
'-t', str(args.time_limit),
|
||||
'-Z', # cmin mode
|
||||
]
|
||||
# yapf: enable
|
||||
found_atat = False
|
||||
for arg in args.args:
|
||||
if "@@" in arg:
|
||||
found_atat = True
|
||||
|
||||
if args.stdin_file:
|
||||
assert args.workers == 1
|
||||
input_from_file = True
|
||||
stdin_file = args.stdin_file
|
||||
cmd += ["-H", stdin_file]
|
||||
elif found_atat:
|
||||
input_from_file = True
|
||||
stdin_file = os.path.join(args.output, f".input.{os.getpid()}")
|
||||
cmd += ["-H", stdin_file]
|
||||
else:
|
||||
input_from_file = False
|
||||
|
||||
if batch:
|
||||
input_from_file = True
|
||||
filelist = os.path.join(args.output, f".filelist.{os.getpid()}")
|
||||
with open(filelist, "w") as f:
|
||||
for _, path in batch:
|
||||
f.write(path + "\n")
|
||||
cmd += ["-I", filelist]
|
||||
output_path = os.path.join(args.output, f".showmap.{os.getpid()}")
|
||||
cmd += ["-o", output_path]
|
||||
else:
|
||||
if input_from_file:
|
||||
shutil.copy(input_path, stdin_file)
|
||||
cmd += ["-o", "-"]
|
||||
|
||||
if args.frida_mode:
|
||||
cmd += ["-O"]
|
||||
if args.qemu_mode:
|
||||
cmd += ["-Q"]
|
||||
if args.unicorn_mode:
|
||||
cmd += ["-U"]
|
||||
if args.nyx_mode:
|
||||
cmd += ["-X"]
|
||||
if args.edge_mode:
|
||||
cmd += ["-e"]
|
||||
cmd += ["--", args.exe] + args.args
|
||||
|
||||
env = os.environ.copy()
|
||||
env["AFL_QUIET"] = "1"
|
||||
env["ASAN_OPTIONS"] = "detect_leaks=0"
|
||||
if first:
|
||||
logger.debug("run command line: %s", subprocess.list2cmdline(cmd))
|
||||
env["AFL_CMIN_ALLOW_ANY"] = "1"
|
||||
if afl_map_size:
|
||||
env["AFL_MAP_SIZE"] = str(afl_map_size)
|
||||
if args.crash_only:
|
||||
env["AFL_CMIN_CRASHES_ONLY"] = "1"
|
||||
if args.allow_any:
|
||||
env["AFL_CMIN_ALLOW_ANY"] = "1"
|
||||
|
||||
if input_from_file:
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=env, bufsize=1048576)
|
||||
else:
|
||||
p = subprocess.Popen(
|
||||
cmd,
|
||||
stdin=open(input_path, "rb"),
|
||||
stdout=subprocess.PIPE,
|
||||
env=env,
|
||||
bufsize=1048576,
|
||||
)
|
||||
out = p.stdout.read()
|
||||
p.wait()
|
||||
|
||||
if batch:
|
||||
result = []
|
||||
for idx, input_path in batch:
|
||||
basename = os.path.basename(input_path)
|
||||
values = []
|
||||
try:
|
||||
trace_file = os.path.join(output_path, basename)
|
||||
with open(trace_file, "r") as f:
|
||||
values = list(map(int, f))
|
||||
crashed = len(values) == 0
|
||||
os.unlink(trace_file)
|
||||
except FileNotFoundError:
|
||||
a = None
|
||||
crashed = True
|
||||
values = [(t // 1000) * 9 + t % 1000 for t in values]
|
||||
a = array.array(tuple_index_type_code, values)
|
||||
result.append((idx, a, crashed))
|
||||
os.unlink(filelist)
|
||||
os.rmdir(output_path)
|
||||
return result
|
||||
else:
|
||||
values = []
|
||||
for line in out.split():
|
||||
if not line.isdigit():
|
||||
continue
|
||||
values.append(int(line))
|
||||
values = [(t // 1000) * 9 + t % 1000 for t in values]
|
||||
a = array.array(tuple_index_type_code, values)
|
||||
crashed = p.returncode in [2, 3]
|
||||
if input_from_file and stdin_file != args.stdin_file:
|
||||
os.unlink(stdin_file)
|
||||
return a, crashed
|
||||
|
||||
|
||||
class JobDispatcher(multiprocessing.Process):
|
||||
|
||||
def __init__(self, job_queue, jobs):
|
||||
super().__init__()
|
||||
self.job_queue = job_queue
|
||||
self.jobs = jobs
|
||||
|
||||
def run(self):
|
||||
for job in self.jobs:
|
||||
self.job_queue.put(job)
|
||||
self.job_queue.close()
|
||||
|
||||
|
||||
class Worker(multiprocessing.Process):
|
||||
|
||||
def __init__(self, idx, afl_map_size, q_in, p_out, r_out):
|
||||
super().__init__()
|
||||
self.idx = idx
|
||||
self.afl_map_size = afl_map_size
|
||||
self.q_in = q_in
|
||||
self.p_out = p_out
|
||||
self.r_out = r_out
|
||||
|
||||
def run(self):
|
||||
map_size = self.afl_map_size or 65536
|
||||
max_tuple = map_size * 9
|
||||
max_file_index = 256 ** array.array(file_index_type_code).itemsize - 1
|
||||
m = array.array(file_index_type_code, [max_file_index] * max_tuple)
|
||||
counter = collections.Counter()
|
||||
crashes = []
|
||||
|
||||
pack_name = os.path.join(args.output, ".traces", f"{self.idx}.pack")
|
||||
pack_pos = 0
|
||||
with open(pack_name, "wb") as trace_pack:
|
||||
while True:
|
||||
batch = self.q_in.get()
|
||||
if batch is None:
|
||||
break
|
||||
|
||||
for idx, r, crash in afl_showmap(
|
||||
batch=batch, afl_map_size=self.afl_map_size
|
||||
):
|
||||
counter.update(r)
|
||||
|
||||
used = False
|
||||
|
||||
if crash:
|
||||
crashes.append(idx)
|
||||
|
||||
# If we aren't saving crashes to a separate dir, handle them
|
||||
# the same as other inputs. However, unless AFL_CMIN_ALLOW_ANY=1,
|
||||
# afl_showmap will not return any coverage for crashes so they will
|
||||
# never be retained.
|
||||
if not crash or not args.crash_dir:
|
||||
for t in r:
|
||||
if idx < m[t]:
|
||||
m[t] = idx
|
||||
used = True
|
||||
|
||||
if used:
|
||||
tuple_count = len(r)
|
||||
r.tofile(trace_pack)
|
||||
self.p_out.put((idx, self.idx, pack_pos, tuple_count))
|
||||
pack_pos += tuple_count * r.itemsize
|
||||
else:
|
||||
self.p_out.put(None)
|
||||
|
||||
self.r_out.put((self.idx, m, counter, crashes))
|
||||
|
||||
|
||||
class CombineTraceWorker(multiprocessing.Process):
|
||||
|
||||
def __init__(self, pack_name, jobs, r_out):
|
||||
super().__init__()
|
||||
self.pack_name = pack_name
|
||||
self.jobs = jobs
|
||||
self.r_out = r_out
|
||||
|
||||
def run(self):
|
||||
already_have = set()
|
||||
with open(self.pack_name, "rb") as f:
|
||||
for pos, tuple_count in self.jobs:
|
||||
f.seek(pos)
|
||||
result = array.array(tuple_index_type_code)
|
||||
result.fromfile(f, tuple_count)
|
||||
already_have.update(result)
|
||||
self.r_out.put(already_have)
|
||||
|
||||
|
||||
def hash_file(path):
|
||||
m = hashlib.sha1()
|
||||
with open(path, "rb") as f:
|
||||
m.update(f.read())
|
||||
return m.digest()
|
||||
|
||||
|
||||
def dedup(files):
|
||||
with multiprocessing.Pool(args.workers) as pool:
|
||||
seen_hash = set()
|
||||
result = []
|
||||
hash_list = []
|
||||
# use large chunksize to reduce multiprocessing overhead
|
||||
chunksize = max(1, min(256, len(files) // args.workers))
|
||||
for i, h in enumerate(
|
||||
tqdm(
|
||||
pool.imap(hash_file, files, chunksize),
|
||||
desc="dedup",
|
||||
total=len(files),
|
||||
ncols=0,
|
||||
leave=(len(files) > 100000),
|
||||
)
|
||||
):
|
||||
if h in seen_hash:
|
||||
continue
|
||||
seen_hash.add(h)
|
||||
result.append(files[i])
|
||||
hash_list.append(h)
|
||||
return result, hash_list
|
||||
|
||||
|
||||
def is_afl_dir(dirnames, filenames):
|
||||
return (
|
||||
"queue" in dirnames
|
||||
and "hangs" in dirnames
|
||||
and "crashes" in dirnames
|
||||
and "fuzzer_setup" in filenames
|
||||
)
|
||||
|
||||
|
||||
def collect_files(input_paths):
|
||||
paths = []
|
||||
for s in input_paths:
|
||||
paths += glob.glob(s)
|
||||
|
||||
files = []
|
||||
with tqdm(desc="search", unit=" files", ncols=0) as pbar:
|
||||
for path in paths:
|
||||
for root, dirnames, filenames in os.walk(path, followlinks=True):
|
||||
for dirname in dirnames:
|
||||
if dirname.startswith("."):
|
||||
dirnames.remove(dirname)
|
||||
|
||||
if not args.crash_only and is_afl_dir(dirnames, filenames):
|
||||
continue
|
||||
|
||||
for filename in filenames:
|
||||
if filename.startswith("."):
|
||||
continue
|
||||
pbar.update(1)
|
||||
files.append(os.path.join(root, filename))
|
||||
return files
|
||||
|
||||
|
||||
def main():
|
||||
init()
|
||||
|
||||
files = collect_files(args.input)
|
||||
if len(files) == 0:
|
||||
logger.error("no inputs in the target directory - nothing to be done")
|
||||
sys.exit(1)
|
||||
logger.info("Found %d input files in %d directories", len(files), len(args.input))
|
||||
|
||||
if not args.no_dedup:
|
||||
files, hash_list = dedup(files)
|
||||
logger.info("Remain %d files after dedup", len(files))
|
||||
else:
|
||||
logger.info("Skipping file deduplication.")
|
||||
|
||||
global file_index_type_code
|
||||
file_index_type_code = detect_type_code(len(files))
|
||||
|
||||
logger.info("Sorting files.")
|
||||
with multiprocessing.Pool(args.workers) as pool:
|
||||
chunksize = max(1, min(512, len(files) // args.workers))
|
||||
size_list = list(pool.map(os.path.getsize, files, chunksize))
|
||||
idxes = sorted(range(len(files)), key=lambda x: size_list[x])
|
||||
files = [files[idx] for idx in idxes]
|
||||
hash_list = [hash_list[idx] for idx in idxes]
|
||||
|
||||
afl_map_size = None
|
||||
if b"AFL_DUMP_MAP_SIZE" in open(args.exe, "rb").read():
|
||||
output = subprocess.run(
|
||||
[args.exe], capture_output=True, env={"AFL_DUMP_MAP_SIZE": "1", "ASAN_OPTIONS": "detect_leaks=0"}
|
||||
).stdout
|
||||
afl_map_size = int(output)
|
||||
logger.info("Setting AFL_MAP_SIZE=%d", afl_map_size)
|
||||
|
||||
global tuple_index_type_code
|
||||
tuple_index_type_code = detect_type_code(afl_map_size * 9)
|
||||
|
||||
logger.info("Testing the target binary")
|
||||
tuples, _ = afl_showmap(files[0], afl_map_size=afl_map_size, first=True)
|
||||
if tuples:
|
||||
logger.info("ok, %d tuples recorded", len(tuples))
|
||||
else:
|
||||
logger.error("no instrumentation output detected")
|
||||
sys.exit(1)
|
||||
|
||||
job_queue = multiprocessing.Queue()
|
||||
progress_queue = multiprocessing.Queue()
|
||||
result_queue = multiprocessing.Queue()
|
||||
|
||||
workers = []
|
||||
for i in range(args.workers):
|
||||
p = Worker(i, afl_map_size, job_queue, progress_queue, result_queue)
|
||||
p.start()
|
||||
workers.append(p)
|
||||
|
||||
chunk = max(1, min(128, len(files) // args.workers))
|
||||
jobs = list(batched(enumerate(files), chunk))
|
||||
jobs += [None] * args.workers # sentinel
|
||||
|
||||
dispatcher = JobDispatcher(job_queue, jobs)
|
||||
dispatcher.start()
|
||||
|
||||
logger.info("Processing traces")
|
||||
effective = 0
|
||||
trace_info = {}
|
||||
for _ in tqdm(files, ncols=0, smoothing=0.01):
|
||||
r = progress_queue.get()
|
||||
if r is not None:
|
||||
idx, worker_idx, pos, tuple_count = r
|
||||
trace_info[idx] = worker_idx, pos, tuple_count
|
||||
effective += 1
|
||||
dispatcher.join()
|
||||
|
||||
logger.info("Obtaining trace results")
|
||||
ms = []
|
||||
crashes = []
|
||||
counter = collections.Counter()
|
||||
for _ in tqdm(range(args.workers), ncols=0):
|
||||
idx, m, c, crs = result_queue.get()
|
||||
ms.append(m)
|
||||
counter.update(c)
|
||||
crashes.extend(crs)
|
||||
workers[idx].join()
|
||||
best_idxes = list(map(min, zip(*ms)))
|
||||
|
||||
if not args.crash_dir:
|
||||
logger.info(
|
||||
"Found %d unique tuples across %d files (%d effective)",
|
||||
len(counter),
|
||||
len(files),
|
||||
effective,
|
||||
)
|
||||
else:
|
||||
logger.info(
|
||||
"Found %d unique tuples across %d files (%d effective, %d crashes)",
|
||||
len(counter),
|
||||
len(files),
|
||||
effective,
|
||||
len(crashes),
|
||||
)
|
||||
all_unique = counter.most_common()
|
||||
|
||||
logger.info("Processing candidates and writing output")
|
||||
already_have = set()
|
||||
count = 0
|
||||
|
||||
def save_file(idx):
|
||||
input_path = files[idx]
|
||||
fn = (
|
||||
base64.b16encode(hash_list[idx]).decode("utf8").lower()
|
||||
if not args.no_dedup
|
||||
else os.path.basename(input_path)
|
||||
)
|
||||
if args.as_queue:
|
||||
if args.no_dedup:
|
||||
fn = "id:%06d,orig:%s" % (count, fn)
|
||||
else:
|
||||
fn = "id:%06d,hash:%s" % (count, fn)
|
||||
output_path = os.path.join(args.output, fn)
|
||||
try:
|
||||
os.link(input_path, output_path)
|
||||
except OSError:
|
||||
shutil.copy(input_path, output_path)
|
||||
|
||||
jobs = [[] for i in range(args.workers)]
|
||||
saved = set()
|
||||
for t, c in all_unique:
|
||||
if c != 1:
|
||||
continue
|
||||
idx = best_idxes[t]
|
||||
if idx in saved:
|
||||
continue
|
||||
save_file(idx)
|
||||
saved.add(idx)
|
||||
count += 1
|
||||
|
||||
worker_idx, pos, tuple_count = trace_info[idx]
|
||||
job = (pos, tuple_count)
|
||||
jobs[worker_idx].append(job)
|
||||
|
||||
trace_packs = []
|
||||
workers = []
|
||||
for i in range(args.workers):
|
||||
pack_name = os.path.join(args.output, ".traces", f"{i}.pack")
|
||||
trace_f = open(pack_name, "rb")
|
||||
trace_packs.append(trace_f)
|
||||
|
||||
p = CombineTraceWorker(pack_name, jobs[i], result_queue)
|
||||
p.start()
|
||||
workers.append(p)
|
||||
|
||||
for _ in range(args.workers):
|
||||
result = result_queue.get()
|
||||
already_have.update(result)
|
||||
|
||||
for t, c in tqdm(list(reversed(all_unique)), ncols=0):
|
||||
if t in already_have:
|
||||
continue
|
||||
|
||||
idx = best_idxes[t]
|
||||
save_file(idx)
|
||||
count += 1
|
||||
|
||||
worker_idx, pos, tuple_count = trace_info[idx]
|
||||
trace_pack = trace_packs[worker_idx]
|
||||
trace_pack.seek(pos)
|
||||
result = array.array(tuple_index_type_code)
|
||||
result.fromfile(trace_pack, tuple_count)
|
||||
|
||||
already_have.update(result)
|
||||
|
||||
for f in trace_packs:
|
||||
f.close()
|
||||
|
||||
if args.crash_dir:
|
||||
logger.info("Saving crashes to %s", args.crash_dir)
|
||||
crash_files = [files[c] for c in crashes]
|
||||
|
||||
if args.no_dedup:
|
||||
# Unless we deduped previously, we have to dedup the crash files
|
||||
# now.
|
||||
crash_files, hash_list = dedup(crash_files)
|
||||
|
||||
for idx, crash_path in enumerate(crash_files):
|
||||
fn = base64.b16encode(hash_list[idx]).decode("utf8").lower()
|
||||
output_path = os.path.join(args.crash_dir, fn)
|
||||
try:
|
||||
os.link(crash_path, output_path)
|
||||
except OSError:
|
||||
try:
|
||||
shutil.copy(crash_path, output_path)
|
||||
except shutil.Error:
|
||||
# This error happens when src and dest are hardlinks of the
|
||||
# same file. We have nothing to do in this case, but handle
|
||||
# it gracefully.
|
||||
pass
|
||||
|
||||
if count == 1:
|
||||
logger.warning("all test cases had the same traces, check syntax!")
|
||||
logger.info('narrowed down to %s files, saved in "%s"', count, args.output)
|
||||
if not os.environ.get("AFL_KEEP_TRACES"):
|
||||
logger.info("Deleting trace files")
|
||||
trace_dir = os.path.join(args.output, ".traces")
|
||||
shutil.rmtree(trace_dir, ignore_errors=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -4,7 +4,7 @@ CFLAGS = -O3 -funroll-loops -fPIC
|
||||
all: aflpp-standalone
|
||||
|
||||
aflpp-standalone: aflpp-standalone.c
|
||||
$(CC) $(CFLAGS) -w -DBIN_PATH=\"foo\" -I../../../include -I. -o aflpp-standalone aflpp-standalone.c ../../../src/afl-performance.c ../../../src/afl-fuzz-extras.c ../../../src/afl-common.c
|
||||
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -o aflpp-standalone aflpp-standalone.c ../../../src/afl-performance.c ../../../src/afl-fuzz-extras.c ../../../src/afl-common.c
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ aflpp-standalone core
|
||||
|
@ -1,20 +1,19 @@
|
||||
|
||||
CFLAGS = -g -O3 -funroll-loops -fPIC -D_STANDALONE_MODULE=1 -Wno-pointer-sign
|
||||
CFLAGS = -g -O3 -funroll-loops -fPIC -D_STANDALONE_MODULE=1 -Wno-implicit-function-declaration
|
||||
CXXFLAGS= -g -O3 -funroll-loops -fPIC -D_STANDALONE_MODULE=1
|
||||
|
||||
all: autotokens-standalone
|
||||
|
||||
autotokens.o: ../autotokens.cpp
|
||||
$(CXX) $(CXXFLAGS) -g -I../../../include -I. -I../.. -c ../autotokens.cpp
|
||||
$(CXX) $(CXXFLAGS) -I../../../include -I. -I../.. -c ../autotokens.cpp
|
||||
|
||||
autotokens-standalone: autotokens-standalone.c autotokens.o
|
||||
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c autotokens-standalone.c
|
||||
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-performance.c
|
||||
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-fuzz-extras.c
|
||||
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-fuzz-queue.c
|
||||
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-common.c
|
||||
$(CXX) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -o autotokens-standalone *.o
|
||||
@rm -f ../../../src/afl-common.o ../../../src/afl-fuzz-queue.o ../../../src/afl-fuzz-extras.o ../../../src/afl-performance.o
|
||||
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c autotokens-standalone.c
|
||||
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-performance.c
|
||||
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-fuzz-extras.c
|
||||
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-fuzz-queue.c
|
||||
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-common.c
|
||||
$(CXX) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -o autotokens-standalone *.o
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ autotokens-standalone core
|
||||
|
@ -1,28 +1,15 @@
|
||||
#include "afl-fuzz.h"
|
||||
#include "afl-mutations.h"
|
||||
#include "forkserver.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
|
||||
static int max_havoc = 16, verbose;
|
||||
static char _mh[4] = "16";
|
||||
static char *dict, *mh = _mh;
|
||||
static unsigned char *dict, *mh = "16";
|
||||
|
||||
extern int module_disabled;
|
||||
|
||||
void *afl_custom_init(afl_state_t *, unsigned int);
|
||||
u8 afl_custom_queue_get(void *data, const u8 *filename);
|
||||
size_t afl_custom_fuzz(void *data, u8 *buf, size_t buf_size, u8 **out_buf,
|
||||
u8 *add_buf, size_t add_buf_size, size_t max_size);
|
||||
|
||||
u32 write_to_testcase(afl_state_t *afl, void **mem, u32 a, u32 b) {
|
||||
return 0;
|
||||
}
|
||||
fsrv_run_result_t fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv,
|
||||
u32 i) {
|
||||
return FSRV_RUN_OK;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
@ -157,7 +144,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
if (dict) {
|
||||
|
||||
load_extras(afl, (u8*)dict);
|
||||
load_extras(afl, dict);
|
||||
if (verbose)
|
||||
fprintf(stderr, "Loaded dictionary: %s (%u entries)\n", dict,
|
||||
afl->extras_cnt);
|
||||
|
@ -3,53 +3,19 @@
|
||||
This is the list of all noteworthy changes made in every public
|
||||
release of the tool. See README.md for the general instruction manual.
|
||||
|
||||
|
||||
### Version ++4.33a (dev)
|
||||
- afl-fuzz:
|
||||
- Use `AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT` if you use AFL_PRELOAD
|
||||
to disable fork, see docs (thanks to @alexandredoyen29)
|
||||
- Fix for FAST power schedules (introduced in 4.32c) (thanks to @kcwu)
|
||||
- Colors for NO_UI output (thanks to @smoelius)
|
||||
- Fix potential sync issues when resuming sessions and when instances in a
|
||||
campaign are restarted and skip entries that were synced from itself
|
||||
(thanks to @kcwu for raising the issues and providing support!)
|
||||
- more 64 bit archicture support by @maribu
|
||||
- afl-cc:
|
||||
- Added instrumenting hidden edges (approx 5% edges were not instrumented,
|
||||
LLVM sancov overall misses 8% of edges compared to our implementation)
|
||||
Note that is is currently only implemented for our PCGUARD plugin, not
|
||||
LTO, CLASSIC, etc.!
|
||||
- Fix to make AFL_SAN_NO_INST work with gcc_plugin
|
||||
- MacOS aflpp driver compilation fix (-fsanitize=fuzzer implementation)
|
||||
- Make AFL_DUMP_MAP_SIZE work even if the target has sanitizer issues
|
||||
- qemuafl:
|
||||
- Better MIPS persistent mode support
|
||||
- afl-cmin:
|
||||
- New afl-cmin.py which is much faster, will be executed by default via
|
||||
afl-cmin if it executes successfully (thanks to @kcwu!)
|
||||
- New desocketing library: utils/libaflppdesock
|
||||
- Likely works when all other desocketing options fail
|
||||
|
||||
|
||||
### Version ++4.32c (release)
|
||||
### Version ++4.32a (dev)
|
||||
- Fixed a bug where after a fast restart of a full fuzzed corpus afl-fuzz
|
||||
terminates with "need at least one valid input seed that does not crash"
|
||||
- Small improvements to afl-*-config
|
||||
- afl-fuzz:
|
||||
- memory leak fixes by @kcwu - thanks!
|
||||
- many more nits and small memory saves thanks to @kcwu
|
||||
- some more nits and small memory saves thanks to @kcwu
|
||||
- remove deprecated files from queue/.state
|
||||
- fix bitmap update function if no current trace is present
|
||||
- fix for afl_custom_queue_get
|
||||
- various small nits
|
||||
- afl-cc:
|
||||
- fix pass support for LLVM 20 (passes were run too early)
|
||||
- dropped plugin support for LLVM 13
|
||||
- fix AFL_OLD_FORKSERVER
|
||||
- various minor fixes
|
||||
- frida_mode:
|
||||
- fixes for new MacOS + M4 hardware
|
||||
|
||||
|
||||
### Version ++4.31c (release)
|
||||
- SAND mode added (docs/SAND.md) for more effecient fuzzing with sanitizers
|
||||
(thanks to @wtdcode !)
|
||||
|
12
docs/FAQ.md
12
docs/FAQ.md
@ -11,7 +11,7 @@ If you find an interesting or important question missing, submit it via
|
||||
AFL++ is a superior fork to Google's AFL - more speed, more and better
|
||||
mutations, more and better instrumentation, custom module support, etc.
|
||||
|
||||
American Fuzzy Lop (AFL) was developed by Michal "lcamtuf" Zalewski starting
|
||||
American Fuzzy Lop (AFL) was developed by Michał "lcamtuf" Zalewski starting
|
||||
in 2013/2014, and when he left Google end of 2017 he stopped developing it.
|
||||
|
||||
At the end of 2019, the Google fuzzing team took over maintenance of AFL,
|
||||
@ -284,14 +284,14 @@ If you find an interesting or important question missing, submit it via
|
||||
afl-cc/afl-clang-fast/afl-clang-lto:
|
||||
|
||||
```
|
||||
/prg/tmp/llvm-project/build/bin/clang-18: symbol lookup error: /usr/local/bin/../lib/afl//cmplog-instructions-pass.so: undefined symbol: _ZNK4llvm8TypeSizecvmEv
|
||||
clang-18: error: unable to execute command: No such file or directory
|
||||
clang-18: error: clang frontend command failed due to signal (use -v to see invocation)
|
||||
clang version 18.0.0 (https://github.com/llvm/llvm-project 1d7cf550721c51030144f3cd295c5789d51c4aad)
|
||||
/prg/tmp/llvm-project/build/bin/clang-13: symbol lookup error: /usr/local/bin/../lib/afl//cmplog-instructions-pass.so: undefined symbol: _ZNK4llvm8TypeSizecvmEv
|
||||
clang-13: error: unable to execute command: No such file or directory
|
||||
clang-13: error: clang frontend command failed due to signal (use -v to see invocation)
|
||||
clang version 13.0.0 (https://github.com/llvm/llvm-project 1d7cf550721c51030144f3cd295c5789d51c4aad)
|
||||
Target: x86_64-unknown-linux-gnu
|
||||
Thread model: posix
|
||||
InstalledDir: /prg/tmp/llvm-project/build/bin
|
||||
clang-18: note: diagnostic msg:
|
||||
clang-13: note: diagnostic msg:
|
||||
********************
|
||||
```
|
||||
|
||||
|
@ -21,7 +21,7 @@ If you want to build AFL++ yourself, you have many options. The easiest choice
|
||||
is to build and install everything:
|
||||
|
||||
NOTE: depending on your Debian/Ubuntu/Kali/... release, replace `-14` with
|
||||
whatever llvm version is available. We recommend llvm 14 or newer.
|
||||
whatever llvm version is available. We recommend llvm 13 or newer.
|
||||
|
||||
```shell
|
||||
sudo apt-get update
|
||||
|
@ -21,7 +21,7 @@ For a normal fuzzing workflow, we have:
|
||||
For SAND fuzzing workflow, this is slightly different:
|
||||
|
||||
1. Build target project _without_ any sanitizers to get `target_native`, which we will define as a "native binary". It is usually done by using `afl-clang-fast/lto(++)` to compile your project _without_ `AFL_USE_ASAN/UBSAN/MSAN`.
|
||||
2. Build target project with AFL_USE_ASAN=1 AFL_LLVM_ONLY_FSRV=1 to get `target_asan`. Do note this step can be repeated for multiple sanitizers, like MSAN, UBSAN etc. It is also possible to have ASAN and UBSAN to build together.
|
||||
2. Build target project with AFL_USE_ASAN=1 AFL_SAN_NO_INST=1 to get `target_asan`. Do note this step can be repeated for multiple sanitizers, like MSAN, UBSAN etc. It is also possible to have ASAN and UBSAN to build together.
|
||||
3. Fuzz the target with `afl-fuzz -i seeds -o out -w ./target_asan -- ./target_native`. Note `-w` can be specified multiple times.
|
||||
|
||||
Then you get:
|
||||
@ -44,11 +44,11 @@ Just like the normal building process, except using `afl-clang-fast`
|
||||
2. Build the sanitizers-enabled binaries.
|
||||
|
||||
```bash
|
||||
AFL_LLVM_ONLY_FSRV=1 AFL_USE_UBSAN=1 AFL_USE_ASAN=1 afl-clang-fast test-instr.c -o ./asanubsan
|
||||
AFL_LLVM_ONLY_FSRV=1 AFL_USE_MSAN=1 afl-clang-fast test-instr.c -o ./msan
|
||||
AFL_SAN_NO_INST=1 AFL_USE_UBSAN=1 AFL_USE_ASAN=1 afl-clang-fast test-instr.c -o ./asanubsan
|
||||
AFL_SAN_NO_INST=1 AFL_USE_MSAN=1 afl-clang-fast test-instr.c -o ./msan
|
||||
```
|
||||
|
||||
Do note `AFL_LLVM_ONLY_FSRV=1` is crucial, this enables forkservers but disables pc instrumentation. You are allowed to reuse sanitizers-enabled binaries, i.e. binaries built _without_ `AFL_LLVM_ONLY_FSRV=1`, at a cost of reduced speed.
|
||||
Do note `AFL_SAN_NO_INST=1` is crucial, this enables forkservers but disables pc instrumentation. Do not reuse sanitizers-enabled binaries built _without_ `AFL_SAN_NO_INST=1`. This will mess up SAND execution pattern.
|
||||
|
||||
3. Start fuzzing
|
||||
|
||||
|
@ -111,10 +111,6 @@ fairly broad use of environment variables instead:
|
||||
|
||||
- Note: both `AFL_CFISAN_VERBOSE=1` and `AFL_UBSAN_VERBOSE=1` are disabled by default as verbose output can significantly slow down fuzzing performance. Use these options only during debugging or when additional crash diagnostics are required
|
||||
|
||||
- `AFL_LLVM_ONLY_FSRV`/`AFL_GCC_ONLY_FSRV` will inject forkserver but not pc instrumentation. Please note this is different compared to `AFL_LLVM_DISABLE_INSTRUMENTATION`, which will totally disable forkserver implementation. This env is pretty useful in two cases:
|
||||
- [SAND](./SAND.md). In this case, the binaries built in this way will serve as extra oracles. Check the corresponding documents for details.
|
||||
- Compatible with LibAFL ForkserverExecutor implementation and thus faster to repeatedly run, compared to simple CommandExecutor.
|
||||
|
||||
- `TMPDIR` is used by afl-as for temporary files; if this variable is not set,
|
||||
the tool defaults to /tmp.
|
||||
|
||||
@ -668,24 +664,6 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
Note that will not be exact and with slow targets it can take seconds
|
||||
until there is a slice for the time test.
|
||||
|
||||
- When using `AFL_PRELOAD` with a preload that disable `fork()` calls in
|
||||
the target, the forkserver becomes unable to fork.
|
||||
To overcome this issue, the `AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT`
|
||||
permits to be able to check in the preloaded library if the environment
|
||||
variable `AFL_FORKSERVER_PARENT` is set, to be able to use vanilla
|
||||
`fork()` in the forkserver, and the placeholder in the target.
|
||||
Here is a POC :
|
||||
```C
|
||||
// AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT=1 afl-fuzz ...
|
||||
pid_t fork(void)
|
||||
{
|
||||
if (getenv("AFL_FORKSERVER_PARENT") == NULL)
|
||||
return 0; // We are in the target
|
||||
else
|
||||
return real_fork(); // We are in the forkserver
|
||||
}
|
||||
```
|
||||
|
||||
## 6) Settings for afl-qemu-trace
|
||||
|
||||
The QEMU wrapper used to instrument binary-only code supports several settings:
|
||||
|
@ -45,7 +45,7 @@ E. CmpLog is our enhanced
|
||||
implementation, see
|
||||
[instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md)
|
||||
|
||||
F. Similar and compatible to clang 14+ sancov sanitize-coverage-allow/deny but
|
||||
F. Similar and compatible to clang 13+ sancov sanitize-coverage-allow/deny but
|
||||
for all llvm versions and all our compile modes, only instrument what should
|
||||
be instrumented, for more speed, directed fuzzing and less instability; see
|
||||
[instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md)
|
||||
|
@ -132,15 +132,11 @@ options are available:
|
||||
locations. This technique is very fast and good - if the target does not
|
||||
transform input data before comparison. Therefore, this technique is called
|
||||
`input to state` or `redqueen`. If you want to use this technique, then you
|
||||
have to compile the target with `AFL_LLVM_CMPLOG=1`.
|
||||
You could use the resulting binary for both normal fuzzing and `-c` CMPLOG
|
||||
mode (with `-c 0`), however this will result in a performance loss of about
|
||||
20%.
|
||||
It is therefore better to compile a specific CMPLOG target with
|
||||
`AFL_LLVM_ONLY_FSRV=1 AFL_LLVM_CMPLOG=1` and pass this binary name via
|
||||
`-c cmplog-fuzzing-target` and compile target again normally with `afl-cc`
|
||||
and use this is the fuzzing target as usual.
|
||||
You can read more about this in
|
||||
have to compile the target twice, once specifically with/for this mode by
|
||||
setting `AFL_LLVM_CMPLOG=1`, and pass this binary to afl-fuzz via the `-c`
|
||||
parameter. Note that you can compile also just a cmplog binary and use that
|
||||
for both, however, there will be a performance penalty. You can read more
|
||||
about this in
|
||||
[instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md).
|
||||
|
||||
If you use LTO, LLVM, or GCC_PLUGIN mode
|
||||
@ -869,13 +865,10 @@ Here are some of the most important caveats for AFL++:
|
||||
|
||||
- There is no direct support for fuzzing network services, background daemons,
|
||||
or interactive apps that require UI interaction to work. You may need to make
|
||||
simple code changes to make them behave in a more traditional way. Preeny,
|
||||
libdesock or desockmulti may offer a relatively simple option, too - see:
|
||||
simple code changes to make them behave in a more traditional way. Preeny or
|
||||
libdesock may offer a relatively simple option, too - see:
|
||||
[https://github.com/zardus/preeny](https://github.com/zardus/preeny) or
|
||||
[https://github.com/fkie-cad/libdesock](https://github.com/fkie-cad/libdesock)
|
||||
[https://github.com/zyingp/desockmulti](https://github.com/zyingp/desockmulti)
|
||||
If these fail then try our own which might be a bit slower but is more
|
||||
reliable: [utils/libaflppdesock](../utils/libaflppdesock)
|
||||
|
||||
Some useful tips for modifying network-based services can be also found at:
|
||||
[https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop](https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop)
|
||||
|
@ -15,7 +15,6 @@ JS_OBJ:=$(BUILD_DIR)api.o
|
||||
SOURCES:=$(wildcard $(SRC_DIR)**/*.c) $(wildcard $(SRC_DIR)*.c)
|
||||
OBJS:=$(foreach src,$(SOURCES),$(OBJ_DIR)$(notdir $(patsubst %.c, %.o, $(src))))
|
||||
|
||||
XTOOLS_HOST?=x86_64-linux-gnu
|
||||
TARGET_CC?=$(CC)
|
||||
TARGET_CXX?=$(CXX)
|
||||
HOST_CC?=$(CC)
|
||||
@ -187,13 +186,39 @@ ifndef OS
|
||||
$(error "Operating system unsupported")
|
||||
endif
|
||||
|
||||
GUM_DEVKIT_VERSION=17.0.7
|
||||
GUM_DEVKIT_VERSION=16.1.11
|
||||
GUM_DEVKIT_FILENAME=frida-gumjs-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar.xz
|
||||
GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(GUM_DEVKIT_VERSION)/$(GUM_DEVKIT_FILENAME)"
|
||||
|
||||
ifeq ($(OS),macos)
|
||||
# Extract the major version
|
||||
GUM_VERSION_MAJOR := $(shell echo "$(GUM_DEVKIT_VERSION)" | sed -E 's/\..*//')
|
||||
# Extract the minor version (assumes format "MAJOR.MINOR[.PATCH...]")
|
||||
GUM_VERSION_MINOR := $(shell echo "$(GUM_DEVKIT_VERSION)" | sed -E 's/^[^.]*\.//; s/\..*//')
|
||||
|
||||
# Evaluate the version condition in a separate shell call
|
||||
IS_GUM_16_6_PLUS := $(shell \
|
||||
if (( $(GUM_VERSION_MAJOR) > 16 || ( $(GUM_VERSION_MAJOR) == 16 && $(GUM_VERSION_MINOR) >= 6 ) )); then \
|
||||
echo 1; \
|
||||
fi)
|
||||
else
|
||||
IS_GUM_16_6_PLUS := $(shell VERSION="$(GUM_DEVKIT_VERSION)"; \
|
||||
MAJOR=$${VERSION%%.*}; \
|
||||
MINOR=$${VERSION#*.}; MINOR=$${MINOR%%.*}; \
|
||||
if [ $$MAJOR -gt 16 ] || { [ $$MAJOR -eq 16 ] && [ $$MINOR -ge 6 ]; }; then \
|
||||
echo 1; \
|
||||
fi)
|
||||
endif
|
||||
|
||||
CFLAGS += $(if $(IS_GUM_16_6_PLUS),-DGUM_16_6_PLUS)
|
||||
|
||||
GUM_DEVKIT_TARBALL:=$(FRIDA_BUILD_DIR)$(GUM_DEVKIT_FILENAME)
|
||||
GUM_DEVIT_HEADER=$(FRIDA_BUILD_DIR)frida-gumjs.h
|
||||
ifdef FRIDA_SOURCE
|
||||
GUM_DEVIT_LIBRARY=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gumjs-1.0.a
|
||||
else
|
||||
GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gumjs.a
|
||||
endif
|
||||
GUM_DEVIT_HEADER=$(FRIDA_BUILD_DIR)frida-gumjs.h
|
||||
|
||||
FRIDA_DIR:=$(PWD)build/frida-source/
|
||||
FRIDA_MAKEFILE:=$(FRIDA_DIR)Makefile
|
||||
@ -227,13 +252,13 @@ BIN2C_SRC:=$(PWD)util/bin2c.c
|
||||
all: $(FRIDA_TRACE) $(FRIDA_TRACE_LIB) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_QEMU_DRIVER_HOOK_OBJ) $(ADDR_BIN)
|
||||
|
||||
32:
|
||||
XTOOLS_HOST=i686-linux-gnu CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
|
||||
CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
|
||||
|
||||
arm:
|
||||
XTOOLS_HOST=arm-linux-gnueabihf CFLAGS="-marm" LDFLAGS="-marm" ARCH="armhf" TARGET_CC=arm-linux-gnueabihf-gcc TARGET_CXX=arm-linux-gnueabihf-g++ make all
|
||||
CFLAGS="-marm" LDFLAGS="-marm" ARCH="armhf" TARGET_CC=arm-linux-gnueabihf-gcc TARGET_CXX=arm-linux-gnueabihf-g++ make all
|
||||
|
||||
arm64:
|
||||
XTOOLS_HOST=aarch64-linux-gnu ARCH="arm64" TARGET_CC=aarch64-linux-gnu-gcc TARGET_CXX=aarch64-linux-gnu-g++ make all
|
||||
ARCH="arm64" TARGET_CC=aarch64-linux-gnu-gcc TARGET_CXX=aarch64-linux-gnu-g++ make all
|
||||
|
||||
$(BUILD_DIR):
|
||||
mkdir -p $(BUILD_DIR)
|
||||
@ -246,29 +271,114 @@ $(OBJ_DIR): | $(BUILD_DIR)
|
||||
$(FRIDA_BUILD_DIR): | $(BUILD_DIR)
|
||||
mkdir -p $@
|
||||
|
||||
#TODO Set architecture
|
||||
ifdef FRIDA_SOURCE
|
||||
$(FRIDA_MAKEFILE): | $(BUILD_DIR)
|
||||
git clone https://github.com/frida/frida-gum.git $(FRIDA_DIR)
|
||||
cd $(FRIDA_DIR) && \
|
||||
./configure \
|
||||
--host=$(XTOOLS_HOST) \
|
||||
--enable-tests \
|
||||
--enable-gumpp \
|
||||
--enable-gumjs \
|
||||
--with-devkits=gum,gumjs
|
||||
git clone --recursive https://github.com/frida/frida.git $(FRIDA_DIR)
|
||||
|
||||
.PHONY: $(GUM_DEVIT_LIBRARY)
|
||||
|
||||
$(GUM_DEVIT_LIBRARY): $(FRIDA_MAKEFILE) | $(FRIDA_BUILD_DIR)
|
||||
echo $(GUM_DEVIT_LIBRARY) $(FRIDA_MAKEFILE) $(FRIDA_BUILD_DIR)
|
||||
cd $(FRIDA_DIR) && make FRIDA_V8=disabled
|
||||
cp $(FRIDA_DIR)build/bindings/gumjs/devkit/frida-gumjs.h $(GUM_DEVIT_HEADER)
|
||||
cp $(FRIDA_DIR)build/bindings/gumjs/devkit/libfrida-gumjs.a $(GUM_DEVIT_LIBRARY)
|
||||
$(GUM_DEVIT_LIBRARY): $(FRIDA_MAKEFILE)
|
||||
cd $(FRIDA_DIR) && make gum-$(OS)$(GUM_ARCH) FRIDA_V8=disabled
|
||||
|
||||
$(GUM_DEVIT_HEADER): $(FRIDA_MAKEFILE) | $(FRIDA_BUILD_DIR)
|
||||
echo "#include <stdio.h>" > $@
|
||||
echo "#include <unistd.h>" >> $@
|
||||
echo "#include <gum/gumreturnaddress.h>" >> $@
|
||||
echo "#include <gum/gumbacktracer.h>" >> $@
|
||||
echo "#include <gum/gumsymbolutil.h>" >> $@
|
||||
echo "#include <gum/gumstalker.h>" >> $@
|
||||
echo "#include <gum/gumlibc.h>" >> $@
|
||||
echo "#include <gumjs/gumscriptbackend.h>" >> $@
|
||||
|
||||
ifeq "$(OS)" "macos"
|
||||
|
||||
CFLAGS+=-I $(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/include/frida-1.0 \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
|
||||
|
||||
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libiconv.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libv8-8.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgmodule-2.0.a \
|
||||
|
||||
else ifeq "$(ARCH)" "arm64"
|
||||
|
||||
CFLAGS+=-I $(FRIDA_DIR)build/$(OS)-$(ARCH)/include/frida-1.0 \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
|
||||
|
||||
ifeq "$(OS)" "android"
|
||||
CFLAGS += -static-libstdc++
|
||||
endif
|
||||
else
|
||||
CFLAGS+=-I $(FRIDA_DIR)build/$(OS)-$(ARCH)/include/frida-1.0 \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
|
||||
|
||||
endif
|
||||
|
||||
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libunwind.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libdwarf.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libelf.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
|
||||
|
||||
CFLAGS+=-I $(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/include/frida-1.0 \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/
|
||||
|
||||
ifeq "$(OS)" "android"
|
||||
CFLAGS += -static-libstdc++
|
||||
endif
|
||||
|
||||
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libunwind.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libdwarf.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libelf.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
|
||||
|
||||
|
||||
else
|
||||
$(GUM_DEVKIT_TARBALL): | $(FRIDA_BUILD_DIR)
|
||||
|
@ -27,6 +27,7 @@ void asan_init(void) {
|
||||
|
||||
}
|
||||
|
||||
#ifdef GUM_16_6_PLUS
|
||||
static gboolean asan_exclude_module(GumModule *module, gpointer user_data) {
|
||||
|
||||
gchar *symbol_name = (gchar *)user_data;
|
||||
@ -46,6 +47,32 @@ static gboolean asan_exclude_module(GumModule *module, gpointer user_data) {
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
static gboolean asan_exclude_module(const GumModuleDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
gchar *symbol_name = (gchar *)user_data;
|
||||
GumAddress address;
|
||||
|
||||
address = gum_module_find_export_by_name(details->name, symbol_name);
|
||||
if (address == 0) { return TRUE; }
|
||||
|
||||
/* If the reported address of the symbol is outside of the range of the module
|
||||
* then ignore it */
|
||||
if (address < details->range->base_address) { return TRUE; }
|
||||
if (address > (details->range->base_address + details->range->size)) {
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
ranges_add_exclude((GumMemoryRange *)details->range);
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void asan_exclude_module_by_symbol(gchar *symbol_name) {
|
||||
|
||||
gum_process_enumerate_modules(asan_exclude_module, symbol_name);
|
||||
|
@ -382,5 +382,5 @@ Afl.jsApiSetTraceable = Afl.jsApiGetFunction("js_api_set_traceable", "void", [])
|
||||
Afl.jsApiSetVerbose = Afl.jsApiGetFunction("js_api_set_verbose", "void", []);
|
||||
Afl.jsApiWrite = new NativeFunction(
|
||||
/* tslint:disable-next-line:no-null-keyword */
|
||||
Module.getGlobalExportByName("write"), "int", ["int", "pointer", "int"]);
|
||||
Module.getExportByName(null, "write"), "int", ["int", "pointer", "int"]);
|
||||
Afl.jsApiIjonSet = Afl.jsApiGetFunction("js_api_ijon_set", "void", ["uint32"]);
|
||||
|
@ -39,6 +39,7 @@ typedef struct {
|
||||
static guint64 text_base = 0;
|
||||
static guint64 text_limit = 0;
|
||||
|
||||
#ifdef GUM_16_6_PLUS
|
||||
static gboolean lib_find_exe(GumModule *module, gpointer user_data) {
|
||||
|
||||
lib_details_t *lib_details = (lib_details_t *)user_data;
|
||||
@ -56,6 +57,24 @@ static gboolean lib_find_exe(GumModule *module, gpointer user_data) {
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
static gboolean lib_find_exe(const GumModuleDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
lib_details_t *lib_details = (lib_details_t *)user_data;
|
||||
|
||||
strncpy(lib_details->name, details->name, PATH_MAX);
|
||||
strncpy(lib_details->path, details->path, PATH_MAX);
|
||||
lib_details->name[PATH_MAX] = '\0';
|
||||
lib_details->path[PATH_MAX] = '\0';
|
||||
lib_details->base_address = details->range->base_address;
|
||||
lib_details->size = details->range->size;
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void lib_validate_hdr(Elf_Ehdr *hdr) {
|
||||
|
||||
if (hdr->e_ident[0] != ELFMAG0) FFATAL("Invalid e_ident[0]");
|
||||
|
@ -12,6 +12,7 @@ extern void gum_darwin_enumerate_modules(mach_port_t task,
|
||||
static guint64 text_base = 0;
|
||||
static guint64 text_limit = 0;
|
||||
|
||||
#ifdef GUM_16_6_PLUS
|
||||
static gboolean lib_get_main_module(GumModule *module, gpointer user_data) {
|
||||
|
||||
GumDarwinModule **ret = (GumDarwinModule **)user_data;
|
||||
@ -29,6 +30,25 @@ static gboolean lib_get_main_module(GumModule *module, gpointer user_data) {
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
static gboolean lib_get_main_module(const GumModuleDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
GumDarwinModule **ret = (GumDarwinModule **)user_data;
|
||||
GumDarwinModule *module = gum_darwin_module_new_from_memory(
|
||||
details->path, mach_task_self(), details->range->base_address,
|
||||
GUM_DARWIN_MODULE_FLAGS_NONE, NULL);
|
||||
|
||||
FVERBOSE("Found main module: %s", module->name);
|
||||
|
||||
*ret = module;
|
||||
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
gboolean lib_get_text_section(const GumDarwinSectionDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
|
@ -46,7 +46,6 @@ gboolean found_range(const GumRangeDetails *details, gpointer user_data) {
|
||||
static int on_dlclose(void *handle) {
|
||||
|
||||
GArray *ranges = NULL;
|
||||
GumModule *module = NULL;
|
||||
struct link_map *lm = NULL;
|
||||
gum_range_t *range = NULL;
|
||||
GumAddress base;
|
||||
@ -62,12 +61,8 @@ static int on_dlclose(void *handle) {
|
||||
FVERBOSE("on_dlclose: %s", lm->l_name);
|
||||
|
||||
ranges = g_array_new(FALSE, TRUE, sizeof(gum_range_t));
|
||||
|
||||
module = gum_process_find_module_by_name(lm->l_name);
|
||||
|
||||
if (module == NULL) { FATAL("Failed to find module: %s", lm->l_name); }
|
||||
|
||||
gum_module_enumerate_ranges(module, GUM_PAGE_EXECUTE, found_range, ranges);
|
||||
gum_module_enumerate_ranges(lm->l_name, GUM_PAGE_EXECUTE, found_range,
|
||||
ranges);
|
||||
|
||||
int ret = dlclose(handle);
|
||||
if (ret != 0) {
|
||||
|
@ -263,8 +263,13 @@ static int prefetch_on_fork(void) {
|
||||
|
||||
static void prefetch_hook_fork(void) {
|
||||
|
||||
#ifdef GUM_16_6_PLUS
|
||||
void *fork_addr =
|
||||
GSIZE_TO_POINTER(gum_module_find_global_export_by_name("fork"));
|
||||
#else
|
||||
void *fork_addr =
|
||||
GSIZE_TO_POINTER(gum_module_find_export_by_name(NULL, "fork"));
|
||||
#endif
|
||||
intercept_hook(fork_addr, prefetch_on_fork, NULL);
|
||||
|
||||
}
|
||||
|
@ -116,6 +116,7 @@ static void convert_address_token(gchar *token, GumMemoryRange *range) {
|
||||
|
||||
}
|
||||
|
||||
#ifdef GUM_16_6_PLUS
|
||||
static gboolean convert_name_token_for_module(GumModule *module,
|
||||
gpointer user_data) {
|
||||
|
||||
@ -137,6 +138,28 @@ static gboolean convert_name_token_for_module(GumModule *module,
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
static gboolean convert_name_token_for_module(const GumModuleDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
convert_name_ctx_t *ctx = (convert_name_ctx_t *)user_data;
|
||||
if (details->path == NULL) { return true; };
|
||||
|
||||
if (!g_str_has_suffix(details->path, ctx->suffix)) { return true; };
|
||||
|
||||
FVERBOSE("Found module - prefix: %s, 0x%016" G_GINT64_MODIFIER
|
||||
"x-0x%016" G_GINT64_MODIFIER "x %s",
|
||||
ctx->suffix, details->range->base_address,
|
||||
details->range->base_address + details->range->size, details->path);
|
||||
|
||||
*ctx->range = *details->range;
|
||||
ctx->done = true;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void convert_name_token(gchar *token, GumMemoryRange *range) {
|
||||
|
||||
gchar *suffix = g_strconcat("/", token, NULL);
|
||||
|
1950
generator_mutation_gpt_3_5.py
Normal file
1950
generator_mutation_gpt_3_5.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -770,7 +770,6 @@ typedef struct afl_state {
|
||||
#define FOREIGN_SYNCS_MAX 32U
|
||||
u8 foreign_sync_cnt;
|
||||
struct foreign_sync foreign_syncs[FOREIGN_SYNCS_MAX];
|
||||
char *foreign_file;
|
||||
|
||||
#ifdef _AFL_DOCUMENT_MUTATIONS
|
||||
u8 do_document;
|
||||
@ -874,6 +873,9 @@ typedef struct afl_state {
|
||||
u32 bitsmap_size;
|
||||
#endif
|
||||
|
||||
char *target_program;
|
||||
char *generator_base_path;
|
||||
|
||||
} afl_state_t;
|
||||
|
||||
struct custom_mutator {
|
||||
@ -1140,7 +1142,6 @@ struct custom_mutator {
|
||||
|
||||
void afl_state_init(afl_state_t *, uint32_t map_size);
|
||||
void afl_state_deinit(afl_state_t *);
|
||||
void afl_resize_map_buffers(afl_state_t *, u32 old_size, u32 new_size);
|
||||
|
||||
/* Set stop_soon flag on all children, kill all children */
|
||||
void afl_states_stop(void);
|
||||
@ -1182,7 +1183,7 @@ u8 havoc_mutation_probability_py(void *);
|
||||
u8 queue_get_py(void *, const u8 *);
|
||||
const char *introspection_py(void *);
|
||||
u8 queue_new_entry_py(void *, const u8 *, const u8 *);
|
||||
void splice_optout_py(void *);
|
||||
void splice_optout(void *);
|
||||
void deinit_py(void *);
|
||||
|
||||
#endif
|
||||
@ -1217,6 +1218,7 @@ u8 *describe_op(afl_state_t *, u8, size_t);
|
||||
#endif
|
||||
u8 save_if_interesting(afl_state_t *, void *, u32, u8);
|
||||
u8 has_new_bits(afl_state_t *, u8 *);
|
||||
u8 has_new_bits_unclassified(afl_state_t *, u8 *);
|
||||
#ifndef AFL_SHOWMAP
|
||||
void classify_counts(afl_forkserver_t *);
|
||||
#endif
|
||||
@ -1259,7 +1261,6 @@ int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen);
|
||||
|
||||
/* Run */
|
||||
|
||||
void check_sync_fuzzers(afl_state_t *);
|
||||
void sync_fuzzers(afl_state_t *);
|
||||
u32 write_to_testcase(afl_state_t *, void **, u32, u32);
|
||||
u8 calibrate_case(afl_state_t *, struct queue_entry *, u8 *, u32, u8);
|
||||
@ -1280,6 +1281,7 @@ u8 fuzz_one(afl_state_t *);
|
||||
#ifdef HAVE_AFFINITY
|
||||
void bind_to_free_cpu(afl_state_t *);
|
||||
#endif
|
||||
void setup_post(afl_state_t *);
|
||||
void read_testcases(afl_state_t *, u8 *);
|
||||
void perform_dry_run(afl_state_t *);
|
||||
void pivot_inputs(afl_state_t *);
|
||||
|
@ -26,7 +26,7 @@
|
||||
/* Version string: */
|
||||
|
||||
// c = release, a = volatile github dev, e = experimental branch
|
||||
#define VERSION "++4.33a"
|
||||
#define VERSION "++4.32a"
|
||||
|
||||
/******************************************************
|
||||
* *
|
||||
@ -171,9 +171,8 @@
|
||||
#define EXEC_TM_ROUND 20U
|
||||
|
||||
/* 64bit arch MACRO */
|
||||
#if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__) || \
|
||||
(defined(__riscv) && __riscv_xlen == 64) || defined(__powerpc64le__) || \
|
||||
defined(__s390x__) || defined(__loongarch64))
|
||||
#if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__) || \
|
||||
(defined(__riscv) && __riscv_xlen == 64))
|
||||
#define WORD_SIZE_64 1
|
||||
#endif
|
||||
|
||||
@ -339,10 +338,6 @@
|
||||
|
||||
#define AVG_SMOOTHING 16
|
||||
|
||||
/* Max length of sync id (the id after -M and -S) */
|
||||
|
||||
#define SYNC_ID_MAX_LEN 50
|
||||
|
||||
/* Sync interval (every n havoc cycles): */
|
||||
|
||||
#define SYNC_INTERVAL 8
|
||||
@ -428,15 +423,9 @@
|
||||
|
||||
#define SHM_ENV_VAR "__AFL_SHM_ID"
|
||||
|
||||
/* Environment variable used to pass shared memory fuzz map id
|
||||
and the mapping size to the called program. */
|
||||
/* Environment variable used to pass SHM FUZZ ID to the called program. */
|
||||
|
||||
#define SHM_FUZZ_ENV_VAR "__AFL_SHM_FUZZ_ID"
|
||||
#define SHM_FUZZ_MAP_SIZE_ENV_VAR "__AFL_SHM_FUZZ_MAP_SIZE"
|
||||
|
||||
/* Default size of the shared memory fuzz map.
|
||||
We add 4 byte for one u32 length field. */
|
||||
#define SHM_FUZZ_MAP_SIZE_DEFAULT (MAX_FILE + 4)
|
||||
|
||||
/* Other less interesting, internal-only variables. */
|
||||
|
||||
|
@ -10,7 +10,6 @@ static char *afl_environment_deprecated[] = {
|
||||
"AFL_DEFER_FORKSRV",
|
||||
"AFL_POST_LIBRARY",
|
||||
"AFL_PERSISTENT",
|
||||
"AFL_SAN_NO_INST",
|
||||
NULL
|
||||
|
||||
};
|
||||
@ -119,8 +118,7 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_CFISAN_VERBOSE", "AFL_USE_LSAN", "AFL_WINE_PATH", "AFL_NO_SNAPSHOT",
|
||||
"AFL_EXPAND_HAVOC_NOW", "AFL_USE_FASAN", "AFL_USE_QASAN",
|
||||
"AFL_PRINT_FILENAMES", "AFL_PIZZA_MODE", "AFL_NO_FASTRESUME",
|
||||
"AFL_SAN_ABSTRACTION", "AFL_LLVM_ONLY_FSRV", "AFL_GCC_ONLY_FRSV",
|
||||
"AFL_SAN_RECOVER", "AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT", NULL};
|
||||
"AFL_SAN_ABSTRACTION", "AFL_SAN_NO_INST", "AFL_SAN_RECOVER", NULL};
|
||||
|
||||
extern char *afl_environment_variables[];
|
||||
|
||||
|
@ -159,8 +159,6 @@ typedef struct afl_forkserver {
|
||||
|
||||
u8 uses_asan; /* Target uses ASAN/LSAN/MSAN? (bit 0/1/2 respectively) */
|
||||
|
||||
bool setenv; /* setenv() to discriminate the forkserver? */
|
||||
|
||||
bool debug; /* debug mode? */
|
||||
|
||||
u8 san_but_not_instrumented; /* Is it sanitizer enabled but not instrumented?
|
||||
@ -242,7 +240,6 @@ typedef enum fsrv_run_result {
|
||||
|
||||
void afl_fsrv_init(afl_forkserver_t *fsrv);
|
||||
void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from);
|
||||
void afl_fsrv_setup_preload(afl_forkserver_t *fsrv, char *argv0);
|
||||
void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
volatile u8 *stop_soon_p, u8 debug_child_output);
|
||||
u32 afl_fsrv_get_mapsize(afl_forkserver_t *fsrv, char **argv,
|
||||
|
@ -2,6 +2,18 @@
|
||||
american fuzzy lop++ - hashing function
|
||||
---------------------------------------
|
||||
|
||||
The hash32() function is a variant of MurmurHash3, a good
|
||||
non-cryptosafe hashing function developed by Austin Appleby.
|
||||
|
||||
For simplicity, this variant does *NOT* accept buffer lengths
|
||||
that are not divisible by 8 bytes. The 32-bit version is otherwise
|
||||
similar to the original; the 64-bit one is a custom hack with
|
||||
mostly-unproven properties.
|
||||
|
||||
Austin's original code is public domain.
|
||||
|
||||
Other code written by Michal Zalewski
|
||||
|
||||
Copyright 2016 Google Inc. All rights reserved.
|
||||
Copyright 2019-2024 AFLplusplus Project. All rights reserved.
|
||||
|
||||
@ -21,5 +33,82 @@
|
||||
u32 hash32(u8 *key, u32 len, u32 seed);
|
||||
u64 hash64(u8 *key, u32 len, u64 seed);
|
||||
|
||||
#if 0
|
||||
|
||||
The following code is disabled because xxh3 is 30% faster
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
#define ROL64(_x, _r) ((((u64)(_x)) << (_r)) | (((u64)(_x)) >> (64 - (_r))))
|
||||
|
||||
static inline u32 hash32(u8 *key, u32 len, u32 seed) {
|
||||
|
||||
const u64 *data = (u64 *)key;
|
||||
u64 h1 = seed ^ len;
|
||||
|
||||
len >>= 3;
|
||||
|
||||
while (len--) {
|
||||
|
||||
u64 k1 = *data++;
|
||||
|
||||
k1 *= 0x87c37b91114253d5ULL;
|
||||
k1 = ROL64(k1, 31);
|
||||
k1 *= 0x4cf5ad432745937fULL;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = ROL64(h1, 27);
|
||||
h1 = h1 * 5 + 0x52dce729;
|
||||
|
||||
}
|
||||
|
||||
h1 ^= h1 >> 33;
|
||||
h1 *= 0xff51afd7ed558ccdULL;
|
||||
h1 ^= h1 >> 33;
|
||||
h1 *= 0xc4ceb9fe1a85ec53ULL;
|
||||
h1 ^= h1 >> 33;
|
||||
|
||||
return h1;
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define ROL32(_x, _r) ((((u32)(_x)) << (_r)) | (((u32)(_x)) >> (32 - (_r))))
|
||||
|
||||
static inline u32 hash32(const void *key, u32 len, u32 seed) {
|
||||
|
||||
const u32 *data = (u32 *)key;
|
||||
u32 h1 = seed ^ len;
|
||||
|
||||
len >>= 2;
|
||||
|
||||
while (len--) {
|
||||
|
||||
u32 k1 = *data++;
|
||||
|
||||
k1 *= 0xcc9e2d51;
|
||||
k1 = ROL32(k1, 15);
|
||||
k1 *= 0x1b873593;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = ROL32(h1, 13);
|
||||
h1 = h1 * 5 + 0xe6546b64;
|
||||
|
||||
}
|
||||
|
||||
h1 ^= h1 >> 16;
|
||||
h1 *= 0x85ebca6b;
|
||||
h1 ^= h1 >> 13;
|
||||
h1 *= 0xc2b2ae35;
|
||||
h1 ^= h1 >> 16;
|
||||
|
||||
return h1;
|
||||
|
||||
}
|
||||
|
||||
#endif /* ^__x86_64__ */
|
||||
#endif
|
||||
|
||||
#endif /* !_HAVE_HASH_H */
|
||||
|
||||
|
@ -327,13 +327,13 @@ class ModuleSanitizerCoverageLTOLegacyPass : public ModulePass {
|
||||
|
||||
};
|
||||
|
||||
if (!getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
if (!getenv("AFL_SAN_NO_INST")) {
|
||||
|
||||
return ModuleSancov.instrumentModule(M, DTCallback, PDTCallback);
|
||||
|
||||
} else {
|
||||
|
||||
if (getenv("AFL_DEBUG")) { DEBUGF("Instrumentation disabled\n"); }
|
||||
if (getenv("AFL_DEBUG")) { DEBUGF("Instrument disabled\n"); }
|
||||
return false;
|
||||
|
||||
}
|
||||
@ -389,14 +389,14 @@ PreservedAnalyses ModuleSanitizerCoverageLTO::run(Module &M,
|
||||
|
||||
};
|
||||
|
||||
if (!getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
if (!getenv("AFL_SAN_NO_INST")) {
|
||||
|
||||
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
|
||||
return PreservedAnalyses::none();
|
||||
|
||||
} else {
|
||||
|
||||
if (debug) { DEBUGF("Instrumentation disabled\n"); }
|
||||
if (debug) { DEBUGF("Instrument disabled\n"); }
|
||||
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
// #include "llvm/IR/Verifier.h"
|
||||
#if LLVM_VERSION_MAJOR >= 15
|
||||
#if LLVM_VERSION_MAJOR < 17
|
||||
#include "llvm/ADT/Triple.h"
|
||||
@ -77,9 +76,9 @@
|
||||
#else
|
||||
#include "llvm/Transforms/Utils/Instrumentation.h"
|
||||
#endif
|
||||
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Transforms/Utils/ModuleUtils.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
@ -207,8 +206,7 @@ class ModuleSanitizerCoverageAFL
|
||||
|
||||
SanitizerCoverageOptions Options;
|
||||
|
||||
uint32_t instr = 0, selects = 0, hidden = 0, unhandled = 0, skippedbb = 0,
|
||||
dump_cc = 0;
|
||||
uint32_t instr = 0, selects = 0, unhandled = 0, dump_cc = 0;
|
||||
GlobalVariable *AFLMapPtr = NULL;
|
||||
ConstantInt *One = NULL;
|
||||
ConstantInt *Zero = NULL;
|
||||
@ -228,28 +226,20 @@ llvmGetPassPluginInfo() {
|
||||
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
|
||||
#endif
|
||||
#if LLVM_VERSION_MAJOR >= 16
|
||||
PB.registerOptimizerEarlyEPCallback([](ModulePassManager &MPM,
|
||||
OptimizationLevel OL
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
,
|
||||
ThinOrFullLTOPhase Phase
|
||||
PB.registerPipelineStartEPCallback(
|
||||
#else
|
||||
PB.registerOptimizerEarlyEPCallback(
|
||||
#endif
|
||||
) {
|
||||
|
||||
MPM.addPass(ModuleSanitizerCoverageAFL());
|
||||
|
||||
});
|
||||
|
||||
#else
|
||||
PB.registerOptimizerLastEPCallback(
|
||||
#endif
|
||||
[](ModulePassManager &MPM, OptimizationLevel OL) {
|
||||
|
||||
MPM.addPass(ModuleSanitizerCoverageAFL());
|
||||
|
||||
});
|
||||
|
||||
#endif
|
||||
|
||||
}};
|
||||
|
||||
}
|
||||
@ -274,14 +264,14 @@ PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M,
|
||||
// TODO: Support LTO or llvm classic?
|
||||
// Note we still need afl-compiler-rt so we just disable the instrumentation
|
||||
// here.
|
||||
if (!getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
if (!getenv("AFL_SAN_NO_INST")) {
|
||||
|
||||
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
|
||||
return PreservedAnalyses::none();
|
||||
|
||||
} else {
|
||||
|
||||
if (getenv("AFL_DEBUG")) { DEBUGF("Instrumentation disabled\n"); }
|
||||
if (getenv("AFL_DEBUG")) { DEBUGF("Instrument disabled\n"); }
|
||||
|
||||
}
|
||||
|
||||
@ -507,16 +497,9 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
|
||||
getenv("AFL_USE_TSAN") ? ", TSAN" : "",
|
||||
getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
|
||||
getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
|
||||
char buf[32] = "";
|
||||
if (skippedbb) {
|
||||
|
||||
snprintf(buf, sizeof(buf), " %u instrumentations saved.", skippedbb);
|
||||
|
||||
}
|
||||
|
||||
OKF("Instrumented %u locations with no collisions (%s mode) of which are "
|
||||
"%u handled and %u unhandled special instructions.%s",
|
||||
instr, modeline, selects + hidden, unhandled, buf);
|
||||
"%u handled and %u unhandled selects.",
|
||||
instr, modeline, selects, unhandled);
|
||||
|
||||
}
|
||||
|
||||
@ -790,14 +773,11 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
|
||||
if (AllBlocks.empty()) return false;
|
||||
|
||||
uint32_t cnt_cov = 0, cnt_sel = 0, cnt_sel_inc = 0, cnt_hidden_sel = 0,
|
||||
cnt_hidden_sel_inc = 0, skip_blocks = 0;
|
||||
uint32_t cnt_cov = 0, cnt_sel = 0, cnt_sel_inc = 0;
|
||||
static uint32_t first = 1;
|
||||
|
||||
for (auto &BB : F) {
|
||||
|
||||
bool block_is_instrumented = false;
|
||||
|
||||
for (auto &IN : BB) {
|
||||
|
||||
CallInst *callInst = nullptr;
|
||||
@ -811,11 +791,11 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
if (!FuncName.compare(StringRef("dlopen")) ||
|
||||
!FuncName.compare(StringRef("_dlopen"))) {
|
||||
|
||||
WARNF(
|
||||
"dlopen() detected. To have coverage for a library that your "
|
||||
"target dlopen()'s this must either happen before __AFL_INIT() "
|
||||
"or you must use AFL_PRELOAD to preload all dlopen()'ed "
|
||||
"libraries!\n");
|
||||
fprintf(stderr,
|
||||
"WARNING: dlopen() detected. To have coverage for a library "
|
||||
"that your target dlopen()'s this must either happen before "
|
||||
"__AFL_INIT() or you must use AFL_PRELOAD to preload all "
|
||||
"dlopen()'ed libraries!\n");
|
||||
continue;
|
||||
|
||||
}
|
||||
@ -823,183 +803,53 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
if (!FuncName.compare(StringRef("__afl_coverage_interesting"))) {
|
||||
|
||||
cnt_cov++;
|
||||
block_is_instrumented = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool instrumentInst = false;
|
||||
ICmpInst *icmp;
|
||||
FCmpInst *fcmp;
|
||||
SelectInst *selectInst = nullptr;
|
||||
|
||||
if ((icmp = dyn_cast<ICmpInst>(&IN)) ||
|
||||
(fcmp = dyn_cast<FCmpInst>(&IN)) || isa<SelectInst>(&IN)) {
|
||||
if ((selectInst = dyn_cast<SelectInst>(&IN))) {
|
||||
|
||||
// || isa<PHINode>(&IN)
|
||||
Value *c = selectInst->getCondition();
|
||||
auto t = c->getType();
|
||||
if (t->getTypeID() == llvm::Type::IntegerTyID) {
|
||||
|
||||
bool usedInBranch = false, usedInSelectDecision = false;
|
||||
cnt_sel++;
|
||||
cnt_sel_inc += 2;
|
||||
|
||||
for (auto *U : IN.users()) {
|
||||
}
|
||||
|
||||
if (isa<BranchInst>(U)) {
|
||||
else if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
|
||||
|
||||
usedInBranch = true;
|
||||
break;
|
||||
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
|
||||
if (tt) {
|
||||
|
||||
}
|
||||
|
||||
if (auto *sel = dyn_cast<SelectInst>(U)) {
|
||||
|
||||
if (icmp && sel->getCondition() == icmp) {
|
||||
|
||||
usedInSelectDecision = true;
|
||||
|
||||
} else if (fcmp && sel->getCondition() == fcmp) {
|
||||
|
||||
usedInSelectDecision = true;
|
||||
|
||||
}
|
||||
cnt_sel++;
|
||||
cnt_sel_inc += (tt->getElementCount().getKnownMinValue() * 2);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!usedInBranch && !usedInSelectDecision) {
|
||||
|
||||
// errs() << "Instrument! " << *(&IN) << "\n";
|
||||
instrumentInst = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (instrumentInst) {
|
||||
|
||||
block_is_instrumented = true;
|
||||
SelectInst *selectInst;
|
||||
ICmpInst *icmp;
|
||||
FCmpInst *fcmp;
|
||||
// PHINode *phiInst;
|
||||
// errs() << "IN: " << *(&IN) << "\n";
|
||||
|
||||
/* if ((phiInst = dyn_cast<PHINode>(&IN))) {
|
||||
|
||||
cnt_hidden_sel++;
|
||||
cnt_hidden_sel_inc += phiInst->getNumIncomingValues();
|
||||
|
||||
} else*/
|
||||
|
||||
if ((icmp = dyn_cast<ICmpInst>(&IN))) {
|
||||
|
||||
if (icmp->getType()->isIntegerTy(1)) {
|
||||
|
||||
cnt_sel++;
|
||||
cnt_sel_inc += 2;
|
||||
|
||||
} else {
|
||||
|
||||
unhandled++;
|
||||
|
||||
}
|
||||
|
||||
} else if ((fcmp = dyn_cast<FCmpInst>(&IN))) {
|
||||
|
||||
if (fcmp->getType()->isIntegerTy(1)) {
|
||||
|
||||
cnt_sel++;
|
||||
cnt_sel_inc += 2;
|
||||
|
||||
} else {
|
||||
|
||||
unhandled++;
|
||||
|
||||
}
|
||||
|
||||
} else if ((selectInst = dyn_cast<SelectInst>(&IN))) {
|
||||
|
||||
Value *c = selectInst->getCondition();
|
||||
auto t = c->getType();
|
||||
if (t->getTypeID() == llvm::Type::IntegerTyID) {
|
||||
|
||||
cnt_sel++;
|
||||
cnt_sel_inc += 2;
|
||||
|
||||
} else if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
|
||||
|
||||
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
|
||||
if (tt) {
|
||||
|
||||
cnt_sel++;
|
||||
cnt_sel_inc += (tt->getElementCount().getKnownMinValue() * 2);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (!be_quiet) {
|
||||
|
||||
WARNF("unknown select ID type: %u\n", t->getTypeID());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} /*else {
|
||||
|
||||
cnt_hidden_sel++;
|
||||
cnt_hidden_sel_inc += 2;
|
||||
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (block_is_instrumented && &BB != &BB.getParent()->getEntryBlock() &&
|
||||
llvm::is_contained(AllBlocks, &BB)) {
|
||||
|
||||
Instruction *instr = &*BB.begin();
|
||||
LLVMContext &Ctx = BB.getContext();
|
||||
MDNode *md = MDNode::get(Ctx, MDString::get(Ctx, "skipinstrument"));
|
||||
instr->setMetadata("tag", md);
|
||||
skip_blocks++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint32_t xtra = 0;
|
||||
if (skip_blocks < first + cnt_cov + cnt_sel_inc + cnt_hidden_sel_inc) {
|
||||
|
||||
xtra = first + cnt_cov + cnt_sel_inc + cnt_hidden_sel_inc - skip_blocks;
|
||||
|
||||
}
|
||||
|
||||
CreateFunctionLocalArrays(F, AllBlocks, xtra);
|
||||
|
||||
if (!FunctionGuardArray) {
|
||||
|
||||
WARNF(
|
||||
"SANCOV: FunctionGuardArray is NULL, failed to emit instrumentation.");
|
||||
return false;
|
||||
|
||||
}
|
||||
CreateFunctionLocalArrays(F, AllBlocks, first + cnt_cov + cnt_sel_inc);
|
||||
|
||||
if (first) { first = 0; }
|
||||
selects += cnt_sel;
|
||||
hidden += cnt_hidden_sel;
|
||||
|
||||
uint32_t special = 0, local_selects = 0, skip_select = 0, skip_icmp = 0;
|
||||
// uint32_t skip_phi = 0;
|
||||
uint32_t special = 0, local_selects = 0, skip_next = 0;
|
||||
|
||||
for (auto &BB : F) {
|
||||
|
||||
// errs() << *(&BB) << "\n";
|
||||
|
||||
for (auto &IN : BB) {
|
||||
|
||||
// errs() << *(&IN) << "\n";
|
||||
CallInst *callInst = nullptr;
|
||||
|
||||
if ((callInst = dyn_cast<CallInst>(&IN))) {
|
||||
@ -1017,6 +867,15 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
IRBuilder<> IRB(callInst);
|
||||
#endif
|
||||
|
||||
if (!FunctionGuardArray) {
|
||||
|
||||
fprintf(stderr,
|
||||
"SANCOV: FunctionGuardArray is NULL, failed to emit "
|
||||
"instrumentation.");
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
Value *GuardPtr = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
@ -1030,324 +889,132 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
|
||||
}
|
||||
|
||||
bool instrumentInst = false;
|
||||
ICmpInst *icmp;
|
||||
FCmpInst *fcmp;
|
||||
SelectInst *selectInst = nullptr;
|
||||
|
||||
if ((icmp = dyn_cast<ICmpInst>(&IN)) ||
|
||||
(fcmp = dyn_cast<FCmpInst>(&IN)) || isa<SelectInst>(&IN)) {
|
||||
if (!skip_next && (selectInst = dyn_cast<SelectInst>(&IN))) {
|
||||
|
||||
// || isa<PHINode>(&IN)
|
||||
|
||||
bool usedInBranch = false, usedInSelectDecision = false;
|
||||
|
||||
for (auto *U : IN.users()) {
|
||||
|
||||
if (isa<BranchInst>(U)) {
|
||||
|
||||
usedInBranch = true;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (auto *sel = dyn_cast<SelectInst>(U)) {
|
||||
|
||||
if (icmp && sel->getCondition() == icmp) {
|
||||
|
||||
usedInSelectDecision = true;
|
||||
break;
|
||||
|
||||
} else if (fcmp && sel->getCondition() == fcmp) {
|
||||
|
||||
usedInSelectDecision = true;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!usedInBranch && !usedInSelectDecision) {
|
||||
|
||||
// errs() << "Instrument! " << *(&IN) << "\n";
|
||||
instrumentInst = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (instrumentInst) {
|
||||
|
||||
Value *result = nullptr;
|
||||
uint32_t vector_cnt = 0;
|
||||
SelectInst *selectInst;
|
||||
// PHINode *phi = nullptr, *newPhi = nullptr;
|
||||
IRBuilder<> IRB(IN.getNextNode());
|
||||
Value *condition = selectInst->getCondition();
|
||||
Value *result;
|
||||
auto t = condition->getType();
|
||||
IRBuilder<> IRB(selectInst->getNextNode());
|
||||
|
||||
if ((icmp = dyn_cast<ICmpInst>(&IN))) {
|
||||
if (t->getTypeID() == llvm::Type::IntegerTyID) {
|
||||
|
||||
if (!icmp->getType()->isIntegerTy(1)) { continue; }
|
||||
if (!FunctionGuardArray) {
|
||||
|
||||
if (skip_icmp) {
|
||||
|
||||
skip_icmp--;
|
||||
fprintf(stderr,
|
||||
"SANCOV: FunctionGuardArray is NULL, failed to emit "
|
||||
"instrumentation.");
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
|
||||
if (DILocation *Loc = IN.getDebugLoc()) {
|
||||
|
||||
llvm::errs() << "DEBUG " << Loc->getFilename() << ":"
|
||||
<< Loc->getLine() << ":";
|
||||
std::string path =
|
||||
Loc->getDirectory().str() + "/" + Loc->getFilename().str();
|
||||
std::ifstream sourceFile(path);
|
||||
std::string lineContent;
|
||||
for (unsigned line = 1; line <= Loc->getLine(); ++line)
|
||||
std::getline(sourceFile, lineContent);
|
||||
llvm::errs() << lineContent << "\n";
|
||||
|
||||
}
|
||||
|
||||
errs() << *(&IN) << "\n";
|
||||
|
||||
}
|
||||
|
||||
auto res = icmp;
|
||||
auto GuardPtr1 = IRB.CreateInBoundsGEP(
|
||||
FunctionGuardArray->getValueType(), FunctionGuardArray,
|
||||
{IRB.getInt64(0),
|
||||
IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))});
|
||||
|
||||
auto GuardPtr2 = IRB.CreateInBoundsGEP(
|
||||
FunctionGuardArray->getValueType(), FunctionGuardArray,
|
||||
{IRB.getInt64(0),
|
||||
IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))});
|
||||
|
||||
result = IRB.CreateSelect(res, GuardPtr1, GuardPtr2);
|
||||
skip_select = 1;
|
||||
// fprintf(stderr, "Icmp!\n");
|
||||
|
||||
} else if ((fcmp = dyn_cast<FCmpInst>(&IN))) {
|
||||
|
||||
if (!fcmp->getType()->isIntegerTy(1)) { continue; }
|
||||
|
||||
if (debug) {
|
||||
|
||||
if (DILocation *Loc = IN.getDebugLoc()) {
|
||||
|
||||
llvm::errs() << "DEBUG " << Loc->getFilename() << ":"
|
||||
<< Loc->getLine() << ":";
|
||||
std::string path =
|
||||
Loc->getDirectory().str() + "/" + Loc->getFilename().str();
|
||||
std::ifstream sourceFile(path);
|
||||
std::string lineContent;
|
||||
for (unsigned line = 1; line <= Loc->getLine(); ++line)
|
||||
std::getline(sourceFile, lineContent);
|
||||
llvm::errs() << lineContent << "\n";
|
||||
|
||||
}
|
||||
|
||||
errs() << *(&IN) << "\n";
|
||||
|
||||
}
|
||||
|
||||
auto res = fcmp;
|
||||
auto GuardPtr1 = IRB.CreateInBoundsGEP(
|
||||
FunctionGuardArray->getValueType(), FunctionGuardArray,
|
||||
{IRB.getInt64(0),
|
||||
IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))});
|
||||
|
||||
auto GuardPtr2 = IRB.CreateInBoundsGEP(
|
||||
FunctionGuardArray->getValueType(), FunctionGuardArray,
|
||||
{IRB.getInt64(0),
|
||||
IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))});
|
||||
|
||||
result = IRB.CreateSelect(res, GuardPtr1, GuardPtr2);
|
||||
skip_select = 1;
|
||||
// fprintf(stderr, "Fcmp!\n");
|
||||
|
||||
/*} else if ((phi = dyn_cast<PHINode>(&IN))) {
|
||||
|
||||
if (skip_phi) {
|
||||
|
||||
skip_phi = 0;
|
||||
// errs() << "SKIP: " << *(&IN) << "\n";
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
// errs() << "-->PHI: " << *(&IN) << "\n";
|
||||
// continue;
|
||||
Instruction *insertBefore =
|
||||
&*phi->getParent()->getFirstInsertionPt(); newPhi =
|
||||
PHINode::Create(Int32PtrTy, 0, "", insertBefore); BasicBlock
|
||||
*phiBlock = phi->getParent();
|
||||
|
||||
for (BasicBlock *pred : predecessors(phiBlock)) {
|
||||
|
||||
IRBuilder<> predBuilder(pred->getTerminator());
|
||||
|
||||
Value *ptr = predBuilder.CreateInBoundsGEP(
|
||||
FunctionGuardArray->getValueType(), FunctionGuardArray,
|
||||
auto GuardPtr1 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy, (cnt_cov + local_selects++ +
|
||||
AllBlocks.size()))); newPhi->addIncoming(ptr, pred);
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
|
||||
Int32PtrTy);
|
||||
|
||||
}
|
||||
auto GuardPtr2 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
|
||||
Int32PtrTy);
|
||||
|
||||
result = newPhi;
|
||||
skip_phi = 1;
|
||||
// fprintf(stderr, "Phi!\n");
|
||||
*/
|
||||
result = IRB.CreateSelect(condition, GuardPtr1, GuardPtr2);
|
||||
|
||||
} else if ((selectInst = dyn_cast<SelectInst>(&IN))) {
|
||||
|
||||
if (skip_select) {
|
||||
|
||||
skip_select = 0;
|
||||
continue;
|
||||
|
||||
} else {
|
||||
|
||||
// fprintf(stderr, "Select!\n");
|
||||
|
||||
}
|
||||
|
||||
Value *condition = selectInst->getCondition();
|
||||
auto t = condition->getType();
|
||||
|
||||
if (t->getTypeID() == llvm::Type::IntegerTyID) {
|
||||
|
||||
auto GuardPtr1 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
|
||||
Int32PtrTy);
|
||||
|
||||
auto GuardPtr2 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
|
||||
Int32PtrTy);
|
||||
|
||||
result = IRB.CreateSelect(condition, GuardPtr1, GuardPtr2);
|
||||
skip_select = 1;
|
||||
|
||||
} else
|
||||
} else
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
|
||||
if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
|
||||
|
||||
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
|
||||
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
|
||||
if (tt) {
|
||||
|
||||
if (tt) {
|
||||
uint32_t elements = tt->getElementCount().getFixedValue();
|
||||
vector_cnt = elements;
|
||||
if (elements) {
|
||||
|
||||
uint32_t elements = tt->getElementCount().getFixedValue();
|
||||
vector_cnt = elements;
|
||||
if (elements) {
|
||||
FixedVectorType *GuardPtr1 =
|
||||
FixedVectorType::get(Int32PtrTy, elements);
|
||||
FixedVectorType *GuardPtr2 =
|
||||
FixedVectorType::get(Int32PtrTy, elements);
|
||||
Value *x, *y;
|
||||
|
||||
FixedVectorType *GuardPtr1 =
|
||||
FixedVectorType::get(Int32PtrTy, elements);
|
||||
FixedVectorType *GuardPtr2 =
|
||||
FixedVectorType::get(Int32PtrTy, elements);
|
||||
Value *x, *y;
|
||||
if (!FunctionGuardArray) {
|
||||
|
||||
Value *val1 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(IntptrTy, (cnt_cov + local_selects++ +
|
||||
AllBlocks.size()) *
|
||||
4)),
|
||||
Int32PtrTy);
|
||||
x = IRB.CreateInsertElement(GuardPtr1, val1, (uint64_t)0);
|
||||
|
||||
Value *val2 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(IntptrTy, (cnt_cov + local_selects++ +
|
||||
AllBlocks.size()) *
|
||||
4)),
|
||||
Int32PtrTy);
|
||||
y = IRB.CreateInsertElement(GuardPtr2, val2, (uint64_t)0);
|
||||
|
||||
for (uint64_t i = 1; i < elements; i++) {
|
||||
|
||||
val1 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) *
|
||||
4)),
|
||||
Int32PtrTy);
|
||||
x = IRB.CreateInsertElement(x, val1, i);
|
||||
|
||||
val2 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) *
|
||||
4)),
|
||||
Int32PtrTy);
|
||||
y = IRB.CreateInsertElement(y, val2, i);
|
||||
|
||||
}
|
||||
|
||||
result = IRB.CreateSelect(condition, x, y);
|
||||
skip_select = 1;
|
||||
fprintf(stderr,
|
||||
"SANCOV: FunctionGuardArray is NULL, failed to emit "
|
||||
"instrumentation.");
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Value *val1 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
|
||||
Int32PtrTy);
|
||||
x = IRB.CreateInsertElement(GuardPtr1, val1, (uint64_t)0);
|
||||
|
||||
} else
|
||||
Value *val2 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
|
||||
Int32PtrTy);
|
||||
y = IRB.CreateInsertElement(GuardPtr2, val2, (uint64_t)0);
|
||||
|
||||
#endif
|
||||
{
|
||||
for (uint64_t i = 1; i < elements; i++) {
|
||||
|
||||
if (!be_quiet) {
|
||||
val1 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(IntptrTy, (cnt_cov + local_selects++ +
|
||||
AllBlocks.size()) *
|
||||
4)),
|
||||
Int32PtrTy);
|
||||
x = IRB.CreateInsertElement(x, val1, i);
|
||||
|
||||
WARNF("Warning: Unhandled ID type: %u\n", t->getTypeID());
|
||||
val2 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(IntptrTy, (cnt_cov + local_selects++ +
|
||||
AllBlocks.size()) *
|
||||
4)),
|
||||
Int32PtrTy);
|
||||
y = IRB.CreateInsertElement(y, val2, i);
|
||||
|
||||
}
|
||||
|
||||
result = IRB.CreateSelect(condition, x, y);
|
||||
|
||||
}
|
||||
|
||||
unhandled++;
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
} else
|
||||
|
||||
#endif
|
||||
{
|
||||
|
||||
// fprintf(stderr, "UNHANDLED: %u\n", t->getTypeID());
|
||||
unhandled++;
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
uint32_t vector_cur = 0;
|
||||
|
||||
/* Load SHM pointer */
|
||||
/*
|
||||
if (newPhi) {
|
||||
|
||||
auto *inst = dyn_cast<Instruction>(result);
|
||||
PHINode *nphi;
|
||||
|
||||
while ((nphi = dyn_cast<PHINode>(inst))) {
|
||||
|
||||
// fprintf(stderr, "NEXT!\n");
|
||||
inst = inst->getNextNode();
|
||||
|
||||
}
|
||||
|
||||
IRB.SetInsertPoint(inst);
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
LoadInst *MapPtr =
|
||||
IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr);
|
||||
@ -1398,7 +1065,6 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
auto cf = IRB.CreateICmpEQ(Incr, Zero);
|
||||
auto carry = IRB.CreateZExt(cf, Int8Ty);
|
||||
Incr = IRB.CreateAdd(Incr, carry);
|
||||
skip_icmp++;
|
||||
|
||||
}
|
||||
|
||||
@ -1420,8 +1086,13 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
|
||||
}
|
||||
|
||||
skip_next = 1;
|
||||
instr += vector_cnt;
|
||||
|
||||
} else {
|
||||
|
||||
skip_next = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -1430,40 +1101,9 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
|
||||
if (AllBlocks.empty() && !special && !local_selects) return false;
|
||||
|
||||
uint32_t skipped = 0;
|
||||
|
||||
if (!AllBlocks.empty()) {
|
||||
|
||||
for (size_t i = 0, N = AllBlocks.size(); i < N; i++) {
|
||||
|
||||
auto instr = AllBlocks[i]->begin();
|
||||
if (instr->getMetadata("skipinstrument")) {
|
||||
|
||||
skipped++;
|
||||
// fprintf(stderr, "Skipped!\n");
|
||||
|
||||
} else {
|
||||
|
||||
InjectCoverageAtBlock(F, *AllBlocks[i], i - skipped, IsLeafFunc);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
skippedbb += skipped;
|
||||
|
||||
/*
|
||||
if (verifyFunction(F, &errs())) {
|
||||
|
||||
errs() << "Broken function after instrumentation\n";
|
||||
F.print(errs(), nullptr);
|
||||
report_fatal_error("Invalid IR");
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
if (!AllBlocks.empty())
|
||||
for (size_t i = 0, N = AllBlocks.size(); i < N; i++)
|
||||
InjectCoverageAtBlock(F, *AllBlocks[i], i, IsLeafFunc);
|
||||
|
||||
return true;
|
||||
|
||||
|
@ -119,8 +119,6 @@ u64 __afl_map_addr;
|
||||
u32 __afl_first_final_loc;
|
||||
u32 __afl_old_forkserver;
|
||||
|
||||
u8 __afl_forkserver_setenv = 0;
|
||||
|
||||
#ifdef __AFL_CODE_COVERAGE
|
||||
typedef struct afl_module_info_t afl_module_info_t;
|
||||
|
||||
@ -294,25 +292,6 @@ static void __afl_map_shm_fuzz() {
|
||||
u8 *map = NULL;
|
||||
|
||||
#ifdef USEMMAP
|
||||
|
||||
// Newer afl-fuzz versions will set a shm_fuzz page size env, else fall back
|
||||
size_t shm_fuzz_map_size = SHM_FUZZ_MAP_SIZE_DEFAULT;
|
||||
char *map_size_env = getenv(SHM_FUZZ_MAP_SIZE_ENV_VAR);
|
||||
if (map_size_env != NULL) {
|
||||
|
||||
char *endptr;
|
||||
errno = 0;
|
||||
shm_fuzz_map_size = (size_t)strtoul(map_size_env, &endptr, 10);
|
||||
if (errno != 0 || shm_fuzz_map_size == 0) {
|
||||
|
||||
perror("shm_fuzz mapping size parsing");
|
||||
send_forkserver_error(FS_ERROR_SHM_OPEN);
|
||||
_exit(1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const char *shm_file_path = id_str;
|
||||
int shm_fd = -1;
|
||||
|
||||
@ -326,7 +305,8 @@ static void __afl_map_shm_fuzz() {
|
||||
|
||||
}
|
||||
|
||||
map = (u8 *)mmap(0, shm_fuzz_map_size, PROT_READ, MAP_SHARED, shm_fd, 0);
|
||||
map =
|
||||
(u8 *)mmap(0, MAX_FILE + sizeof(u32), PROT_READ, MAP_SHARED, shm_fd, 0);
|
||||
|
||||
#else
|
||||
u32 shm_id = atoi(id_str);
|
||||
@ -382,7 +362,6 @@ static void __afl_map_shm(void) {
|
||||
if (getenv("AFL_DUMP_MAP_SIZE")) {
|
||||
|
||||
printf("%u\n", __afl_map_size);
|
||||
fflush(stdout);
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
@ -909,20 +888,14 @@ static void __afl_start_forkserver(void) {
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT") != NULL) {
|
||||
|
||||
__afl_forkserver_setenv = 1;
|
||||
|
||||
}
|
||||
|
||||
/* Phone home and tell the parent that we're OK. If parent isn't there,
|
||||
assume we're not running in forkserver mode and just execute program. */
|
||||
|
||||
// return because possible non-forkserver usage
|
||||
if (write(FORKSRV_FD + 1, msg, 4) != 4) { return; }
|
||||
|
||||
if (!__afl_old_forkserver) {
|
||||
|
||||
// return because possible non-forkserver usage
|
||||
if (write(FORKSRV_FD + 1, msg, 4) != 4) { return; }
|
||||
|
||||
if (read(FORKSRV_FD, reply, 4) != 4) { _exit(1); }
|
||||
if (tmp != status2) {
|
||||
|
||||
@ -940,12 +913,7 @@ static void __afl_start_forkserver(void) {
|
||||
|
||||
}
|
||||
|
||||
if (write(FORKSRV_FD + 1, msg, 4) != 4) {
|
||||
|
||||
errno = 0;
|
||||
_exit(1);
|
||||
|
||||
}
|
||||
if (write(FORKSRV_FD + 1, msg, 4) != 4) { _exit(1); }
|
||||
|
||||
// Now send the parameters for the set options, increasing by option number
|
||||
|
||||
@ -1086,13 +1054,6 @@ static void __afl_start_forkserver(void) {
|
||||
|
||||
close(FORKSRV_FD);
|
||||
close(FORKSRV_FD + 1);
|
||||
|
||||
if (unlikely(__afl_forkserver_setenv)) {
|
||||
|
||||
unsetenv("AFL_FORKSERVER_PARENT");
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
@ -1265,15 +1226,6 @@ void __afl_manual_init(void) {
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_LLVM_ONLY_FSRV") || getenv("AFL_GCC_ONLY_FRSV")) {
|
||||
|
||||
fprintf(stderr,
|
||||
"DEBUG: Overwrite area_ptr to dummy due to "
|
||||
"AFL_LLVM_ONLY_FSRV/AFL_GCC_ONLY_FRSV\n");
|
||||
__afl_area_ptr = __afl_area_ptr_dummy;
|
||||
|
||||
}
|
||||
|
||||
if (!init_done) {
|
||||
|
||||
__afl_start_forkserver();
|
||||
|
@ -462,7 +462,6 @@ static struct plugin_info afl_plugin = {
|
||||
.help = G_("AFL gcc plugin\n\
|
||||
\n\
|
||||
Set AFL_QUIET in the environment to silence it.\n\
|
||||
Set AFL_GCC_ONLY_FRSV in the environment to disable instrumentation.\n\
|
||||
\n\
|
||||
Set AFL_INST_RATIO in the environment to a number from 0 to 100\n\
|
||||
to control how likely a block will be chosen for instrumentation.\n\
|
||||
@ -503,10 +502,9 @@ int plugin_init(struct plugin_name_args *info,
|
||||
case it was specified in the command line's -frandom-seed for
|
||||
reproducible instrumentation. */
|
||||
srandom(get_random_seed(false));
|
||||
bool fsrv_only = !!getenv("AFL_GCC_ONLY_FRSV");
|
||||
|
||||
const char *name = info->base_name;
|
||||
if (!fsrv_only) { register_callback(name, PLUGIN_INFO, NULL, &afl_plugin); }
|
||||
register_callback(name, PLUGIN_INFO, NULL, &afl_plugin);
|
||||
|
||||
afl_pass *aflp = new afl_pass(quiet, inst_ratio);
|
||||
struct register_pass_info pass_info = {
|
||||
@ -518,20 +516,14 @@ int plugin_init(struct plugin_name_args *info,
|
||||
|
||||
};
|
||||
|
||||
if (!fsrv_only) {
|
||||
|
||||
register_callback(name, PLUGIN_PASS_MANAGER_SETUP, NULL, &pass_info);
|
||||
register_callback(name, PLUGIN_FINISH, afl_pass::plugin_finalize,
|
||||
pass_info.pass);
|
||||
|
||||
}
|
||||
register_callback(name, PLUGIN_PASS_MANAGER_SETUP, NULL, &pass_info);
|
||||
register_callback(name, PLUGIN_FINISH, afl_pass::plugin_finalize,
|
||||
pass_info.pass);
|
||||
|
||||
if (!quiet)
|
||||
ACTF(G_("%s instrumentation at ratio of %u%% in %s mode."),
|
||||
aflp->out_of_line ? G_("Call-based") : G_("Inline"), inst_ratio,
|
||||
getenv("AFL_HARDEN") ? G_("hardened") : G_("non-hardened"));
|
||||
else if (fsrv_only)
|
||||
ACTF("Instrumentation disabled due to AFL_GCC_ONLY_FRSV");
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -121,16 +121,15 @@ extern "C" LLVM_ATTRIBUTE_WEAK PassPluginLibraryInfo llvmGetPassPluginInfo() {
|
||||
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
|
||||
#endif
|
||||
#if LLVM_VERSION_MAJOR >= 16
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
PB.registerPipelineStartEPCallback(
|
||||
#else
|
||||
PB.registerOptimizerEarlyEPCallback(
|
||||
#endif
|
||||
#else
|
||||
PB.registerOptimizerLastEPCallback(
|
||||
#endif
|
||||
[](ModulePassManager &MPM, OptimizationLevel OL
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
,
|
||||
ThinOrFullLTOPhase Phase
|
||||
#endif
|
||||
) {
|
||||
[](ModulePassManager &MPM, OptimizationLevel OL) {
|
||||
|
||||
MPM.addPass(AFLCoverage());
|
||||
|
||||
@ -225,17 +224,17 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
if (getenv("AFL_DEBUG")) debug = 1;
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
if (getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
if (getenv("AFL_SAN_NO_INST")) {
|
||||
|
||||
if (debug) { fprintf(stderr, "Instrumentation disabled\n"); }
|
||||
if (debug) { fprintf(stderr, "Instrument disabled\n"); }
|
||||
return PreservedAnalyses::all();
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
if (getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
if (getenv("AFL_SAN_NO_INST")) {
|
||||
|
||||
if (debug) { fprintf(stderr, "Instrumentation disabled\n"); }
|
||||
if (debug) { fprintf(stderr, "Instrument disabled\n"); }
|
||||
return true;
|
||||
|
||||
}
|
||||
|
@ -64,8 +64,6 @@ using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
using DomTreeCallback = function_ref<const DominatorTree *(Function &F)>;
|
||||
|
||||
#if LLVM_MAJOR >= 11 /* use new pass manager */
|
||||
class CmpLogInstructions : public PassInfoMixin<CmpLogInstructions> {
|
||||
|
||||
@ -94,8 +92,6 @@ class CmpLogInstructions : public ModulePass {
|
||||
#else
|
||||
bool runOnModule(Module &M) override;
|
||||
|
||||
bool IsBackEdge(BasicBlock *From, BasicBlock *To, const DominatorTree *DT);
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 4
|
||||
StringRef getPassName() const override {
|
||||
|
||||
@ -110,7 +106,7 @@ class CmpLogInstructions : public ModulePass {
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool hookInstrs(Module &M, DomTreeCallback DTCallback);
|
||||
bool hookInstrs(Module &M);
|
||||
|
||||
};
|
||||
|
||||
@ -162,16 +158,7 @@ Iterator Unique(Iterator first, Iterator last) {
|
||||
|
||||
}
|
||||
|
||||
bool IsBackEdge(BasicBlock *From, BasicBlock *To, const DominatorTree *DT) {
|
||||
|
||||
if (DT->dominates(To, From)) return true;
|
||||
if (auto Next = To->getUniqueSuccessor())
|
||||
if (DT->dominates(Next, From)) return true;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
|
||||
bool CmpLogInstructions::hookInstrs(Module &M) {
|
||||
|
||||
std::vector<Instruction *> icomps;
|
||||
LLVMContext &C = M.getContext();
|
||||
@ -309,7 +296,6 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
|
||||
for (auto &F : M) {
|
||||
|
||||
if (!isInInstrumentList(&F, MNAME)) continue;
|
||||
const DominatorTree *DT = DTCallback(F);
|
||||
|
||||
for (auto &BB : F) {
|
||||
|
||||
@ -318,12 +304,6 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
|
||||
CmpInst *selectcmpInst = nullptr;
|
||||
if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) {
|
||||
|
||||
// skip loop comparisons
|
||||
if (selectcmpInst->hasOneUse())
|
||||
if (auto BR = dyn_cast<BranchInst>(selectcmpInst->user_back()))
|
||||
for (BasicBlock *B : BR->successors())
|
||||
if (IsBackEdge(BR->getParent(), B, DT)) continue;
|
||||
|
||||
icomps.push_back(selectcmpInst);
|
||||
|
||||
}
|
||||
@ -701,19 +681,11 @@ bool CmpLogInstructions::runOnModule(Module &M) {
|
||||
|
||||
#endif
|
||||
|
||||
auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
|
||||
auto DTCallback = [&FAM](Function &F) -> const DominatorTree *{
|
||||
|
||||
return &FAM.getResult<DominatorTreeAnalysis>(F);
|
||||
|
||||
};
|
||||
|
||||
if (getenv("AFL_QUIET") == NULL)
|
||||
printf("Running cmplog-instructions-pass by andreafioraldi@gmail.com\n");
|
||||
else
|
||||
be_quiet = 1;
|
||||
|
||||
bool ret = hookInstrs(M, DTCallback);
|
||||
bool ret = hookInstrs(M);
|
||||
verifyModule(M);
|
||||
|
||||
#if LLVM_MAJOR >= 11 /* use new pass manager */
|
||||
|
@ -130,16 +130,15 @@ llvmGetPassPluginInfo() {
|
||||
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
|
||||
#endif
|
||||
#if LLVM_VERSION_MAJOR >= 16
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
PB.registerPipelineStartEPCallback(
|
||||
#else
|
||||
PB.registerOptimizerEarlyEPCallback(
|
||||
#endif
|
||||
#else
|
||||
PB.registerOptimizerLastEPCallback(
|
||||
#endif
|
||||
[](ModulePassManager &MPM, OptimizationLevel OL
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
,
|
||||
ThinOrFullLTOPhase Phase
|
||||
#endif
|
||||
) {
|
||||
[](ModulePassManager &MPM, OptimizationLevel OL) {
|
||||
|
||||
MPM.addPass(CompareTransform());
|
||||
|
||||
|
@ -190,16 +190,15 @@ llvmGetPassPluginInfo() {
|
||||
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
|
||||
#endif
|
||||
#if LLVM_VERSION_MAJOR >= 16
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
PB.registerPipelineStartEPCallback(
|
||||
#else
|
||||
PB.registerOptimizerEarlyEPCallback(
|
||||
#endif
|
||||
#else
|
||||
PB.registerOptimizerLastEPCallback(
|
||||
#endif
|
||||
[](ModulePassManager &MPM, OptimizationLevel OL
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
,
|
||||
ThinOrFullLTOPhase Phase
|
||||
#endif
|
||||
) {
|
||||
[](ModulePassManager &MPM, OptimizationLevel OL) {
|
||||
|
||||
MPM.addPass(SplitComparesTransform());
|
||||
|
||||
|
@ -138,17 +138,15 @@ llvmGetPassPluginInfo() {
|
||||
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
|
||||
#endif
|
||||
#if LLVM_VERSION_MAJOR >= 16
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
PB.registerPipelineStartEPCallback(
|
||||
#else
|
||||
PB.registerOptimizerEarlyEPCallback(
|
||||
#endif
|
||||
#else
|
||||
PB.registerOptimizerLastEPCallback(
|
||||
#endif
|
||||
[](ModulePassManager &MPM, OptimizationLevel OL
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
,
|
||||
ThinOrFullLTOPhase Phase
|
||||
#endif
|
||||
|
||||
) {
|
||||
[](ModulePassManager &MPM, OptimizationLevel OL) {
|
||||
|
||||
MPM.addPass(SplitSwitchesTransform());
|
||||
|
||||
|
1910
program_gen.py
Normal file
1910
program_gen.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -1 +1 @@
|
||||
c43dd6e036
|
||||
ef1cd9a8cb
|
||||
|
Submodule qemu_mode/qemuafl updated: c43dd6e036...ef1cd9a8cb
@ -75,6 +75,7 @@ static bool edges_only, /* Ignore hit counts? */
|
||||
static volatile u8 stop_soon; /* Ctrl-C pressed? */
|
||||
|
||||
static u8 *target_path;
|
||||
static u8 frida_mode;
|
||||
static u8 qemu_mode;
|
||||
static u8 cs_mode;
|
||||
static u32 map_size = MAP_SIZE;
|
||||
@ -627,7 +628,9 @@ static void handle_stop_sig(int sig) {
|
||||
|
||||
static void set_up_environment(char **argv) {
|
||||
|
||||
u8 *x;
|
||||
u8 *x;
|
||||
char *afl_preload;
|
||||
char *frida_afl_preload = NULL;
|
||||
|
||||
fsrv.dev_null_fd = open("/dev/null", O_RDWR);
|
||||
if (fsrv.dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
|
||||
@ -669,7 +672,57 @@ static void set_up_environment(char **argv) {
|
||||
}
|
||||
|
||||
set_sanitizer_defaults();
|
||||
afl_fsrv_setup_preload(&fsrv, argv[0]);
|
||||
|
||||
if (get_afl_env("AFL_PRELOAD")) {
|
||||
|
||||
if (qemu_mode) {
|
||||
|
||||
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
|
||||
|
||||
} else if (frida_mode) {
|
||||
|
||||
afl_preload = getenv("AFL_PRELOAD");
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
if (afl_preload) {
|
||||
|
||||
frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
|
||||
|
||||
} else {
|
||||
|
||||
frida_afl_preload = alloc_printf("%s", frida_binary);
|
||||
|
||||
}
|
||||
|
||||
ck_free(frida_binary);
|
||||
|
||||
setenv("LD_PRELOAD", frida_afl_preload, 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
|
||||
/* CoreSight mode uses the default behavior. */
|
||||
|
||||
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
} else if (frida_mode) {
|
||||
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
setenv("LD_PRELOAD", frida_binary, 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
|
||||
#endif
|
||||
ck_free(frida_binary);
|
||||
|
||||
}
|
||||
|
||||
if (frida_afl_preload) { ck_free(frida_afl_preload); }
|
||||
|
||||
}
|
||||
|
||||
@ -883,9 +936,10 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
case 'O': /* FRIDA mode */
|
||||
|
||||
if (fsrv.frida_mode) { FATAL("Multiple -O options not supported"); }
|
||||
if (frida_mode) { FATAL("Multiple -O options not supported"); }
|
||||
|
||||
fsrv.frida_mode = true;
|
||||
frida_mode = 1;
|
||||
fsrv.frida_mode = frida_mode;
|
||||
setenv("AFL_FRIDA_INST_SEED", "1", 1);
|
||||
|
||||
break;
|
||||
|
79
src/afl-cc.c
79
src/afl-cc.c
@ -244,7 +244,7 @@ static inline void insert_object(aflcc_state_t *aflcc, u8 *obj, u8 *fmt,
|
||||
/* Insert params into the new argv, make clang load the pass. */
|
||||
static inline void load_llvm_pass(aflcc_state_t *aflcc, u8 *pass) {
|
||||
|
||||
if (getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
if (getenv("AFL_SAN_NO_INST")) {
|
||||
|
||||
if (!be_quiet) { DEBUGF("SAND: Coverage instrumentation disabled\n"); }
|
||||
return;
|
||||
@ -253,11 +253,7 @@ static inline void load_llvm_pass(aflcc_state_t *aflcc, u8 *pass) {
|
||||
|
||||
#if LLVM_MAJOR >= 11 /* use new pass manager */
|
||||
#if LLVM_MAJOR < 16
|
||||
#if LLVM_MAJOR < 15
|
||||
insert_param(aflcc, "-fno-legacy-pass-manager");
|
||||
#else
|
||||
insert_param(aflcc, "-fexperimental-new-pass-manager");
|
||||
#endif
|
||||
#endif
|
||||
insert_object(aflcc, pass, "-fpass-plugin=%s", 0);
|
||||
#else
|
||||
@ -2097,7 +2093,7 @@ void add_native_pcguard(aflcc_state_t *aflcc) {
|
||||
* anyway.
|
||||
*/
|
||||
if (aflcc->have_rust_asanrt) { return; }
|
||||
if (getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
if (getenv("AFL_SAN_NO_INST")) {
|
||||
|
||||
if (!be_quiet) { DEBUGF("SAND: Coverage instrumentation disabled\n"); }
|
||||
return;
|
||||
@ -2138,7 +2134,7 @@ void add_native_pcguard(aflcc_state_t *aflcc) {
|
||||
*/
|
||||
void add_optimized_pcguard(aflcc_state_t *aflcc) {
|
||||
|
||||
if (getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
if (getenv("AFL_SAN_NO_INST")) {
|
||||
|
||||
if (!be_quiet) { DEBUGF("SAND: Coverage instrumentation disabled\n"); }
|
||||
return;
|
||||
@ -2167,11 +2163,7 @@ void add_optimized_pcguard(aflcc_state_t *aflcc) {
|
||||
|
||||
/* Since LLVM_MAJOR >= 13 we use new pass manager */
|
||||
#if LLVM_MAJOR < 16
|
||||
#if LLVM_MAJOR < 15
|
||||
insert_param(aflcc, "-fno-legacy-pass-manager");
|
||||
#else
|
||||
insert_param(aflcc, "-fexperimental-new-pass-manager");
|
||||
#endif
|
||||
#endif
|
||||
insert_object(aflcc, "SanitizerCoveragePCGUARD.so", "-fpass-plugin=%s", 0);
|
||||
|
||||
@ -2600,13 +2592,6 @@ void add_assembler(aflcc_state_t *aflcc) {
|
||||
/* Add params to launch the gcc plugins for instrumentation. */
|
||||
void add_gcc_plugin(aflcc_state_t *aflcc) {
|
||||
|
||||
if (getenv("AFL_GCC_ONLY_FSRV")) {
|
||||
|
||||
if (!be_quiet) { DEBUGF("SAND: Coverage instrumentation disabled\n"); }
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if (aflcc->cmplog_mode) {
|
||||
|
||||
insert_object(aflcc, "afl-gcc-cmplog-pass.so", "-fplugin=%s", 0);
|
||||
@ -3606,64 +3591,6 @@ int main(int argc, char **argv, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
// We only support plugins with LLVM 14 onwards
|
||||
#if LLVM_MAJOR < 14
|
||||
if (aflcc->instrument_mode != INSTRUMENT_LLVMNATIVE &&
|
||||
aflcc->compiler_mode != GCC_PLUGIN) {
|
||||
|
||||
aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
|
||||
aflcc->compiler_mode = LLVM;
|
||||
|
||||
}
|
||||
|
||||
if (aflcc->compiler_mode == LLVM) {
|
||||
|
||||
if (aflcc->cmplog_mode) {
|
||||
|
||||
WARNF("CMPLOG support requires LLVM 14+");
|
||||
aflcc->cmplog_mode = 0;
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_LLVM_DICT2FILE")) {
|
||||
|
||||
WARNF("DICT2FILE support requires LLVM14+");
|
||||
unsetenv("AFL_LLVM_DICT2FILE");
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_LLVM_LAF_SPLIT_SWITCHES") ||
|
||||
getenv("AFL_LLVM_LAF_SPLIT_COMPARES") ||
|
||||
getenv("AFL_LLVM_LAF_SPLIT_FLOATS") ||
|
||||
getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES") ||
|
||||
getenv("AFL_LLVM_LAF_ALL")) {
|
||||
|
||||
WARNF("AFL_LLVM_LAF support requires LLVM14+");
|
||||
unsetenv("AFL_LLVM_LAF_SPLIT_SWITCHES");
|
||||
unsetenv("AFL_LLVM_LAF_SPLIT_COMPARES");
|
||||
unsetenv("AFL_LLVM_LAF_SPLIT_FLOATS");
|
||||
unsetenv("AFL_LLVM_LAF_TRANSFORM_COMPARES");
|
||||
unsetenv("AFL_LLVM_LAF_ALL");
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_LLVM_INJECTIONS_ALL") ||
|
||||
getenv("AFL_LLVM_INJECTIONS_SQL") ||
|
||||
getenv("AFL_LLVM_INJECTIONS_LDAP") ||
|
||||
getenv("AFL_LLVM_INJECTIONS_XSS")) {
|
||||
|
||||
WARNF("AFL_LLVM_INJECTIONS support requires LLVM14+");
|
||||
unsetenv("AFL_LLVM_INJECTIONS_ALL");
|
||||
unsetenv("AFL_LLVM_INJECTIONS_SQL");
|
||||
unsetenv("AFL_LLVM_INJECTIONS_LDAP");
|
||||
unsetenv("AFL_LLVM_INJECTIONS_XSS");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
mode_notification(aflcc);
|
||||
|
||||
if (aflcc->debug) debugf_args(argc, argv);
|
||||
|
@ -179,7 +179,7 @@ u32 check_binary_signatures(u8 *fn) {
|
||||
if (f_data == MAP_FAILED) { PFATAL("Unable to mmap file '%s'", fn); }
|
||||
close(fd);
|
||||
|
||||
if (afl_memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG))) {
|
||||
if (afl_memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG) + 1)) {
|
||||
|
||||
if (!be_quiet) { OKF(cPIN "Persistent mode binary detected."); }
|
||||
setenv(PERSIST_ENV_VAR, "1", 1);
|
||||
@ -204,7 +204,7 @@ u32 check_binary_signatures(u8 *fn) {
|
||||
|
||||
}
|
||||
|
||||
if (afl_memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG))) {
|
||||
if (afl_memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
|
||||
|
||||
if (!be_quiet) { OKF(cPIN "Deferred forkserver binary detected."); }
|
||||
setenv(DEFER_ENV_VAR, "1", 1);
|
||||
@ -819,21 +819,7 @@ void check_environment_vars(char **envp) {
|
||||
|
||||
WARNF("AFL environment variable %s is deprecated!",
|
||||
afl_environment_deprecated[i]);
|
||||
|
||||
if (strncmp(afl_environment_deprecated[i], "AFL_SAN_NO_INST",
|
||||
strlen(afl_environment_deprecated[i])) == 0) {
|
||||
|
||||
WARNF(
|
||||
"AFL_LLVM_ONLY_FSRV/AFL_GCC_ONLY_FSRV is induced and set "
|
||||
"instead.");
|
||||
setenv("AFL_GCC_ONLY_FSRV", "1", 0);
|
||||
setenv("AFL_LLVM_ONLY_FSRV", "1", 0);
|
||||
|
||||
} else {
|
||||
|
||||
issue_detected = 1;
|
||||
|
||||
}
|
||||
issue_detected = 1;
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -140,7 +140,7 @@ nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) {
|
||||
if (plugin->nyx_get_target_hash64 == NULL) { goto fail; }
|
||||
|
||||
plugin->nyx_config_free = dlsym(handle, "nyx_config_free");
|
||||
if (plugin->nyx_config_free == NULL) { goto fail; }
|
||||
if (plugin->nyx_get_target_hash64 == NULL) { goto fail; }
|
||||
|
||||
OKF("libnyx plugin is ready!");
|
||||
return plugin;
|
||||
@ -250,16 +250,6 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
|
||||
fsrv->child_kill_signal = SIGKILL;
|
||||
fsrv->max_length = MAX_FILE;
|
||||
|
||||
if (getenv("AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT") != NULL) {
|
||||
|
||||
fsrv->setenv = 1;
|
||||
|
||||
} else {
|
||||
|
||||
fsrv->setenv = 0;
|
||||
|
||||
}
|
||||
|
||||
/* exec related stuff */
|
||||
fsrv->child_pid = -1;
|
||||
fsrv->map_size = get_map_size();
|
||||
@ -320,38 +310,6 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
|
||||
|
||||
}
|
||||
|
||||
void afl_fsrv_setup_preload(afl_forkserver_t *fsrv, char *argv0) {
|
||||
|
||||
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
|
||||
if (fsrv->qemu_mode) return;
|
||||
|
||||
u8 *afl_preload = getenv("AFL_PRELOAD");
|
||||
u8 *preload_path = NULL;
|
||||
u8 *frida_binary = NULL;
|
||||
if (fsrv->frida_mode)
|
||||
frida_binary = find_afl_binary(argv0, "afl-frida-trace.so");
|
||||
|
||||
if (afl_preload && frida_binary)
|
||||
preload_path = alloc_printf("%s:%s", afl_preload, frida_binary);
|
||||
else if (afl_preload)
|
||||
preload_path = ck_strdup(afl_preload);
|
||||
else if (frida_binary)
|
||||
preload_path = ck_strdup(frida_binary);
|
||||
|
||||
ck_free(frida_binary);
|
||||
|
||||
if (preload_path) {
|
||||
|
||||
setenv("LD_PRELOAD", preload_path, 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", preload_path, 1);
|
||||
#endif
|
||||
ck_free(preload_path);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Wrapper for select() and read(), reading a 32 bit var.
|
||||
Returns the time passed to read.
|
||||
If the wait times out, returns timeout_ms + 1;
|
||||
@ -920,8 +878,6 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
|
||||
/* CHILD PROCESS */
|
||||
|
||||
if (unlikely(fsrv->setenv)) { setenv("AFL_FORKSERVER_PARENT", "1", 0); }
|
||||
|
||||
// enable terminating on sigpipe in the children
|
||||
struct sigaction sa;
|
||||
memset((char *)&sa, 0, sizeof(sa));
|
||||
|
@ -255,8 +255,7 @@ inline u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) {
|
||||
* on rare cases it fall backs to the slow path: classify_counts() first, then
|
||||
* return has_new_bits(). */
|
||||
|
||||
static inline u8 has_new_bits_unclassified(afl_state_t *afl, u8 *virgin_map,
|
||||
bool *classified) {
|
||||
inline u8 has_new_bits_unclassified(afl_state_t *afl, u8 *virgin_map) {
|
||||
|
||||
/* Handle the hot path first: no new coverage */
|
||||
u8 *end = afl->fsrv.trace_bits + afl->fsrv.map_size;
|
||||
@ -273,7 +272,6 @@ static inline u8 has_new_bits_unclassified(afl_state_t *afl, u8 *virgin_map,
|
||||
|
||||
#endif /* ^WORD_SIZE_64 */
|
||||
classify_counts(&afl->fsrv);
|
||||
*classified = true;
|
||||
return has_new_bits(afl, virgin_map);
|
||||
|
||||
}
|
||||
@ -319,15 +317,7 @@ u8 *describe_op(afl_state_t *afl, u8 new_bits, size_t max_description_len) {
|
||||
|
||||
if (unlikely(afl->syncing_party)) {
|
||||
|
||||
if (unlikely(afl->foreign_file)) {
|
||||
|
||||
sprintf(ret, "sync:%s,src:%.20s", afl->syncing_party, afl->foreign_file);
|
||||
|
||||
} else {
|
||||
|
||||
sprintf(ret, "sync:%s,src:%06u", afl->syncing_party, afl->syncing_case);
|
||||
|
||||
}
|
||||
sprintf(ret, "sync:%s,src:%06u", afl->syncing_party, afl->syncing_case);
|
||||
|
||||
} else {
|
||||
|
||||
@ -472,46 +462,6 @@ void write_crash_readme(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
static inline void classify_if_necessary(afl_state_t *afl, bool *classified) {
|
||||
|
||||
if (*classified) return;
|
||||
classify_counts(&afl->fsrv);
|
||||
*classified = true;
|
||||
|
||||
}
|
||||
|
||||
static inline void calculate_cksum_if_necessary(afl_state_t *afl, u64 *cksum,
|
||||
bool *cksumed,
|
||||
bool *classified) {
|
||||
|
||||
if (*cksumed) return;
|
||||
classify_if_necessary(afl, classified);
|
||||
*cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
|
||||
*cksumed = true;
|
||||
|
||||
}
|
||||
|
||||
static inline void calculate_new_bits_if_necessary(afl_state_t *afl,
|
||||
u8 *new_bits,
|
||||
bool *bits_counted,
|
||||
bool *classified) {
|
||||
|
||||
if (*bits_counted) return;
|
||||
|
||||
if (*classified) {
|
||||
|
||||
*new_bits = has_new_bits(afl, afl->virgin_bits);
|
||||
|
||||
} else {
|
||||
|
||||
*new_bits = has_new_bits_unclassified(afl, afl->virgin_bits, classified);
|
||||
|
||||
}
|
||||
|
||||
*bits_counted = true;
|
||||
|
||||
}
|
||||
|
||||
/* Check if the result of an execve() during routine fuzzing is interesting,
|
||||
save or queue the input test case for further analysis if so. Returns 1 if
|
||||
entry is saved, 0 otherwise. */
|
||||
@ -519,6 +469,8 @@ static inline void calculate_new_bits_if_necessary(afl_state_t *afl,
|
||||
u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
u32 len, u8 fault) {
|
||||
|
||||
u8 classified = 0;
|
||||
|
||||
if (unlikely(len == 0)) { return 0; }
|
||||
|
||||
if (unlikely(fault == FSRV_RUN_TMOUT && afl->afl_env.afl_ignore_timeouts)) {
|
||||
@ -527,6 +479,7 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
|
||||
classify_counts(&afl->fsrv);
|
||||
u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
|
||||
classified = 1;
|
||||
|
||||
// Saturated increment
|
||||
if (likely(afl->n_fuzz[cksum % N_FUZZ_SIZE] < 0xFFFFFFFF))
|
||||
@ -540,14 +493,13 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
|
||||
u8 fn[PATH_MAX];
|
||||
u8 *queue_fn = "";
|
||||
u8 keeping = 0, res, is_timeout = 0;
|
||||
u8 san_fault = 0, san_idx = 0, feed_san = 0;
|
||||
u8 new_bits = 0, keeping = 0, res, is_timeout = 0, need_hash = 1;
|
||||
s32 fd;
|
||||
u64 cksum = 0;
|
||||
u32 cksum_simplified = 0, cksum_unique = 0;
|
||||
|
||||
bool classified = false, bits_counted = false, cksumed = false;
|
||||
u8 new_bits = 0; /* valid if bits_counted is true */
|
||||
u64 cksum = 0; /* valid if cksumed is true */
|
||||
u8 san_fault = 0;
|
||||
u8 san_idx = 0;
|
||||
u8 feed_san = 0;
|
||||
|
||||
afl->san_case_status = 0;
|
||||
|
||||
@ -557,7 +509,10 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
only be used for special schedules */
|
||||
if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
|
||||
|
||||
calculate_cksum_if_necessary(afl, &cksum, &cksumed, &classified);
|
||||
classify_counts(&afl->fsrv);
|
||||
need_hash = 0;
|
||||
|
||||
cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
|
||||
|
||||
/* Saturated increment */
|
||||
if (likely(afl->n_fuzz[cksum % N_FUZZ_SIZE] < 0xFFFFFFFF))
|
||||
@ -592,8 +547,7 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
unlikely(afl->san_abstraction == COVERAGE_INCREASE)) {
|
||||
|
||||
/* Check if the input increase the coverage */
|
||||
calculate_new_bits_if_necessary(afl, &new_bits, &bits_counted,
|
||||
&classified);
|
||||
new_bits = has_new_bits_unclassified(afl, afl->virgin_bits);
|
||||
|
||||
if (unlikely(new_bits)) { feed_san = 1; }
|
||||
|
||||
@ -602,9 +556,15 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
if (unlikely(afl->san_binary_length) &&
|
||||
likely(afl->san_abstraction == UNIQUE_TRACE)) {
|
||||
|
||||
// If schedule is not FAST..RARE, we need to classify counts here
|
||||
// Note: SAND was evaluated under FAST schedule but should also work
|
||||
// with other scedules.
|
||||
classify_if_necessary(afl, &classified);
|
||||
if (!classified) {
|
||||
|
||||
classify_counts(&afl->fsrv);
|
||||
classified = 1;
|
||||
|
||||
}
|
||||
|
||||
cksum_unique =
|
||||
hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
|
||||
@ -664,7 +624,22 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
|
||||
/* Keep only if there are new bits in the map, add to queue for
|
||||
future fuzzing, etc. */
|
||||
calculate_new_bits_if_necessary(afl, &new_bits, &bits_counted, &classified);
|
||||
if (!unlikely(afl->san_abstraction == COVERAGE_INCREASE && feed_san)) {
|
||||
|
||||
/* If we are in coverage increasing abstraction and have fed input to
|
||||
sanitizers, we are sure it has new bits.*/
|
||||
if (classified) {
|
||||
|
||||
/* We could have classified the bits in SAND with UNIQUE_TRACE */
|
||||
new_bits = has_new_bits(afl, afl->virgin_bits);
|
||||
|
||||
} else {
|
||||
|
||||
new_bits = has_new_bits_unclassified(afl, afl->virgin_bits);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (likely(!new_bits)) {
|
||||
|
||||
@ -687,11 +662,6 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
|
||||
save_to_queue:
|
||||
|
||||
/* these calculations are necessary because some code flow may jump here via
|
||||
goto */
|
||||
calculate_cksum_if_necessary(afl, &cksum, &cksumed, &classified);
|
||||
calculate_new_bits_if_necessary(afl, &new_bits, &bits_counted, &classified);
|
||||
|
||||
#ifndef SIMPLE_FILES
|
||||
|
||||
if (!afl->afl_env.afl_sha1_filenames) {
|
||||
@ -716,7 +686,7 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
#else
|
||||
|
||||
queue_fn = alloc_printf(
|
||||
"%s/queue/id_%06u%s%s", afl->out_dir, afl->queued_items,
|
||||
"%s/queue/id_%06u", afl->out_dir, afl->queued_items,
|
||||
afl->file_extension ? "." : "",
|
||||
afl->file_extension ? (const char *)afl->file_extension : "");
|
||||
|
||||
@ -773,8 +743,6 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
|
||||
#endif
|
||||
|
||||
afl->queue_top->exec_cksum = cksum;
|
||||
|
||||
if (new_bits == 2) {
|
||||
|
||||
afl->queue_top->has_new_cov = 1;
|
||||
@ -782,8 +750,17 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
|
||||
}
|
||||
|
||||
if (unlikely(need_hash && new_bits)) {
|
||||
|
||||
/* due to classify counts we have to recalculate the checksum */
|
||||
afl->queue_top->exec_cksum =
|
||||
hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
|
||||
need_hash = 0;
|
||||
|
||||
}
|
||||
|
||||
/* For AFLFast schedules we update the new queue entry */
|
||||
if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
|
||||
if (likely(cksum)) {
|
||||
|
||||
afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE;
|
||||
afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1;
|
||||
@ -882,9 +859,7 @@ may_save_fault:
|
||||
}
|
||||
|
||||
new_fault = fuzz_run_target(afl, &afl->fsrv, afl->hang_tmout);
|
||||
classified = false;
|
||||
bits_counted = false;
|
||||
cksumed = false;
|
||||
classify_counts(&afl->fsrv);
|
||||
|
||||
/* A corner case that one user reported bumping into: increasing the
|
||||
timeout actually uncovers a crash. Make sure we don't discard it if
|
||||
|
@ -589,6 +589,8 @@ void read_foreign_testcases(afl_state_t *afl, int first) {
|
||||
u8 *fn2 =
|
||||
alloc_printf("%s/%s", afl->foreign_syncs[iter].dir, nl[i]->d_name);
|
||||
|
||||
free(nl[i]); /* not tracked */
|
||||
|
||||
if (unlikely(lstat(fn2, &st) || access(fn2, R_OK))) {
|
||||
|
||||
if (first) PFATAL("Unable to access '%s'", fn2);
|
||||
@ -651,14 +653,17 @@ void read_foreign_testcases(afl_state_t *afl, int first) {
|
||||
u32 len = write_to_testcase(afl, (void **)&mem, st.st_size, 1);
|
||||
fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
|
||||
afl->syncing_party = foreign_name;
|
||||
afl->foreign_file = nl[i]->d_name;
|
||||
afl->queued_imported += save_if_interesting(afl, mem, len, fault);
|
||||
|
||||
afl->syncing_party = 0;
|
||||
munmap(mem, st.st_size);
|
||||
close(fd);
|
||||
|
||||
if (st.st_mtime > mtime_max) { mtime_max = st.st_mtime; }
|
||||
show_stats(afl);
|
||||
if (st.st_mtime > mtime_max) {
|
||||
|
||||
mtime_max = st.st_mtime;
|
||||
show_stats(afl);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -668,21 +673,12 @@ void read_foreign_testcases(afl_state_t *afl, int first) {
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < (u32)nl_cnt; ++i) {
|
||||
|
||||
free(nl[i]); /* not tracked */
|
||||
|
||||
}
|
||||
|
||||
free(nl); /* not tracked */
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
afl->foreign_file = NULL;
|
||||
afl->syncing_party = 0;
|
||||
|
||||
if (first) {
|
||||
|
||||
afl->last_find_time = 0;
|
||||
@ -760,10 +756,21 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
|
||||
if (nl_cnt) {
|
||||
|
||||
u32 done = 0;
|
||||
i = 0;
|
||||
|
||||
if (unlikely(afl->in_place_resume)) {
|
||||
|
||||
i = nl_cnt;
|
||||
|
||||
} else {
|
||||
|
||||
i = 0;
|
||||
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
if (unlikely(afl->in_place_resume)) { --i; }
|
||||
|
||||
struct stat st;
|
||||
u8 dfn[PATH_MAX];
|
||||
snprintf(dfn, PATH_MAX, "%s/.state/deterministic_done/%s", afl->in_dir,
|
||||
@ -843,12 +850,22 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
|
||||
}
|
||||
|
||||
next_entry:
|
||||
if (unlikely(++i >= (u32)nl_cnt)) { done = 1; }
|
||||
if (unlikely(afl->in_place_resume)) {
|
||||
|
||||
if (unlikely(i == 0)) { done = 1; }
|
||||
|
||||
} else {
|
||||
|
||||
if (unlikely(++i >= (u32)nl_cnt)) { done = 1; }
|
||||
|
||||
}
|
||||
|
||||
} while (!done);
|
||||
|
||||
}
|
||||
|
||||
// if (getenv("MYTEST")) afl->in_place_resume = 0;
|
||||
|
||||
free(nl); /* not tracked */
|
||||
|
||||
if (!afl->queued_items && directory == NULL) {
|
||||
@ -892,21 +909,9 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
|
||||
struct queue_entry *q;
|
||||
u32 cal_failures = 0, idx;
|
||||
u8 *use_mem, done = 0;
|
||||
u8 *use_mem;
|
||||
|
||||
if (afl->in_place_resume) {
|
||||
|
||||
idx = afl->queued_items;
|
||||
|
||||
} else {
|
||||
|
||||
idx = 0;
|
||||
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
if (afl->in_place_resume) { --idx; }
|
||||
for (idx = 0; idx < afl->queued_items; idx++) {
|
||||
|
||||
q = afl->queue_buf[idx];
|
||||
if (unlikely(!q || q->disabled)) { continue; }
|
||||
@ -1373,17 +1378,7 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
if (!afl->in_place_resume) {
|
||||
|
||||
if (++idx >= afl->queued_items) { done = 1; }
|
||||
|
||||
} else {
|
||||
|
||||
if (idx == 0) { done = 1; }
|
||||
|
||||
}
|
||||
|
||||
} while (!done);
|
||||
}
|
||||
|
||||
if (cal_failures) {
|
||||
|
||||
@ -1412,51 +1407,67 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
|
||||
q = afl->queue_buf[idx];
|
||||
if (!q || q->disabled || q->cal_failed || !q->exec_cksum) { continue; }
|
||||
u32 done = 0;
|
||||
|
||||
for (i = idx + 1; likely(i < afl->queued_items && afl->queue_buf[i]); ++i) {
|
||||
for (i = idx + 1;
|
||||
likely(i < afl->queued_items && afl->queue_buf[i] && !done); ++i) {
|
||||
|
||||
struct queue_entry *p = afl->queue_buf[i];
|
||||
if (p->disabled || p->cal_failed || !p->exec_cksum) { continue; }
|
||||
if (p->exec_cksum != q->exec_cksum) continue;
|
||||
|
||||
duplicates = 1;
|
||||
if (p->exec_cksum == q->exec_cksum) {
|
||||
|
||||
// we keep the shorter file
|
||||
struct queue_entry *to_disable, *to_keep;
|
||||
if (p->len >= q->len) {
|
||||
duplicates = 1;
|
||||
|
||||
to_disable = p;
|
||||
to_keep = q;
|
||||
// we keep the shorter file
|
||||
if (p->len >= q->len) {
|
||||
|
||||
} else {
|
||||
if (!p->was_fuzzed) {
|
||||
|
||||
to_disable = q;
|
||||
to_keep = p;
|
||||
p->was_fuzzed = 1;
|
||||
afl->reinit_table = 1;
|
||||
--afl->pending_not_fuzzed;
|
||||
--afl->active_items;
|
||||
|
||||
}
|
||||
|
||||
p->disabled = 1;
|
||||
p->perf_score = 0;
|
||||
|
||||
if (afl->debug) {
|
||||
|
||||
WARNF("Same coverage - %s is kept active, %s is disabled.",
|
||||
q->fname, p->fname);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (!q->was_fuzzed) {
|
||||
|
||||
q->was_fuzzed = 1;
|
||||
afl->reinit_table = 1;
|
||||
--afl->pending_not_fuzzed;
|
||||
--afl->active_items;
|
||||
|
||||
}
|
||||
|
||||
q->disabled = 1;
|
||||
q->perf_score = 0;
|
||||
|
||||
if (afl->debug) {
|
||||
|
||||
WARNF("Same coverage - %s is kept active, %s is disabled.",
|
||||
p->fname, q->fname);
|
||||
|
||||
}
|
||||
|
||||
done = 1; // end inner loop because outer loop entry is disabled now
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!to_disable->was_fuzzed) {
|
||||
|
||||
to_disable->was_fuzzed = 1;
|
||||
afl->reinit_table = 1;
|
||||
--afl->pending_not_fuzzed;
|
||||
--afl->active_items;
|
||||
|
||||
}
|
||||
|
||||
to_disable->disabled = 1;
|
||||
to_disable->perf_score = 0;
|
||||
|
||||
if (afl->debug) {
|
||||
|
||||
WARNF("Same coverage - %s is kept active, %s is disabled.",
|
||||
to_keep->fname, to_disable->fname);
|
||||
|
||||
}
|
||||
|
||||
// end inner loop because outer loop entry is disabled now
|
||||
if (to_disable == q) break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -1546,9 +1557,8 @@ void pivot_inputs(afl_state_t *afl) {
|
||||
ID matches the one we'd assign, just use the original file name.
|
||||
This is valuable for resuming fuzzing runs. */
|
||||
|
||||
if (afl->in_place_resume ||
|
||||
(!strncmp(rsl, CASE_PREFIX, 3) &&
|
||||
sscanf(rsl + 3, "%06u", &orig_id) == 1 && orig_id == id)) {
|
||||
if (!strncmp(rsl, CASE_PREFIX, 3) &&
|
||||
sscanf(rsl + 3, "%06u", &orig_id) == 1 && orig_id == id) {
|
||||
|
||||
u8 *src_str;
|
||||
u32 src_id;
|
||||
@ -2791,9 +2801,9 @@ void fix_up_sync(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
if (strlen(afl->sync_id) > SYNC_ID_MAX_LEN) {
|
||||
if (strlen(afl->sync_id) > 50) {
|
||||
|
||||
FATAL("sync_id max length is %d characters", SYNC_ID_MAX_LEN);
|
||||
FATAL("sync_id max length is 50 characters");
|
||||
|
||||
}
|
||||
|
||||
@ -2901,16 +2911,11 @@ void setup_testcase_shmem(afl_state_t *afl) {
|
||||
afl->shm_fuzz = ck_alloc(sizeof(sharedmem_t));
|
||||
|
||||
// we need to set the non-instrumented mode to not overwrite the SHM_ENV_VAR
|
||||
size_t shm_fuzz_map_size = SHM_FUZZ_MAP_SIZE_DEFAULT;
|
||||
u8 *map = afl_shm_init(afl->shm_fuzz, shm_fuzz_map_size, 1);
|
||||
u8 *map = afl_shm_init(afl->shm_fuzz, MAX_FILE + sizeof(u32), 1);
|
||||
afl->shm_fuzz->shmemfuzz_mode = 1;
|
||||
|
||||
if (!map) { FATAL("BUG: Zero return from afl_shm_init."); }
|
||||
|
||||
u8 *shm_fuzz_map_size_str = alloc_printf("%zu", shm_fuzz_map_size);
|
||||
setenv(SHM_FUZZ_MAP_SIZE_ENV_VAR, shm_fuzz_map_size_str, 1);
|
||||
ck_free(shm_fuzz_map_size_str);
|
||||
|
||||
#ifdef USEMMAP
|
||||
setenv(SHM_FUZZ_ENV_VAR, afl->shm_fuzz->g_shm_file_path, 1);
|
||||
#else
|
||||
@ -3111,7 +3116,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
|
||||
!afl->fsrv.nyx_mode &&
|
||||
#endif
|
||||
!afl->fsrv.cs_mode && !afl->non_instrumented_mode &&
|
||||
!afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR))) {
|
||||
!afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
|
||||
|
||||
SAYF("\n" cLRD "[-] " cRST
|
||||
"Looks like the target binary is not instrumented! The fuzzer depends "
|
||||
@ -3142,7 +3147,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
|
||||
}
|
||||
|
||||
if ((afl->fsrv.cs_mode || afl->fsrv.qemu_mode || afl->fsrv.frida_mode) &&
|
||||
afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR))) {
|
||||
afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
|
||||
|
||||
SAYF("\n" cLRD "[-] " cRST
|
||||
"This program appears to be instrumented with AFL++ compilers, but is "
|
||||
@ -3177,7 +3182,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
|
||||
|
||||
/* Detect persistent & deferred init signatures in the binary. */
|
||||
|
||||
if (afl_memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG))) {
|
||||
if (afl_memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG) + 1)) {
|
||||
|
||||
OKF(cPIN "Persistent mode binary detected.");
|
||||
setenv(PERSIST_ENV_VAR, "1", 1);
|
||||
@ -3204,7 +3209,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
|
||||
}
|
||||
|
||||
if (afl->fsrv.frida_mode ||
|
||||
afl_memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG))) {
|
||||
afl_memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
|
||||
|
||||
OKF(cPIN "Deferred forkserver binary detected.");
|
||||
setenv(DEFER_ENV_VAR, "1", 1);
|
||||
|
@ -356,12 +356,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
|
||||
if (el->afl_custom_queue_get &&
|
||||
!el->afl_custom_queue_get(el->data, afl->queue_cur->fname)) {
|
||||
|
||||
/* Abandon the entry and return that we skipped it.
|
||||
If we don't do this then when the entry is smallest_favored then
|
||||
we get caught in an infinite loop calling afl_custom_queue_get
|
||||
on smallest_favored */
|
||||
ret_val = 1;
|
||||
goto abandon_entry;
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
@ -411,12 +406,11 @@ u8 fuzz_one_original(afl_state_t *afl) {
|
||||
u_simplestring_time_diff(time_tmp, afl->prev_run_time + get_cur_time(),
|
||||
afl->start_time);
|
||||
ACTF(
|
||||
"Fuzzing test case #%u (%u total, %s%llu crashes saved%s, state: %s, "
|
||||
"Fuzzing test case #%u (%u total, %llu crashes saved, state: %s, "
|
||||
"mode=%s, "
|
||||
"perf_score=%0.0f, weight=%0.0f, favorite=%u, was_fuzzed=%u, "
|
||||
"exec_us=%llu, hits=%u, map=%u, ascii=%u, run_time=%s)...",
|
||||
afl->current_entry, afl->queued_items,
|
||||
afl->saved_crashes != 0 ? cRED : "", afl->saved_crashes, cRST,
|
||||
afl->current_entry, afl->queued_items, afl->saved_crashes,
|
||||
get_fuzzing_state(afl), afl->fuzz_mode ? "exploit" : "explore",
|
||||
afl->queue_cur->perf_score, afl->queue_cur->weight,
|
||||
afl->queue_cur->favored, afl->queue_cur->was_fuzzed,
|
||||
|
@ -26,10 +26,8 @@
|
||||
|
||||
#include "afl-fuzz.h"
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <signal.h>
|
||||
#include <limits.h>
|
||||
#include <glob.h>
|
||||
#if !defined NAME_MAX
|
||||
#define NAME_MAX _XOPEN_NAME_MAX
|
||||
#endif
|
||||
@ -495,41 +493,36 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
|
||||
afl->afl_env.afl_post_process_keep_original = 1;
|
||||
|
||||
/* we need a dummy run if this is LTO + cmplog */
|
||||
/*
|
||||
if (unlikely(afl->shm.cmplog_mode)) {
|
||||
if (unlikely(afl->shm.cmplog_mode)) {
|
||||
|
||||
(void)write_to_testcase(afl, (void **)&use_mem, q->len, 1);
|
||||
(void)write_to_testcase(afl, (void **)&use_mem, q->len, 1);
|
||||
|
||||
fault = fuzz_run_target(afl, &afl->fsrv, use_tmout);
|
||||
fault = fuzz_run_target(afl, &afl->fsrv, use_tmout);
|
||||
|
||||
// afl->stop_soon is set by the handler for Ctrl+C. When it's pressed,
|
||||
// we want to bail out quickly.
|
||||
/* afl->stop_soon is set by the handler for Ctrl+C. When it's pressed,
|
||||
we want to bail out quickly. */
|
||||
|
||||
if (afl->stop_soon || fault != afl->crash_mode) { goto abort_calibration;
|
||||
if (afl->stop_soon || fault != afl->crash_mode) { goto abort_calibration; }
|
||||
|
||||
}
|
||||
if (!afl->non_instrumented_mode && !afl->stage_cur &&
|
||||
!count_bytes(afl, afl->fsrv.trace_bits)) {
|
||||
|
||||
if (!afl->non_instrumented_mode &&
|
||||
!count_bytes(afl, afl->fsrv.trace_bits)) {
|
||||
|
||||
fault = FSRV_RUN_NOINST;
|
||||
goto abort_calibration;
|
||||
|
||||
}
|
||||
|
||||
#ifdef INTROSPECTION
|
||||
if (unlikely(!q->bitsmap_size)) { q->bitsmap_size = afl->bitsmap_size; }
|
||||
#endif
|
||||
fault = FSRV_RUN_NOINST;
|
||||
goto abort_calibration;
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
#ifdef INTROSPECTION
|
||||
if (unlikely(!q->bitsmap_size)) q->bitsmap_size = afl->bitsmap_size;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
if (q->exec_cksum) {
|
||||
|
||||
memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size);
|
||||
hnb = has_new_bits(afl, afl->virgin_bits);
|
||||
if (unlikely(hnb > new_bits)) { new_bits = hnb; }
|
||||
if (hnb > new_bits) { new_bits = hnb; }
|
||||
|
||||
}
|
||||
|
||||
@ -558,7 +551,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
|
||||
|
||||
if (afl->stop_soon || fault != afl->crash_mode) { goto abort_calibration; }
|
||||
|
||||
if (!afl->non_instrumented_mode &&
|
||||
if (!afl->non_instrumented_mode && !afl->stage_cur &&
|
||||
!count_bytes(afl, afl->fsrv.trace_bits)) {
|
||||
|
||||
fault = FSRV_RUN_NOINST;
|
||||
@ -567,19 +560,17 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
|
||||
}
|
||||
|
||||
#ifdef INTROSPECTION
|
||||
if (unlikely(!q->bitsmap_size)) { q->bitsmap_size = afl->bitsmap_size; }
|
||||
if (unlikely(!q->bitsmap_size)) q->bitsmap_size = afl->bitsmap_size;
|
||||
#endif
|
||||
|
||||
classify_counts(&afl->fsrv);
|
||||
cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
|
||||
|
||||
if (unlikely(q->exec_cksum != cksum)) {
|
||||
if (q->exec_cksum != cksum) {
|
||||
|
||||
hnb = has_new_bits(afl, afl->virgin_bits);
|
||||
if (hnb > new_bits) { new_bits = hnb; }
|
||||
|
||||
if (unlikely(hnb > new_bits)) { new_bits = hnb; }
|
||||
|
||||
if (likely(q->exec_cksum)) {
|
||||
if (q->exec_cksum) {
|
||||
|
||||
u32 i;
|
||||
|
||||
@ -706,110 +697,6 @@ abort_calibration:
|
||||
|
||||
}
|
||||
|
||||
/* Do not sync items that were synced from us */
|
||||
|
||||
static bool is_known_case(afl_state_t *afl, u8 *name) {
|
||||
|
||||
static char coming_from_me_str[SYNC_ID_MAX_LEN + 2];
|
||||
static u32 coming_from_me_len = 0;
|
||||
static u32 min_len = 15 + 4 + 6;
|
||||
|
||||
if (!coming_from_me_len) {
|
||||
|
||||
snprintf(coming_from_me_str, sizeof(coming_from_me_str), "%s,",
|
||||
afl->sync_id);
|
||||
min_len += coming_from_me_len = strlen(coming_from_me_str);
|
||||
|
||||
}
|
||||
|
||||
// file name length long enough so it can be ours
|
||||
if (unlikely(strlen(name) < min_len)) { return false; }
|
||||
// is it based on a sync? allow optimizer to make an integer comparison
|
||||
if (likely(memcmp(name + 10, "sync", 4) != 0)) { return false; }
|
||||
// we jump over the ':' after 'sync' and compare to our sync name
|
||||
if (unlikely(memcmp(name + 15, coming_from_me_str, coming_from_me_len) !=
|
||||
0)) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/* We do not need this as we now look on startup how many files are in sync
|
||||
targets.
|
||||
int src_id = atoi(name + 15 + coming_from_me_len + 4);
|
||||
if (unlikely(src_id >= afl->queued_items)) return false;
|
||||
*/
|
||||
|
||||
// yes it is highly likely a current testcase we already know
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/* Write into .sync/INSTANCE.max how many queue files were there on startup */
|
||||
|
||||
void check_sync_fuzzers(afl_state_t *afl) {
|
||||
|
||||
if (unlikely(afl->afl_env.afl_no_sync)) { return; }
|
||||
|
||||
DIR *sd, *dir;
|
||||
struct dirent *sd_ent, *entry;
|
||||
u8 qd_path[PATH_MAX], qd_synced_maxid[PATH_MAX];
|
||||
|
||||
sd = opendir(afl->sync_dir);
|
||||
if (!sd) { PFATAL("Unable to open '%s'", afl->sync_dir); }
|
||||
|
||||
u64 sync_start_us = get_cur_time_us();
|
||||
// Look at the entries created for every other fuzzer in the sync directory.
|
||||
|
||||
while ((sd_ent = readdir(sd))) {
|
||||
|
||||
if (sd_ent->d_name[0] == '.' || !strcmp(afl->sync_id, sd_ent->d_name)) {
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
sprintf(qd_path, "%s/%s/queue", afl->sync_dir, sd_ent->d_name);
|
||||
|
||||
dir = opendir(qd_path);
|
||||
if (dir) {
|
||||
|
||||
u32 max_start_id = 0;
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
|
||||
max_start_id++;
|
||||
|
||||
}
|
||||
|
||||
if (max_start_id > 4) {
|
||||
|
||||
sprintf(qd_synced_maxid, "%s/.synced/%s.max", afl->out_dir,
|
||||
sd_ent->d_name);
|
||||
s32 max_fd = open(qd_synced_maxid, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
DEFAULT_PERMISSION);
|
||||
|
||||
if (max_fd >= 0) {
|
||||
|
||||
max_start_id -= 4; // without ".", "..", ".state" and counting from 0
|
||||
write(max_fd, &max_start_id, sizeof(u32));
|
||||
close(max_fd);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
}
|
||||
|
||||
closedir(sd);
|
||||
|
||||
update_sync_time(afl, &sync_start_us);
|
||||
|
||||
}
|
||||
|
||||
/* Grab interesting test cases from other fuzzers. */
|
||||
|
||||
void sync_fuzzers(afl_state_t *afl) {
|
||||
@ -828,7 +715,8 @@ void sync_fuzzers(afl_state_t *afl) {
|
||||
afl->cur_depth = 0;
|
||||
|
||||
u64 sync_start_us = get_cur_time_us();
|
||||
// Look at the entries created for every other fuzzer in the sync directory.
|
||||
/* Look at the entries created for every other fuzzer in the sync directory.
|
||||
*/
|
||||
|
||||
while ((sd_ent = readdir(sd))) {
|
||||
|
||||
@ -836,11 +724,12 @@ void sync_fuzzers(afl_state_t *afl) {
|
||||
// iteration
|
||||
update_sync_time(afl, &sync_start_us);
|
||||
|
||||
u8 qd_synced_path[PATH_MAX], qd_path[PATH_MAX], qd_synced_maxid[PATH_MAX];
|
||||
u32 min_accept = 0, next_min_accept = 0, max_start_id = 0;
|
||||
u8 qd_synced_path[PATH_MAX], qd_path[PATH_MAX];
|
||||
u32 min_accept = 0, next_min_accept = 0;
|
||||
|
||||
s32 id_fd;
|
||||
|
||||
// Skip dot files and our own output directory.
|
||||
/* Skip dot files and our own output directory. */
|
||||
|
||||
if (sd_ent->d_name[0] == '.' || !strcmp(afl->sync_id, sd_ent->d_name)) {
|
||||
|
||||
@ -875,7 +764,14 @@ void sync_fuzzers(afl_state_t *afl) {
|
||||
|
||||
synced++;
|
||||
|
||||
// Skip anything that doesn't have a queue/ subdirectory.
|
||||
/* 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, DEFAULT_PERMISSION);
|
||||
if (id_fd >= 0) close(id_fd);
|
||||
|
||||
/* Skip anything that doesn't have a queue/ subdirectory. */
|
||||
|
||||
sprintf(qd_path, "%s/%s/queue", afl->sync_dir, sd_ent->d_name);
|
||||
|
||||
@ -891,7 +787,7 @@ void sync_fuzzers(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
// Retrieve the ID of the last seen test case.
|
||||
/* Retrieve the ID of the last seen test case. */
|
||||
|
||||
sprintf(qd_synced_path, "%s/.synced/%s", afl->out_dir, sd_ent->d_name);
|
||||
|
||||
@ -906,55 +802,6 @@ void sync_fuzzers(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
// now document the attempt to sync to this instance
|
||||
sprintf(qd_synced_path, "%s/.synced/%s.last", afl->out_dir, sd_ent->d_name);
|
||||
int id_fd2 =
|
||||
open(qd_synced_path, O_RDWR | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
|
||||
if (id_fd2 >= 0) close(id_fd2);
|
||||
|
||||
// It could be that the target syncing instance was restarted, check!
|
||||
time_t last_mtime = 0;
|
||||
char id0[PATH_MAX];
|
||||
struct stat st;
|
||||
|
||||
if (stat(qd_synced_path, &st) == 0) { last_mtime = st.st_mtime; }
|
||||
|
||||
snprintf(id0, sizeof(id0), "%s/%s/cmdline", afl->sync_dir, sd_ent->d_name);
|
||||
|
||||
if (likely(stat(id0, &st) == 0)) {
|
||||
|
||||
if (unlikely(last_mtime && last_mtime <= st.st_mtime)) {
|
||||
|
||||
// the first entry is newer than when we synced last - instance was
|
||||
// restarted - we have to reset our counter and will skip this instance
|
||||
// this time. It could also be this was trimmed later, or restated with
|
||||
// resume-in-place though but better be safe.
|
||||
min_accept = 0;
|
||||
ck_write(id_fd, &min_accept, sizeof(u32), qd_synced_path);
|
||||
goto close_sync;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// something went wrong - this cannot be right, mabye the instance is
|
||||
// restarting, skip
|
||||
goto close_sync;
|
||||
|
||||
}
|
||||
|
||||
// check if there is a file documented the maximum id seen on startup
|
||||
sprintf(qd_synced_maxid, "%s/.synced/%s.max", afl->out_dir, sd_ent->d_name);
|
||||
s32 max_fd = open(qd_synced_maxid, O_RDONLY, DEFAULT_PERMISSION);
|
||||
|
||||
if (max_fd >= 0) {
|
||||
|
||||
read(max_fd, &max_start_id, sizeof(u32));
|
||||
close(max_fd);
|
||||
if (max_start_id < next_min_accept) { unlink(qd_synced_maxid); }
|
||||
|
||||
}
|
||||
|
||||
/* Show stats */
|
||||
|
||||
snprintf(afl->stage_name_buf, STAGE_BUF_SIZE, "sync %u", ++sync_cnt);
|
||||
@ -1008,37 +855,34 @@ void sync_fuzzers(afl_state_t *afl) {
|
||||
|
||||
if (st.st_size && st.st_size <= MAX_FILE) {
|
||||
|
||||
if (likely(next_min_accept < max_start_id ||
|
||||
!is_known_case(afl, namelist[o]->d_name))) {
|
||||
u8 fault;
|
||||
u8 *mem = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
|
||||
/* See what happens. We rely on save_if_interesting() to catch major
|
||||
errors and save the test case. */
|
||||
if (mem == MAP_FAILED) { PFATAL("Unable to mmap '%s'", path); }
|
||||
|
||||
u8 *mem = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
/* See what happens. We rely on save_if_interesting() to catch major
|
||||
errors and save the test case. */
|
||||
|
||||
if (mem == MAP_FAILED) { PFATAL("Unable to mmap '%s'", path); }
|
||||
u32 new_len = write_to_testcase(afl, (void **)&mem, st.st_size, 1);
|
||||
|
||||
u32 new_len = write_to_testcase(afl, (void **)&mem, st.st_size, 1);
|
||||
fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
|
||||
|
||||
u8 fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
|
||||
if (afl->stop_soon) {
|
||||
|
||||
if (afl->stop_soon) {
|
||||
|
||||
munmap(mem, st.st_size);
|
||||
close(fd);
|
||||
|
||||
goto close_sync;
|
||||
|
||||
}
|
||||
|
||||
afl->syncing_party = sd_ent->d_name;
|
||||
afl->queued_imported += save_if_interesting(afl, mem, new_len, fault);
|
||||
show_stats(afl);
|
||||
afl->syncing_party = 0;
|
||||
munmap(mem, st.st_size);
|
||||
close(fd);
|
||||
|
||||
goto close_sync;
|
||||
|
||||
}
|
||||
|
||||
afl->syncing_party = sd_ent->d_name;
|
||||
afl->queued_imported += save_if_interesting(afl, mem, new_len, fault);
|
||||
show_stats(afl);
|
||||
afl->syncing_party = 0;
|
||||
|
||||
munmap(mem, st.st_size);
|
||||
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
@ -39,9 +39,6 @@ void sanfuzz_exec_child(afl_forkserver_t *fsrv, char **argv) {
|
||||
|
||||
}
|
||||
|
||||
// In case users provide the normally instrumented binaries, this servers as
|
||||
// the last resort to avoid collecting incorrect coverage.
|
||||
setenv("AFL_LLVM_ONLY_FSRV", "1", 0);
|
||||
execv(fsrv->target_path, argv);
|
||||
|
||||
}
|
||||
|
@ -148,34 +148,6 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) {
|
||||
|
||||
}
|
||||
|
||||
void afl_resize_map_buffers(afl_state_t *afl, u32 old_size, u32 new_size) {
|
||||
|
||||
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_size);
|
||||
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_size);
|
||||
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_size);
|
||||
afl->var_bytes = ck_realloc(afl->var_bytes, new_size);
|
||||
afl->top_rated = ck_realloc(afl->top_rated, new_size * sizeof(void *));
|
||||
afl->clean_trace = ck_realloc(afl->clean_trace, new_size);
|
||||
afl->clean_trace_custom = ck_realloc(afl->clean_trace_custom, new_size);
|
||||
afl->first_trace = ck_realloc(afl->first_trace, new_size);
|
||||
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_size);
|
||||
|
||||
if (old_size < new_size) {
|
||||
|
||||
u32 size_diff = new_size - old_size;
|
||||
|
||||
memset(afl->var_bytes + old_size, 0, size_diff);
|
||||
memset(afl->top_rated + old_size * sizeof(void *), 0,
|
||||
size_diff * sizeof(void *));
|
||||
memset(afl->clean_trace + old_size, 0, size_diff);
|
||||
memset(afl->clean_trace_custom + old_size, 0, size_diff);
|
||||
memset(afl->first_trace + old_size, 0, size_diff);
|
||||
memset(afl->map_tmp_buf + old_size, 0, size_diff);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*This sets up the environment variables for afl-fuzz into the afl_state
|
||||
* struct*/
|
||||
|
||||
|
@ -28,13 +28,8 @@
|
||||
#include "envs.h"
|
||||
#include <limits.h>
|
||||
|
||||
// 7 is the number of characters in a color control code
|
||||
// 11 is the number of characters in the fuzzing state itself
|
||||
// 5 is the number of characters in `cRST`
|
||||
// 1 is for the null character
|
||||
static char fuzzing_state[4][7 + 11 + 5 + 1] = {
|
||||
|
||||
"started :-)", "in progress", "final phase", cRED "finished..." cRST};
|
||||
static char fuzzing_state[4][12] = {"started :-)", "in progress", "final phase",
|
||||
"finished..."};
|
||||
|
||||
char *get_fuzzing_state(afl_state_t *afl) {
|
||||
|
||||
@ -59,13 +54,13 @@ char *get_fuzzing_state(afl_state_t *afl) {
|
||||
u64 percent_cur = last_find_100 / cur_run_time;
|
||||
u64 percent_total = last_find_100 / cur_total_run_time;
|
||||
|
||||
if (unlikely(percent_cur >= 75 && percent_total >= 75)) {
|
||||
if (unlikely(percent_cur >= 80 && percent_total >= 80)) {
|
||||
|
||||
if (unlikely(afl->afl_env.afl_exit_when_done)) { afl->stop_soon = 2; }
|
||||
|
||||
return fuzzing_state[3];
|
||||
|
||||
} else if (unlikely(percent_cur >= 50 && percent_total >= 50)) {
|
||||
} else if (unlikely(percent_cur >= 55 && percent_total >= 55)) {
|
||||
|
||||
return fuzzing_state[2];
|
||||
|
||||
|
502
src/afl-fuzz.c
502
src/afl-fuzz.c
@ -543,6 +543,152 @@ static void fasan_check_afl_preload(char *afl_preload) {
|
||||
|
||||
}
|
||||
|
||||
u8 run_gen_seeds(afl_state_t *afl, u8 init_flag) {
|
||||
|
||||
afl->stage_name = "G2-genseed";
|
||||
afl->stage_short = "G2genseed";
|
||||
|
||||
char command[1000];
|
||||
if (init_flag == 1) {
|
||||
|
||||
snprintf(command, sizeof(command),
|
||||
"python %s/program_gen.py --output %s --program %s --input %s "
|
||||
"--mode init >> %s/gen_log",
|
||||
afl->generator_base_path, afl->out_dir, afl->target_program,
|
||||
afl->in_dir, afl->out_dir);
|
||||
|
||||
} else {
|
||||
|
||||
snprintf(
|
||||
command, sizeof(command),
|
||||
"python %s/generator_mutation_gpt_3_5.py --output %s >> %s/mutate_log",
|
||||
afl->generator_base_path, afl->out_dir, afl->out_dir);
|
||||
|
||||
}
|
||||
|
||||
int result = system(command);
|
||||
if (result == 0) {
|
||||
|
||||
// printf("Command executed successfully.\n");
|
||||
|
||||
} else {
|
||||
|
||||
if (afl->afl_env.afl_no_ui) {
|
||||
|
||||
fprintf(stderr,
|
||||
"G2 generator_mutation command failed with exit code %d.\n",
|
||||
result);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// input: dir
|
||||
// queue_testcase_get
|
||||
// get buf from dir
|
||||
DIR *dp;
|
||||
struct dirent *entry_tmp;
|
||||
struct stat file_stat;
|
||||
char *dir = alloc_printf("%s/gen_seeds", afl->out_dir);
|
||||
dp = opendir(dir);
|
||||
if (!dp) {
|
||||
|
||||
perror("opendir");
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
u8 cnt = 0;
|
||||
|
||||
while ((entry_tmp = readdir(dp)) != NULL) {
|
||||
|
||||
char path[1024];
|
||||
snprintf(path, sizeof(path), "%s/%s", dir, entry_tmp->d_name);
|
||||
|
||||
if (stat(path, &file_stat) == 0) {
|
||||
|
||||
if (S_ISREG(file_stat.st_mode)) {
|
||||
|
||||
u32 len = (u32)file_stat.st_size;
|
||||
char *file_name = basename(path);
|
||||
// printf("File: %s, Length: %u bytes\n", file_name, len);
|
||||
|
||||
u8 *buf;
|
||||
buf = afl_realloc((void **)&afl->testcase_buf, len);
|
||||
int fd = open(path, O_RDONLY);
|
||||
if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", path); }
|
||||
ck_read(fd, buf, len, path);
|
||||
close(fd);
|
||||
|
||||
// choose I: directly add to the queue as a new seed that finds new
|
||||
// edges
|
||||
u8 *queue_fn = "";
|
||||
queue_fn = alloc_printf("%s/queue/id:%06u,time:0,execs:%llu,orig:%s",
|
||||
afl->out_dir, afl->queued_items,
|
||||
afl->fsrv.total_execs, file_name);
|
||||
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, buf, len, queue_fn);
|
||||
close(fd);
|
||||
add_to_queue(afl, queue_fn, len, 0);
|
||||
|
||||
if (init_flag == 0) {
|
||||
|
||||
struct queue_entry *q;
|
||||
q = afl->queue_buf[afl->queued_items - 1];
|
||||
calibrate_case(afl, q, buf, 4, 1);
|
||||
|
||||
}
|
||||
|
||||
cnt++;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
perror("stat");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int fileCount = 0;
|
||||
DIR *directory = opendir(dir);
|
||||
struct dirent *entry;
|
||||
while ((entry = readdir(directory)) != NULL) {
|
||||
|
||||
if (entry->d_type == DT_REG) { // Check if it's a regular file
|
||||
fileCount++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (fileCount) {
|
||||
|
||||
char remove_cmd[100];
|
||||
snprintf(remove_cmd, sizeof(remove_cmd), "rm %s/*", dir);
|
||||
result = system(remove_cmd);
|
||||
if (result == 0) {
|
||||
|
||||
// printf("remove_cmd executed successfully.\n");
|
||||
|
||||
} else {
|
||||
|
||||
if (afl->afl_env.afl_no_ui) {
|
||||
|
||||
printf("G2 remove_cmd failed with exit code %d.\n", result);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return cnt;
|
||||
|
||||
}
|
||||
|
||||
/* Main entry point */
|
||||
|
||||
int main(int argc, char **argv_orig, char **envp) {
|
||||
@ -612,11 +758,11 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
afl->shmem_testcase_mode = 1; // we always try to perform shmem fuzzing
|
||||
|
||||
// still available: HjJkKqrv
|
||||
while (
|
||||
(opt = getopt(argc, argv,
|
||||
"+a:Ab:B:c:CdDe:E:f:F:g:G:hi:I:l:L:m:M:nNo:Op:P:QRs:S:t:T:"
|
||||
"uUV:w:WXx:YzZ")) > 0) {
|
||||
// still available: HjKqrv
|
||||
while ((opt = getopt(
|
||||
argc, argv,
|
||||
"+a:Ab:B:c:CdDe:E:f:F:g:G:hi:I:J:k:l:L:m:M:nNo:Op:P:QRs:S:t:T:"
|
||||
"uUV:w:WXx:YzZ")) > 0) {
|
||||
|
||||
switch (opt) {
|
||||
|
||||
@ -1486,6 +1632,28 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
break;
|
||||
|
||||
case 'J':
|
||||
afl->target_program = strdup(optarg);
|
||||
if (afl->target_program == NULL) {
|
||||
|
||||
FATAL("No file format.");
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
|
||||
if (afl->generator_base_path) {
|
||||
|
||||
FATAL("Multiple -k options not supported");
|
||||
|
||||
}
|
||||
|
||||
afl->generator_base_path = optarg;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!show_help) { show_help = 1; }
|
||||
|
||||
@ -1555,6 +1723,13 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
#endif
|
||||
|
||||
// silently disable deterministic mutation if custom mutators are used
|
||||
if (!afl->skip_deterministic && afl->afl_env.afl_custom_mutator_only) {
|
||||
|
||||
afl->skip_deterministic = 1;
|
||||
|
||||
}
|
||||
|
||||
if (afl->fixed_seed) {
|
||||
|
||||
OKF("Running with fixed seed: %u", (u32)afl->init_seed);
|
||||
@ -1745,7 +1920,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
if (afl->cycle_schedules) {
|
||||
|
||||
afl->top_rated_candidates = ck_alloc(map_size * sizeof(u32 *));
|
||||
afl->top_rated_candidates = ck_alloc(map_size * sizeof(u32));
|
||||
|
||||
}
|
||||
|
||||
@ -2307,7 +2482,11 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
u64 target_hash = get_binary_hash(afl->fsrv.target_path);
|
||||
#endif
|
||||
|
||||
if (!target_hash || prev_target_hash != target_hash) {
|
||||
if ((!target_hash || prev_target_hash != target_hash)
|
||||
#ifdef __linux__
|
||||
|| (afl->fsrv.nyx_mode && target_hash == 0)
|
||||
#endif
|
||||
) {
|
||||
|
||||
ACTF("Target binary is different, cannot perform FAST RESUME!");
|
||||
|
||||
@ -2498,8 +2677,29 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
if (afl->non_instrumented_mode || afl->fsrv.qemu_mode ||
|
||||
afl->fsrv.frida_mode || afl->fsrv.cs_mode || afl->unicorn_mode) {
|
||||
|
||||
u32 old_map_size = map_size;
|
||||
map_size = afl->fsrv.real_map_size = afl->fsrv.map_size = MAP_SIZE;
|
||||
afl_resize_map_buffers(afl, 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);
|
||||
|
||||
if (old_map_size < map_size) {
|
||||
|
||||
memset(afl->var_bytes + old_map_size, 0, map_size - old_map_size);
|
||||
memset(afl->top_rated + old_map_size, 0, map_size - old_map_size);
|
||||
memset(afl->clean_trace + old_map_size, 0, map_size - old_map_size);
|
||||
memset(afl->clean_trace_custom + old_map_size, 0,
|
||||
map_size - old_map_size);
|
||||
memset(afl->first_trace + old_map_size, 0, map_size - old_map_size);
|
||||
memset(afl->map_tmp_buf + old_map_size, 0, map_size - old_map_size);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2527,7 +2727,31 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
if (map_size < new_map_size) {
|
||||
|
||||
OKF("Re-initializing maps to %u bytes", new_map_size);
|
||||
afl_resize_map_buffers(afl, map_size, new_map_size);
|
||||
|
||||
u32 old_map_size = 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);
|
||||
|
||||
if (old_map_size < new_map_size) {
|
||||
|
||||
memset(afl->var_bytes + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->top_rated + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->clean_trace + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->clean_trace_custom + old_map_size, 0,
|
||||
new_map_size - old_map_size);
|
||||
memset(afl->first_trace + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->map_tmp_buf + old_map_size, 0, new_map_size - old_map_size);
|
||||
|
||||
}
|
||||
|
||||
afl_fsrv_kill(&afl->fsrv);
|
||||
afl_shm_deinit(&afl->shm);
|
||||
@ -2588,6 +2812,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
*/
|
||||
afl->san_fsrvs[i].trace_bits = ck_alloc(
|
||||
afl->fsrv.map_size + 8); /* One more u64 according to afl_shm_init*/
|
||||
afl->san_fsrvs[i].map_size = afl->fsrv.map_size;
|
||||
afl->san_fsrvs[i].san_but_not_instrumented = 1;
|
||||
|
||||
afl->san_fsrvs[i].cs_mode = afl->fsrv.cs_mode;
|
||||
@ -2597,6 +2822,10 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
afl->san_fsrvs[i].target_path = afl->san_binary[i];
|
||||
afl->san_fsrvs[i].init_child_func = sanfuzz_exec_child;
|
||||
|
||||
afl->san_fsrvs[i].child_kill_signal =
|
||||
afl->fsrv.child_kill_signal; // I believe cmplog also needs this.
|
||||
afl->san_fsrvs[i].fsrv_kill_signal = afl->fsrv.fsrv_kill_signal;
|
||||
|
||||
if ((map_size <= DEFAULT_SHMEM_SIZE ||
|
||||
afl->san_fsrvs[i].map_size < map_size) &&
|
||||
!afl->non_instrumented_mode && !afl->fsrv.qemu_mode &&
|
||||
@ -2619,7 +2848,18 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
OKF("Re-initializing maps to %u bytes due to SAN instrumented binary",
|
||||
new_map_size);
|
||||
afl_resize_map_buffers(afl, map_size, 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->san_fsrvs[i]);
|
||||
@ -2685,7 +2925,31 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
if (map_size < new_map_size) {
|
||||
|
||||
OKF("Re-initializing maps to %u bytes due cmplog", new_map_size);
|
||||
afl_resize_map_buffers(afl, map_size, new_map_size);
|
||||
|
||||
u32 old_map_size = 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);
|
||||
|
||||
if (old_map_size < new_map_size) {
|
||||
|
||||
memset(afl->var_bytes + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->top_rated + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->clean_trace + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->clean_trace_custom + old_map_size, 0,
|
||||
new_map_size - old_map_size);
|
||||
memset(afl->first_trace + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->map_tmp_buf + old_map_size, 0, new_map_size - old_map_size);
|
||||
|
||||
}
|
||||
|
||||
afl_fsrv_kill(&afl->fsrv);
|
||||
afl_fsrv_kill(&afl->cmplog_fsrv);
|
||||
@ -2913,8 +3177,6 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
if (afl->stop_soon) { goto stop_fuzzing; }
|
||||
|
||||
if (!afl->in_place_resume) { check_sync_fuzzers(afl); }
|
||||
|
||||
/* Woop woop woop */
|
||||
|
||||
if (!afl->not_on_tty) {
|
||||
@ -2947,6 +3209,8 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
// real start time, we reset, so this works correctly with -V
|
||||
afl->start_time = get_cur_time();
|
||||
u64 gen_last_update = get_cur_time();
|
||||
u64 use_time = 0;
|
||||
|
||||
while (likely(!afl->stop_soon)) {
|
||||
|
||||
@ -3162,117 +3426,169 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
++runs_in_current_cycle;
|
||||
|
||||
do {
|
||||
if (get_cur_time() - afl->last_find_time >
|
||||
300 * 1000 + use_time * 60 * 1000 &&
|
||||
get_cur_time() - gen_last_update > 300 * 1000 + use_time * 60 * 1000) {
|
||||
|
||||
if (likely(!afl->old_seed_selection)) {
|
||||
u8 log_path[PATH_MAX];
|
||||
sprintf(log_path, "%s/gen_seeds_energy_log", afl->out_dir);
|
||||
FILE *file = fopen(log_path, "a");
|
||||
|
||||
if (likely(afl->pending_favored && afl->smallest_favored >= 0)) {
|
||||
u8 cnt = run_gen_seeds(afl, 0);
|
||||
|
||||
afl->current_entry = afl->smallest_favored;
|
||||
afl->stage_name = "G2-runseed";
|
||||
afl->stage_short = "G2runseed";
|
||||
|
||||
/*
|
||||
u32 *target_seeds = (u32 *)malloc(cnt * sizeof(u32));
|
||||
for (u32 i = 0; i < cnt; i++) {
|
||||
|
||||
} else {
|
||||
target_seeds[i] = afl->queued_items - i - 1;
|
||||
afl->queue_cur = afl->queue_buf[target_seeds[i]];
|
||||
// printf("%s\n", afl->queue_cur->fname);
|
||||
|
||||
for (s32 iter = afl->queued_items - 1; iter >= 0; --iter)
|
||||
{
|
||||
}
|
||||
|
||||
if (unlikely(afl->queue_buf[iter]->favored &&
|
||||
!afl->queue_buf[iter]->was_fuzzed)) {
|
||||
for (u8 i = 0; i < cnt; i++) {
|
||||
|
||||
afl->current_entry = iter;
|
||||
break;
|
||||
if (unlikely(prev_queued_items < afl->queued_items ||
|
||||
afl->reinit_table)) {
|
||||
|
||||
// we have new queue entries since the last run, recreate alias table
|
||||
prev_queued_items = afl->queued_items;
|
||||
create_alias_table(afl);
|
||||
|
||||
}
|
||||
|
||||
afl->queue_cur = afl->queue_buf[target_seeds[i]];
|
||||
afl->current_entry = afl->queue_cur->id;
|
||||
afl->queue_cur->favored = 1;
|
||||
|
||||
fuzz_one(afl);
|
||||
|
||||
}
|
||||
|
||||
gen_last_update = get_cur_time();
|
||||
use_time += 1;
|
||||
|
||||
fclose(file);
|
||||
|
||||
} else {
|
||||
|
||||
do {
|
||||
|
||||
if (likely(!afl->old_seed_selection)) {
|
||||
|
||||
if (likely(afl->pending_favored && afl->smallest_favored >= 0)) {
|
||||
|
||||
afl->current_entry = afl->smallest_favored;
|
||||
|
||||
/*
|
||||
|
||||
} else {
|
||||
|
||||
for (s32 iter = afl->queued_items - 1; iter >= 0;
|
||||
--iter)
|
||||
{
|
||||
|
||||
if (unlikely(afl->queue_buf[iter]->favored &&
|
||||
!afl->queue_buf[iter]->was_fuzzed)) {
|
||||
|
||||
afl->current_entry = iter;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
*/
|
||||
afl->queue_cur = afl->queue_buf[afl->current_entry];
|
||||
|
||||
afl->queue_cur = afl->queue_buf[afl->current_entry];
|
||||
} else {
|
||||
|
||||
} else {
|
||||
if (unlikely(prev_queued_items < afl->queued_items ||
|
||||
afl->reinit_table)) {
|
||||
|
||||
if (unlikely(prev_queued_items < afl->queued_items ||
|
||||
afl->reinit_table)) {
|
||||
// we have new queue entries since the last run, recreate alias
|
||||
// table
|
||||
prev_queued_items = afl->queued_items;
|
||||
create_alias_table(afl);
|
||||
|
||||
// we have new queue entries since the last run, recreate alias
|
||||
// table
|
||||
prev_queued_items = afl->queued_items;
|
||||
create_alias_table(afl);
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
afl->current_entry = select_next_queue_entry(afl);
|
||||
|
||||
} while (unlikely(afl->current_entry >= afl->queued_items));
|
||||
|
||||
afl->queue_cur = afl->queue_buf[afl->current_entry];
|
||||
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
afl->current_entry = select_next_queue_entry(afl);
|
||||
|
||||
} while (unlikely(afl->current_entry >= afl->queued_items));
|
||||
|
||||
afl->queue_cur = afl->queue_buf[afl->current_entry];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
skipped_fuzz = fuzz_one(afl);
|
||||
skipped_fuzz = fuzz_one(afl);
|
||||
#ifdef INTROSPECTION
|
||||
++afl->queue_cur->stats_selected;
|
||||
++afl->queue_cur->stats_selected;
|
||||
|
||||
if (unlikely(skipped_fuzz)) {
|
||||
if (unlikely(skipped_fuzz)) {
|
||||
|
||||
++afl->queue_cur->stats_skipped;
|
||||
|
||||
} else {
|
||||
|
||||
if (unlikely(afl->queued_items > stat_prev_queued_items)) {
|
||||
|
||||
afl->queue_cur->stats_finds +=
|
||||
afl->queued_items - stat_prev_queued_items;
|
||||
stat_prev_queued_items = afl->queued_items;
|
||||
|
||||
}
|
||||
|
||||
if (unlikely(afl->saved_crashes > prev_saved_crashes)) {
|
||||
|
||||
afl->queue_cur->stats_crashes +=
|
||||
afl->saved_crashes - prev_saved_crashes;
|
||||
prev_saved_crashes = afl->saved_crashes;
|
||||
|
||||
}
|
||||
|
||||
if (unlikely(afl->saved_tmouts > prev_saved_tmouts)) {
|
||||
|
||||
afl->queue_cur->stats_tmouts += afl->saved_tmouts - prev_saved_tmouts;
|
||||
prev_saved_tmouts = afl->saved_tmouts;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (unlikely(!afl->stop_soon && exit_1)) { afl->stop_soon = 2; }
|
||||
|
||||
if (unlikely(afl->old_seed_selection)) {
|
||||
|
||||
while (++afl->current_entry < afl->queued_items &&
|
||||
afl->queue_buf[afl->current_entry]->disabled) {};
|
||||
if (unlikely(afl->current_entry >= afl->queued_items ||
|
||||
afl->queue_buf[afl->current_entry] == NULL ||
|
||||
afl->queue_buf[afl->current_entry]->disabled)) {
|
||||
|
||||
afl->queue_cur = NULL;
|
||||
++afl->queue_cur->stats_skipped;
|
||||
|
||||
} else {
|
||||
|
||||
afl->queue_cur = afl->queue_buf[afl->current_entry];
|
||||
if (unlikely(afl->queued_items > stat_prev_queued_items)) {
|
||||
|
||||
afl->queue_cur->stats_finds +=
|
||||
afl->queued_items - stat_prev_queued_items;
|
||||
stat_prev_queued_items = afl->queued_items;
|
||||
|
||||
}
|
||||
|
||||
if (unlikely(afl->saved_crashes > prev_saved_crashes)) {
|
||||
|
||||
afl->queue_cur->stats_crashes +=
|
||||
afl->saved_crashes - prev_saved_crashes;
|
||||
prev_saved_crashes = afl->saved_crashes;
|
||||
|
||||
}
|
||||
|
||||
if (unlikely(afl->saved_tmouts > prev_saved_tmouts)) {
|
||||
|
||||
afl->queue_cur->stats_tmouts +=
|
||||
afl->saved_tmouts - prev_saved_tmouts;
|
||||
prev_saved_tmouts = afl->saved_tmouts;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
} while (skipped_fuzz && afl->queue_cur && !afl->stop_soon);
|
||||
if (unlikely(!afl->stop_soon && exit_1)) { afl->stop_soon = 2; }
|
||||
|
||||
if (unlikely(afl->old_seed_selection)) {
|
||||
|
||||
while (++afl->current_entry < afl->queued_items &&
|
||||
afl->queue_buf[afl->current_entry]->disabled) {};
|
||||
if (unlikely(afl->current_entry >= afl->queued_items ||
|
||||
afl->queue_buf[afl->current_entry] == NULL ||
|
||||
afl->queue_buf[afl->current_entry]->disabled)) {
|
||||
|
||||
afl->queue_cur = NULL;
|
||||
|
||||
} else {
|
||||
|
||||
afl->queue_cur = afl->queue_buf[afl->current_entry];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} while (skipped_fuzz && afl->queue_cur && !afl->stop_soon);
|
||||
|
||||
}
|
||||
|
||||
u64 cur_time = get_cur_time();
|
||||
|
||||
|
@ -71,7 +71,6 @@ void afl_shm_deinit(sharedmem_t *shm) {
|
||||
if (shm->shmemfuzz_mode) {
|
||||
|
||||
unsetenv(SHM_FUZZ_ENV_VAR);
|
||||
unsetenv(SHM_FUZZ_MAP_SIZE_ENV_VAR);
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -714,8 +714,61 @@ static void handle_stop_sig(int sig) {
|
||||
|
||||
static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
|
||||
|
||||
char *afl_preload;
|
||||
char *frida_afl_preload = NULL;
|
||||
|
||||
set_sanitizer_defaults();
|
||||
afl_fsrv_setup_preload(fsrv, argv[0]);
|
||||
|
||||
if (get_afl_env("AFL_PRELOAD")) {
|
||||
|
||||
if (fsrv->qemu_mode) {
|
||||
|
||||
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
|
||||
|
||||
} else if (fsrv->frida_mode) {
|
||||
|
||||
afl_preload = getenv("AFL_PRELOAD");
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
if (afl_preload) {
|
||||
|
||||
frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
|
||||
|
||||
} else {
|
||||
|
||||
frida_afl_preload = alloc_printf("%s", frida_binary);
|
||||
|
||||
}
|
||||
|
||||
ck_free(frida_binary);
|
||||
|
||||
setenv("LD_PRELOAD", frida_afl_preload, 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
|
||||
/* CoreSight mode uses the default behavior. */
|
||||
|
||||
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
} else if (fsrv->frida_mode) {
|
||||
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
setenv("LD_PRELOAD", frida_binary, 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
|
||||
#endif
|
||||
ck_free(frida_binary);
|
||||
|
||||
}
|
||||
|
||||
if (frida_afl_preload) { ck_free(frida_afl_preload); }
|
||||
|
||||
}
|
||||
|
||||
@ -1208,6 +1261,8 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
break;
|
||||
|
||||
/* FIXME: We want to use -P for consistency, but it is already unused for
|
||||
* undocumenetd feature "Another afl-cmin specific feature." */
|
||||
case 'A': /* CoreSight mode */
|
||||
|
||||
#if !defined(__aarch64__) || !defined(__linux__)
|
||||
@ -1487,15 +1542,9 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
shm_fuzz->cmplog_mode = 0;
|
||||
atexit(at_exit_handler);
|
||||
|
||||
size_t shm_fuzz_map_size = SHM_FUZZ_MAP_SIZE_DEFAULT;
|
||||
u8 *map = afl_shm_init(shm_fuzz, shm_fuzz_map_size, 1);
|
||||
u8 *map = afl_shm_init(shm_fuzz, MAX_FILE + sizeof(u32), 1);
|
||||
shm_fuzz->shmemfuzz_mode = true;
|
||||
if (!map) { FATAL("BUG: Zero return from afl_shm_init."); }
|
||||
|
||||
u8 *shm_fuzz_map_size_str = alloc_printf("%zu", shm_fuzz_map_size);
|
||||
setenv(SHM_FUZZ_MAP_SIZE_ENV_VAR, shm_fuzz_map_size_str, 1);
|
||||
ck_free(shm_fuzz_map_size_str);
|
||||
|
||||
#ifdef USEMMAP
|
||||
setenv(SHM_FUZZ_ENV_VAR, shm_fuzz->g_shm_file_path, 1);
|
||||
#else
|
||||
@ -1542,7 +1591,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
// only reinitialize when it makes sense
|
||||
if (map_size < new_map_size ||
|
||||
(new_map_size < map_size && map_size - new_map_size > MAP_SIZE)) {
|
||||
(new_map_size > map_size && new_map_size - map_size > MAP_SIZE)) {
|
||||
|
||||
if (!be_quiet)
|
||||
ACTF("Acquired new map size for target: %u bytes\n", new_map_size);
|
||||
|
@ -899,7 +899,9 @@ static void handle_stop_sig(int sig) {
|
||||
|
||||
static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
|
||||
|
||||
u8 *x;
|
||||
u8 *x;
|
||||
char *afl_preload;
|
||||
char *frida_afl_preload = NULL;
|
||||
|
||||
fsrv->dev_null_fd = open("/dev/null", O_RDWR);
|
||||
if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
|
||||
@ -943,7 +945,57 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
|
||||
}
|
||||
|
||||
set_sanitizer_defaults();
|
||||
afl_fsrv_setup_preload(fsrv, argv[0]);
|
||||
|
||||
if (get_afl_env("AFL_PRELOAD")) {
|
||||
|
||||
if (fsrv->qemu_mode) {
|
||||
|
||||
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
|
||||
|
||||
} else if (fsrv->frida_mode) {
|
||||
|
||||
afl_preload = getenv("AFL_PRELOAD");
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
if (afl_preload) {
|
||||
|
||||
frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
|
||||
|
||||
} else {
|
||||
|
||||
frida_afl_preload = alloc_printf("%s", frida_binary);
|
||||
|
||||
}
|
||||
|
||||
ck_free(frida_binary);
|
||||
|
||||
setenv("LD_PRELOAD", frida_afl_preload, 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
|
||||
/* CoreSight mode uses the default behavior. */
|
||||
|
||||
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
} else if (fsrv->frida_mode) {
|
||||
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
setenv("LD_PRELOAD", frida_binary, 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
|
||||
#endif
|
||||
ck_free(frida_binary);
|
||||
|
||||
}
|
||||
|
||||
if (frida_afl_preload) { ck_free(frida_afl_preload); }
|
||||
|
||||
}
|
||||
|
||||
@ -1429,16 +1481,9 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
/* initialize cmplog_mode */
|
||||
shm_fuzz->cmplog_mode = 0;
|
||||
|
||||
size_t shm_fuzz_map_size = SHM_FUZZ_MAP_SIZE_DEFAULT;
|
||||
u8 *map = afl_shm_init(shm_fuzz, shm_fuzz_map_size, 1);
|
||||
u8 *map = afl_shm_init(shm_fuzz, MAX_FILE + sizeof(u32), 1);
|
||||
shm_fuzz->shmemfuzz_mode = 1;
|
||||
if (!map) { FATAL("BUG: Zero return from afl_shm_init."); }
|
||||
|
||||
u8 *shm_fuzz_map_size_str = alloc_printf("%zu", shm_fuzz_map_size);
|
||||
setenv(SHM_FUZZ_MAP_SIZE_ENV_VAR, shm_fuzz_map_size_str, 1);
|
||||
ck_free(shm_fuzz_map_size_str);
|
||||
|
||||
#ifdef USEMMAP
|
||||
setenv(SHM_FUZZ_ENV_VAR, shm_fuzz->g_shm_file_path, 1);
|
||||
#else
|
||||
|
@ -49,11 +49,7 @@ int main(int argc, char **argv) {
|
||||
if ((cnt = read(fd, buf, sizeof(buf) - 1)) < 1) {
|
||||
|
||||
printf("Hum?\n");
|
||||
#ifdef EXIT_AT_END
|
||||
exit(1);
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@ -81,10 +77,6 @@ int main(int argc, char **argv) {
|
||||
|
||||
}
|
||||
|
||||
#ifdef EXIT_AT_END
|
||||
exit(0);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
@ -16,8 +16,7 @@ test -z "$AFL_CC" && {
|
||||
test -e ../afl-qemu-trace && {
|
||||
cc -pie -fPIE -o test-instr ../test-instr.c
|
||||
cc -o test-compcov test-compcov.c
|
||||
cc -pie -fPIE -o test-instr-exit-at-end -DEXIT_AT_END ../test-instr.c
|
||||
test -e test-instr -a -e test-compcov -a -e test-instr-exit-at-end && {
|
||||
test -e test-instr -a -e test-compcov && {
|
||||
{
|
||||
mkdir -p in
|
||||
echo 00000 > in/in
|
||||
@ -150,61 +149,9 @@ test -e ../afl-qemu-trace && {
|
||||
$ECHO "$RED[!] afl-fuzz is not working correctly with persistent qemu_mode"
|
||||
CODE=1
|
||||
}
|
||||
rm -rf out errors
|
||||
} || {
|
||||
$ECHO "$YELLOW[-] not an intel or arm platform, cannot test persistent qemu_mode"
|
||||
}
|
||||
|
||||
test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" && {
|
||||
$ECHO "$GREY[*] running afl-fuzz for persistent qemu_mode with AFL_QEMU_PERSISTENT_EXITS, this will take approx 10 seconds"
|
||||
{
|
||||
IS_STATIC=""
|
||||
file test-instr-exit-at-end | grep -q 'statically linked' && IS_STATIC=1
|
||||
test -z "$IS_STATIC" && {
|
||||
if file test-instr-exit-at-end | grep -q "32-bit"; then
|
||||
# for 32-bit reduce 8 nibbles to the lower 7 nibbles
|
||||
ADDR_LOWER_PART=`nm test-instr-exit-at-end | grep "T main" | awk '{print $1}' | sed 's/^.//'`
|
||||
else
|
||||
# for 64-bit reduce 16 nibbles to the lower 9 nibbles
|
||||
ADDR_LOWER_PART=`nm test-instr-exit-at-end | grep "T main" | awk '{print $1}' | sed 's/^.......//'`
|
||||
fi
|
||||
export AFL_QEMU_PERSISTENT_ADDR=`expr 0x4${ADDR_LOWER_PART}`
|
||||
}
|
||||
test -n "$IS_STATIC" && {
|
||||
export AFL_QEMU_PERSISTENT_ADDR=0x`nm test-instr-exit-at-end | grep "T main" | awk '{print $1}'`
|
||||
}
|
||||
export AFL_QEMU_PERSISTENT_GPR=1
|
||||
$ECHO "Info: AFL_QEMU_PERSISTENT_ADDR=$AFL_QEMU_PERSISTENT_ADDR <= $(nm test-instr-exit-at-end | grep "T main" | awk '{print $1}')"
|
||||
export AFL_QEMU_PERSISTENT_EXITS=1
|
||||
../afl-fuzz -m ${MEM_LIMIT} -V07 -Q -i in -o out -- ./test-instr-exit-at-end
|
||||
echo status "$?"
|
||||
unset AFL_QEMU_PERSISTENT_ADDR
|
||||
unset AFL_QEMU_PERSISTENT_GPR
|
||||
unset AFL_QEMU_PERSISTENT_EXITS
|
||||
} >>errors 2>&1
|
||||
test -n "$( ls out/default/queue/id:000000* 2>/dev/null )" && {
|
||||
$ECHO "$GREEN[+] afl-fuzz is working correctly with persistent qemu_mode and AFL_QEMU_PERSISTENT_EXITS"
|
||||
RUNTIMEP_EXIT=`grep execs_done out/default/fuzzer_stats | awk '{print$3}'`
|
||||
test -n "$RUNTIME" -a -n "$RUNTIMEP_EXIT" && {
|
||||
DIFF=`expr $RUNTIMEP_EXIT / $RUNTIME`
|
||||
test "$DIFF" -gt 1 && { # must be at least twice as fast
|
||||
$ECHO "$GREEN[+] persistent qemu_mode with AFL_QEMU_PERSISTENT_EXITS was noticeable faster than standard qemu_mode"
|
||||
} || {
|
||||
$ECHO "$YELLOW[-] persistent qemu_mode with AFL_QEMU_PERSISTENT_EXITS was not noticeable faster than standard qemu_mode"
|
||||
}
|
||||
} || {
|
||||
$ECHO "$YELLOW[-] we got no data on executions performed? weird!"
|
||||
}
|
||||
} || {
|
||||
echo CUT------------------------------------------------------------------CUT
|
||||
cat errors
|
||||
echo CUT------------------------------------------------------------------CUT
|
||||
$ECHO "$RED[!] afl-fuzz is not working correctly with persistent qemu_mode and AFL_QEMU_PERSISTENT_EXITS"
|
||||
CODE=1
|
||||
}
|
||||
rm -rf in out errors
|
||||
} || {
|
||||
$ECHO "$YELLOW[-] not an intel or arm platform, cannot test persistent qemu_mode with AFL_QEMU_PERSISTENT_EXITS"
|
||||
$ECHO "$YELLOW[-] not an intel or arm platform, cannot test persistent qemu_mode"
|
||||
}
|
||||
|
||||
test -e ../qemu_mode/unsigaction/unsigaction32.so && {
|
||||
@ -265,7 +212,7 @@ test -e ../afl-qemu-trace && {
|
||||
CODE=1
|
||||
}
|
||||
|
||||
rm -f test-instr test-compcov test-instr-exit-at-end
|
||||
rm -f test-instr test-compcov
|
||||
} || {
|
||||
$ECHO "$YELLOW[-] qemu_mode is not compiled, cannot test"
|
||||
INCOMPLETE=1
|
||||
|
@ -18,8 +18,7 @@ ifneq "" "$(LLVM_BINDIR)"
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS := -O3 -funroll-loops -g -fPIC -fno-lto
|
||||
AR ?= ar
|
||||
CFLAGS := -O3 -funroll-loops -g -fPIC
|
||||
|
||||
ifdef IOS_SDK_PATH
|
||||
CFLAGS += -isysroot $(IOS_SDK_PATH)
|
||||
@ -31,7 +30,7 @@ aflpp_driver.o: aflpp_driver.c
|
||||
-$(CC) -I. -I../../include $(CFLAGS) -c aflpp_driver.c
|
||||
|
||||
libAFLDriver.a: aflpp_driver.o
|
||||
@$(AR) rc libAFLDriver.a aflpp_driver.o
|
||||
@ar rc libAFLDriver.a aflpp_driver.o
|
||||
@cp -vf libAFLDriver.a ../../
|
||||
|
||||
debug:
|
||||
@ -39,13 +38,13 @@ debug:
|
||||
$(CC) -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c
|
||||
#$(CC) -S -emit-llvm -Wno-deprecated -I../../include $(CFLAGS) -D_DEBUG=\"1\" -c -o afl-performance.ll ../../src/afl-performance.c
|
||||
#$(CC) -S -emit-llvm -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c
|
||||
$(AR) rc libAFLDriver.a afl-performance.o aflpp_driver.o
|
||||
ar rc libAFLDriver.a afl-performance.o aflpp_driver.o
|
||||
|
||||
aflpp_qemu_driver.o: aflpp_qemu_driver.c
|
||||
-$(CC) $(CFLAGS) -O0 -funroll-loops -c aflpp_qemu_driver.c
|
||||
|
||||
libAFLQemuDriver.a: aflpp_qemu_driver.o
|
||||
@-$(AR) rc libAFLQemuDriver.a aflpp_qemu_driver.o
|
||||
@-ar rc libAFLQemuDriver.a aflpp_qemu_driver.o
|
||||
@-cp -vf libAFLQemuDriver.a ../../
|
||||
|
||||
aflpp_qemu_driver_hook.so: aflpp_qemu_driver_hook.o
|
||||
|
@ -64,15 +64,6 @@ extern "C" {
|
||||
#include "hash.h"
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
#define SECTION_RODATA \
|
||||
__attribute__((used, retain)) __attribute__((section("__RODATA,__" \
|
||||
"rodata")))
|
||||
#else
|
||||
#define SECTION_RODATA \
|
||||
__attribute__((used, retain)) __attribute__((section(".rodata")))
|
||||
#endif
|
||||
|
||||
// AFL++ shared memory fuzz cases
|
||||
int __afl_sharedmem_fuzzing = 1;
|
||||
extern unsigned int *__afl_fuzz_len;
|
||||
@ -115,11 +106,14 @@ __attribute__((weak)) void __asan_unpoison_memory_region(
|
||||
__attribute__((weak)) void *__asan_region_is_poisoned(void *beg, size_t size);
|
||||
|
||||
// Notify AFL about persistent mode.
|
||||
SECTION_RODATA static const char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
|
||||
int __afl_persistent_loop(unsigned int);
|
||||
__attribute__((section(".rodata"), used,
|
||||
retain)) static const char AFL_PERSISTENT[] =
|
||||
"##SIG_AFL_PERSISTENT##";
|
||||
int __afl_persistent_loop(unsigned int);
|
||||
|
||||
// Notify AFL about deferred forkserver.
|
||||
SECTION_RODATA static const char AFL_DEFER_FORKSVR[] =
|
||||
__attribute__((section(".rodata"), used,
|
||||
retain)) static const char AFL_DEFER_FORKSVR[] =
|
||||
"##SIG_AFL_DEFER_FORKSRV##";
|
||||
void __afl_manual_init();
|
||||
|
||||
|
@ -1,12 +0,0 @@
|
||||
|
||||
# For cross compilation modify this as needed
|
||||
#GLIBC_PATH := /path/to/glibc-2.xx/build/local_install
|
||||
#CROSS_CFLAGS := -mfloat-abi=soft -nostdlib -I$(GLIBC_PATH)/include -L$(GLIBC_PATH)/lib -Wl,-rpath=/lib -Wl,--dynamic-linker=/lib/ld-linux.so.3
|
||||
|
||||
all: libaflppdesock.so
|
||||
|
||||
libaflppdesock.so: libaflppdesock.c
|
||||
$(CC) $(CROSS_CFLAGS) -shared -fPIC -o libaflppdesock.so libaflppdesock.c
|
||||
|
||||
clean:
|
||||
rm -f libaflppdesock.so *~ core
|
@ -1,46 +0,0 @@
|
||||
# AFL++ TCP desocket library
|
||||
|
||||
Other desocketing solutions:
|
||||
* https://github.com/zardus/preeny (desock and desock2)
|
||||
* https://github.com/fkie-cad/libdesock
|
||||
* https://github.com/zyingp/desockmulti
|
||||
* https://github.com/vanhauser-thc/network-emulator
|
||||
|
||||
If these desocket solutions fail, then this one will likely easily work
|
||||
for you - alass with slightly lower performance.
|
||||
And it is easy to extend :-)
|
||||
|
||||
## Why might this solution work when others do not?
|
||||
|
||||
What makes this desocket library special is that only **only** intercepts
|
||||
`accept()` calls bound to a specified port. Hence any other network stuff
|
||||
the application does is still working as expected.
|
||||
|
||||
## How to use
|
||||
|
||||
`AFL_PRELOAD` this library and use the following environment variables:
|
||||
|
||||
* `DESOCK_PORT=8080` - required for intercepting incoming connections for fuzzing - sets the TCP port
|
||||
* `DESOCK_FORK=1` - intercept and prevent forking
|
||||
* `DESOCK_CLOSE_EXIT=1` - call _exit() when the desocketed file descriptor is `close`d or `shutdown`ed
|
||||
* `DESOCK_DEBUG=1` - print debug information to `stderr`
|
||||
|
||||
** Internals
|
||||
|
||||
Currently the library intercepts the following calls:
|
||||
|
||||
```
|
||||
shutdown
|
||||
close
|
||||
fork
|
||||
accept
|
||||
accept4
|
||||
listen
|
||||
bind
|
||||
setsockopt
|
||||
getsockopt
|
||||
getpeername
|
||||
getsockname
|
||||
```
|
||||
|
||||
`
|
@ -1,352 +0,0 @@
|
||||
/* desocket library by Marc "vanHauser" Heuse <vh@thc.org>
|
||||
*
|
||||
* Use this library for fuzzing if preeny's desock and desock2 solutions
|
||||
* do not work for you - these would provide faster performance.
|
||||
*
|
||||
*/
|
||||
|
||||
// default: file descriptor 0 for stdin
|
||||
#define FUZZ_INPUT_FD 0
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void *handle;
|
||||
static bool do_fork, do_close, debug, running;
|
||||
static int port = -1;
|
||||
static int listen_fd = -1;
|
||||
|
||||
struct myin_addr {
|
||||
|
||||
unsigned int s_addr; // IPv4 address in network byte order
|
||||
|
||||
};
|
||||
|
||||
struct mysockaddr {
|
||||
|
||||
unsigned short int sin_family; // Address family: AF_INET
|
||||
unsigned short int sin_port; // Port number (network byte order)
|
||||
struct myin_addr sin_addr; // Internet address
|
||||
char sin_zero[8]; // Padding (unused)
|
||||
|
||||
};
|
||||
|
||||
#define RTLD_LAZY 0x00001
|
||||
|
||||
unsigned short int htons(unsigned short int hostshort) {
|
||||
|
||||
return (hostshort << 8) | (hostshort >> 8);
|
||||
|
||||
}
|
||||
|
||||
static void __get_handle() {
|
||||
|
||||
if (!(handle = dlopen("libc.so", RTLD_NOW))) {
|
||||
|
||||
if (!(handle = dlopen("libc.so.6", RTLD_NOW))) {
|
||||
|
||||
if (!(handle = dlopen("libc-orig.so", RTLD_LAZY))) {
|
||||
|
||||
if (!(handle = dlopen("cygwin1.dll", RTLD_LAZY))) {
|
||||
|
||||
if (!(handle = dlopen("libc.so", RTLD_NOW))) {
|
||||
|
||||
fprintf(stderr, "DESOCK: can not find libc!\n");
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (getenv("DESOCK_DEBUG")) { debug = true; }
|
||||
if (getenv("DESOCK_PORT")) { port = atoi(getenv("DESOCK_PORT")); }
|
||||
if (getenv("DESOCK_FORK")) { do_fork = true; }
|
||||
if (getenv("DESOCK_CLOSE_EXIT")) { do_close = true; }
|
||||
if (debug) fprintf(stderr, "DESOCK: initialized!\n");
|
||||
|
||||
}
|
||||
|
||||
int (*o_shutdown)(int socket, int how);
|
||||
int shutdown(int socket, int how) {
|
||||
|
||||
if (port != -1 && socket == FUZZ_INPUT_FD && running) {
|
||||
|
||||
running = false;
|
||||
if (do_close) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: exiting\n");
|
||||
_exit(0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (port == -1 && do_close) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: exiting\n");
|
||||
_exit(0);
|
||||
|
||||
}
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_shutdown) { o_shutdown = dlsym(handle, "shutdown"); }
|
||||
return o_shutdown(socket, how);
|
||||
|
||||
}
|
||||
|
||||
int (*o_close)(int socket);
|
||||
int close(int socket) {
|
||||
|
||||
if (port != -1 && socket == FUZZ_INPUT_FD && running) {
|
||||
|
||||
running = false;
|
||||
if (do_close) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: exiting\n");
|
||||
_exit(0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (listen_fd != -1 && socket == listen_fd) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: close bind\n");
|
||||
listen_fd = -1;
|
||||
|
||||
}
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_close) { o_close = dlsym(handle, "close"); }
|
||||
return o_close(socket);
|
||||
|
||||
}
|
||||
|
||||
int (*o_fork)(void);
|
||||
int fork() {
|
||||
|
||||
if (do_fork) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: fake fork\n");
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_fork) { o_fork = dlsym(handle, "fork"); }
|
||||
return o_fork();
|
||||
|
||||
}
|
||||
|
||||
int (*o_accept)(int sockfd, struct mysockaddr *addr,
|
||||
unsigned long int *addrlen);
|
||||
int accept(int sockfd, struct mysockaddr *addr, unsigned long int *addrlen) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_accept) { o_accept = dlsym(handle, "accept"); }
|
||||
if (!running && sockfd == listen_fd) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: intercepted accept on %d\n", sockfd);
|
||||
if (addr && addrlen) {
|
||||
|
||||
// we need to fill this!
|
||||
memset(addr, 0, *addrlen);
|
||||
addr->sin_family = 2; // AF_INET
|
||||
addr->sin_port = htons(1023); // Port 1023 in network byte order
|
||||
addr->sin_addr.s_addr = 0x0100007f;
|
||||
|
||||
}
|
||||
|
||||
running = true;
|
||||
return FUZZ_INPUT_FD;
|
||||
|
||||
}
|
||||
|
||||
return o_accept(sockfd, addr, addrlen);
|
||||
|
||||
}
|
||||
|
||||
int accept4(int sockfd, struct mysockaddr *addr, unsigned long int *addrlen,
|
||||
int flags) {
|
||||
|
||||
return accept(sockfd, addr, addrlen); // ignore flags
|
||||
|
||||
}
|
||||
|
||||
int (*o_listen)(int sockfd, int backlog);
|
||||
int listen(int sockfd, int backlog) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_listen) { o_listen = dlsym(handle, "listen"); }
|
||||
if (sockfd == listen_fd) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: intercepted listen on %d\n", sockfd);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return o_listen(sockfd, backlog);
|
||||
|
||||
}
|
||||
|
||||
int (*o_bind)(int sockfd, const struct mysockaddr *addr,
|
||||
unsigned long int addrlen);
|
||||
int bind(int sockfd, const struct mysockaddr *addr, unsigned long int addrlen) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_bind) { o_bind = dlsym(handle, "bind"); }
|
||||
if (addr->sin_port == htons(port)) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: intercepted bind on %d\n", sockfd);
|
||||
listen_fd = sockfd;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return o_bind(sockfd, addr, addrlen);
|
||||
|
||||
}
|
||||
|
||||
int (*o_setsockopt)(int sockfd, int level, int optname, const void *optval,
|
||||
unsigned long int optlen);
|
||||
int setsockopt(int sockfd, int level, int optname, const void *optval,
|
||||
unsigned long int optlen) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_setsockopt) { o_setsockopt = dlsym(handle, "setsockopt"); }
|
||||
if (listen_fd == sockfd) {
|
||||
|
||||
if (debug)
|
||||
fprintf(stderr, "DESOCK: intercepted setsockopt on %d for %d\n", sockfd,
|
||||
optname);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return o_setsockopt(sockfd, level, optname, optval, optlen);
|
||||
|
||||
}
|
||||
|
||||
int (*o_getsockopt)(int sockfd, int level, int optname, void *optval,
|
||||
unsigned long int *optlen);
|
||||
int getsockopt(int sockfd, int level, int optname, void *optval,
|
||||
unsigned long int *optlen) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_getsockopt) { o_getsockopt = dlsym(handle, "getsockopt"); }
|
||||
if (listen_fd == sockfd) {
|
||||
|
||||
if (debug)
|
||||
fprintf(stderr, "DESOCK: intercepted getsockopt on %d for %d\n", sockfd,
|
||||
optname);
|
||||
int *o = (int *)optval;
|
||||
if (o != NULL) {
|
||||
|
||||
*o = 1; // let's hope this is fine
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return o_getsockopt(sockfd, level, optname, optval, optlen);
|
||||
|
||||
}
|
||||
|
||||
int (*o_getpeername)(int sockfd, struct mysockaddr *addr,
|
||||
unsigned long int *addrlen);
|
||||
int getpeername(int sockfd, struct mysockaddr *addr,
|
||||
unsigned long int *addrlen) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_getpeername) { o_getpeername = dlsym(handle, "getpeername"); }
|
||||
if (port != -1 && sockfd == FUZZ_INPUT_FD) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: getpeername\n");
|
||||
if (addr && addrlen) {
|
||||
|
||||
// we need to fill this!
|
||||
memset(addr, 0, *addrlen);
|
||||
addr->sin_family = 2; // AF_INET
|
||||
addr->sin_port = htons(1023); // Port 1023 in network byte order
|
||||
addr->sin_addr.s_addr = 0x0100007f;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return o_getpeername(sockfd, addr, addrlen);
|
||||
|
||||
}
|
||||
|
||||
int (*o_getsockname)(int sockfd, struct mysockaddr *addr,
|
||||
unsigned long int *addrlen);
|
||||
int getsockname(int sockfd, struct mysockaddr *addr,
|
||||
unsigned long int *addrlen) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_getsockname) { o_getsockname = dlsym(handle, "getsockname"); }
|
||||
if (port != -1 && sockfd == FUZZ_INPUT_FD) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: getsockname\n");
|
||||
if (addr && addrlen) {
|
||||
|
||||
// we need to fill this!
|
||||
memset(addr, 0, *addrlen);
|
||||
addr->sin_family = 2; // AF_INET
|
||||
addr->sin_port = htons(port);
|
||||
addr->sin_addr.s_addr = 0x0100007f;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return o_getsockname(sockfd, addr, addrlen);
|
||||
|
||||
}
|
||||
|
||||
static FILE *(*o_fdopen)(int fd, const char *mode);
|
||||
FILE *fdopen(int fd, const char *mode) {
|
||||
|
||||
if (!o_fdopen) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
|
||||
o_fdopen = dlsym(handle, "fdopen");
|
||||
if (!o_fdopen) {
|
||||
|
||||
fprintf(stderr, "%s(): can not find fdopen\n", dlerror());
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (fd == FUZZ_INPUT_FD && strcmp(mode, "r") != 0) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: intercepted fdopen(r+) for %d\n", fd);
|
||||
return o_fdopen(fd, "r");
|
||||
|
||||
}
|
||||
|
||||
return o_fdopen(fd, mode);
|
||||
|
||||
}
|
||||
|
||||
/* TARGET SPECIFIC HOOKS - put extra needed code for your target here */
|
||||
|
@ -19,11 +19,11 @@ HELPER_PATH = $(PREFIX)/lib/afl
|
||||
VERSION = $(shell grep '^\#define VERSION ' ../../config.h | cut -d '"' -f2)
|
||||
|
||||
CFLAGS ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2
|
||||
override CFLAGS += -I ../../include/ -Wall -g -Wno-pointer-sign
|
||||
CFLAGS += -I ../../include/ -Wall -g -Wno-pointer-sign
|
||||
|
||||
CFLAGS_ADD=$(USEHUGEPAGE:1=-DUSEHUGEPAGE)
|
||||
CFLAGS_ADD += $(USENAMEDPAGE:1=-DUSENAMEDPAGE)
|
||||
override CFLAGS += $(CFLAGS_ADD)
|
||||
CFLAGS += $(CFLAGS_ADD)
|
||||
|
||||
all: libdislocator.so
|
||||
|
||||
@ -41,3 +41,4 @@ install: all
|
||||
install -m 755 -d $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 755 ../../libdislocator.so $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 644 -T README.md $${DESTDIR}$(HELPER_PATH)/README.dislocator.md
|
||||
|
||||
|
Reference in New Issue
Block a user