Compare commits

..

3 Commits
stable ... g2

Author SHA1 Message Date
fe218d65ea add G2 python scripts 2025-04-24 15:46:21 +02:00
c504fb2189 Merge pull request #2396 from AFLplusplus/dev
fix for nit in afl-tmin
2025-04-24 15:02:25 +02:00
a6bcd99aec G2 integration 2025-04-24 14:59:13 +02:00
66 changed files with 5244 additions and 2751 deletions

View File

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

View File

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

View File

@ -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
View 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, youll 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.

View File

@ -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>
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/AFLplusplus/AFLplusplus)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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:
********************
```

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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"]);

View File

@ -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]");

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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"); }
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -1 +1 @@
c43dd6e036
ef1cd9a8cb

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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