mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-24 22:53:24 +00:00
Compare commits
133 Commits
Author | SHA1 | Date | |
---|---|---|---|
16cc444ae5 | |||
a9900f02cb | |||
e82de006a7 | |||
4a923e59fd | |||
20348a63bd | |||
cafcb343b1 | |||
588dda3e84 | |||
a17d1daab8 | |||
affe7cf5b4 | |||
fa1ac051eb | |||
f21cc2da58 | |||
8c1ab19ebe | |||
2e7f191f3b | |||
8090c82c63 | |||
f610f53838 | |||
0012f710d8 | |||
be00ea9f00 | |||
d0df78f07a | |||
7e1dc85450 | |||
8152def40e | |||
e6ed31d550 | |||
77758a1343 | |||
ea1fbb75b3 | |||
d62a885f0f | |||
55d534cd6d | |||
cee764689c | |||
d02390e62e | |||
1f878f1b7c | |||
ff1e0580b0 | |||
4730fa4226 | |||
50fb923691 | |||
300fc1f002 | |||
4ff40ee6fd | |||
c3d5f3f471 | |||
45a7d65207 | |||
b8d1f16979 | |||
c699aa252d | |||
7c27fc7cfe | |||
46b9efbf7d | |||
92d1a60096 | |||
f90fafc07a | |||
59c2198532 | |||
c7654c028d | |||
ccc7ab5944 | |||
06afa48e02 | |||
816334000a | |||
2573ccb66e | |||
767b990af6 | |||
1631e5988f | |||
3ee3b5c384 | |||
7f7d5ff29b | |||
6dcd0aa089 | |||
c47221db7c | |||
d6bb210410 | |||
c2a026f68f | |||
2a97350754 | |||
9004be20b8 | |||
dffd6537ae | |||
25d7d65216 | |||
7a32331c99 | |||
b27e861a51 | |||
875c3902f0 | |||
bedb38e216 | |||
ef0c236427 | |||
b6d1247e7d | |||
62e63d1125 | |||
9e4449bad2 | |||
6d4a56e481 | |||
221439fc7a | |||
fca39a6ec3 | |||
9476204da0 | |||
919108ee57 | |||
8204bf6915 | |||
b9e361df46 | |||
19fc27a3f7 | |||
2357daebe0 | |||
f3995d5225 | |||
ea6d182b4a | |||
adeaa714ce | |||
231a4b1937 | |||
977e08cda1 | |||
6b1d6a9055 | |||
4d9d8aaf16 | |||
c150d8e17d | |||
61e97a8ceb | |||
3f2e03aaf9 | |||
406e4880c7 | |||
22b7d370bc | |||
ec27e96486 | |||
fcca917f4f | |||
5bf01afd6b | |||
0a9916deab | |||
b1730d99b6 | |||
6d45b286f8 | |||
673463ff1c | |||
f580fefc5f | |||
320d4b7ef8 | |||
19bd2984d5 | |||
7d29418db5 | |||
4d984d6e2b | |||
421b6492d3 | |||
062f883160 | |||
a76ff5e798 | |||
e9f49527e9 | |||
6f4767ea81 | |||
d28b1418a2 | |||
d10b85421d | |||
6876ab7901 | |||
b1649f2fdb | |||
701299eefd | |||
90e929ea17 | |||
24dc7b569c | |||
7cb8ccc960 | |||
0c4f8934c7 | |||
cd0cb1e731 | |||
52631d925d | |||
d40f935b4e | |||
b418a87340 | |||
04f2a2dd09 | |||
aa1c58a077 | |||
cca5538747 | |||
c4be2ec32f | |||
83a2a8aa14 | |||
6c70d68783 | |||
6d5784e955 | |||
5f7009d6e9 | |||
48bce88050 | |||
f43116d9e0 | |||
876a528156 | |||
8a0e9c8915 | |||
b083016304 | |||
30c93d1321 | |||
e30a17be91 |
18
GNUmakefile
18
GNUmakefile
@ -31,7 +31,7 @@ PROGNAME = afl
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
|
||||
PROGS = afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
|
||||
SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-addseeds afl-system-config afl-persistent-config afl-cc
|
||||
SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-cmin.py 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,14 +76,16 @@ ifdef IS_IOS
|
||||
endif
|
||||
|
||||
ifeq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
CFLAGS_FLTO ?= -flto
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@ -313,8 +315,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
|
||||
ASAN_LDFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
|
||||
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
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
|
@ -148,7 +148,7 @@ afl-common.o: ./src/afl-common.c
|
||||
$(PASSES): instrumentation/afl-gcc-common.h
|
||||
|
||||
./afl-gcc-pass.so: instrumentation/afl-gcc-pass.so.cc | test_deps
|
||||
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
|
||||
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@ $(LDFLAGS)
|
||||
ln -sf afl-cc afl-gcc-fast
|
||||
ln -sf afl-cc afl-g++-fast
|
||||
ln -sf afl-cc.8 afl-gcc-fast.8
|
||||
|
@ -32,8 +32,8 @@ VERSION = $(shell grep '^ *$(HASH)define VERSION ' ./config.h | cut -d '"' -
|
||||
|
||||
SYS = $(shell uname -s)
|
||||
|
||||
override LLVM_TOO_NEW_DEFAULT := 19
|
||||
override LLVM_TOO_OLD_DEFAULT := 13
|
||||
override LLVM_TOO_NEW_DEFAULT := 21
|
||||
override LLVM_TOO_OLD_DEFAULT := 14
|
||||
|
||||
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[1-9]\.' && echo 1 || echo 0)
|
||||
LLVM_UNSUPPORTED := $(shell echo "$(LLVMVER)" | grep -E -q '^[0-2]\.|^3\.[0-7]\.|^2[2-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 $@
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ $(LDFLAGS)
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
Release version: [4.32c](https://github.com/AFLplusplus/AFLplusplus/releases)
|
||||
|
||||
GitHub version: 4.32c
|
||||
GitHub version: 4.33a
|
||||
|
||||
Repository:
|
||||
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
||||
@ -230,7 +230,7 @@ Thank you! (For people sending pull requests - please add yourself to this list
|
||||
fuzzah @intrigus-lgtm
|
||||
Yaakov Saxon Sergej Schumilo
|
||||
Ziqiao Kong Ryan Berger
|
||||
Sangjun Park
|
||||
Sangjun Park Scott Guest
|
||||
```
|
||||
|
||||
</details>
|
||||
@ -259,3 +259,5 @@ presented at WOOT'20:
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
[](https://deepwiki.com/AFLplusplus/AFLplusplus)
|
||||
|
9
afl-cmin
9
afl-cmin
@ -1,12 +1,19 @@
|
||||
#!/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
|
||||
|
760
afl-cmin.py
Executable file
760
afl-cmin.py
Executable file
@ -0,0 +1,760 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright 2016-2025 Google Inc.
|
||||
# Copyright 2025 AFLplusplus Project. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
import argparse
|
||||
import array
|
||||
import base64
|
||||
import collections
|
||||
import glob
|
||||
import hashlib
|
||||
import itertools
|
||||
import logging
|
||||
import multiprocessing
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
# https://more-itertools.readthedocs.io/en/stable/_modules/more_itertools/recipes.html#batched
|
||||
from sys import hexversion
|
||||
|
||||
def _batched(iterable, n, *, strict=False):
|
||||
"""Batch data into tuples of length *n*. If the number of items in
|
||||
*iterable* is not divisible by *n*:
|
||||
* The last batch will be shorter if *strict* is ``False``.
|
||||
* :exc:`ValueError` will be raised if *strict* is ``True``.
|
||||
|
||||
>>> list(batched('ABCDEFG', 3))
|
||||
[('A', 'B', 'C'), ('D', 'E', 'F'), ('G',)]
|
||||
|
||||
On Python 3.13 and above, this is an alias for :func:`itertools.batched`.
|
||||
"""
|
||||
if n < 1:
|
||||
raise ValueError('n must be at least one')
|
||||
iterator = iter(iterable)
|
||||
while batch := tuple(itertools.islice(iterator, n)):
|
||||
if strict and len(batch) != n:
|
||||
raise ValueError('batched(): incomplete batch')
|
||||
yield batch
|
||||
|
||||
|
||||
if hexversion >= 0x30D00A2: # pragma: no cover
|
||||
from itertools import batched as itertools_batched
|
||||
def batched(iterable, n, *, strict=False):
|
||||
return itertools_batched(iterable, n, strict=strict)
|
||||
else:
|
||||
batched = _batched
|
||||
|
||||
batched.__doc__ = _batched.__doc__
|
||||
|
||||
try:
|
||||
from tqdm import tqdm
|
||||
except ImportError:
|
||||
print('Hint: install python module "tqdm" to show progress bar')
|
||||
|
||||
class tqdm:
|
||||
|
||||
def __init__(self, data=None, *args, **argd):
|
||||
self.data = data
|
||||
|
||||
def __iter__(self):
|
||||
yield from self.data
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
pass
|
||||
|
||||
def update(self, *args):
|
||||
pass
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
cpu_count = multiprocessing.cpu_count()
|
||||
group = parser.add_argument_group("Required parameters")
|
||||
group.add_argument(
|
||||
"-i",
|
||||
dest="input",
|
||||
action="append",
|
||||
metavar="dir",
|
||||
required=True,
|
||||
help="input directory with the starting corpus",
|
||||
)
|
||||
group.add_argument(
|
||||
"-o",
|
||||
dest="output",
|
||||
metavar="dir",
|
||||
required=True,
|
||||
help="output directory for minimized files",
|
||||
)
|
||||
|
||||
group = parser.add_argument_group("Execution control settings")
|
||||
group.add_argument(
|
||||
"-f",
|
||||
dest="stdin_file",
|
||||
metavar="file",
|
||||
help="location read by the fuzzed program (stdin)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-m",
|
||||
dest="memory_limit",
|
||||
default="none",
|
||||
metavar="megs",
|
||||
type=lambda x: x if x == "none" else int(x),
|
||||
help="memory limit for child process (default: %(default)s)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-t",
|
||||
dest="time_limit",
|
||||
default=5000,
|
||||
metavar="msec",
|
||||
type=lambda x: x if x == "none" else int(x),
|
||||
help="timeout for each run (default: %(default)s)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-O",
|
||||
dest="frida_mode",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="use binary-only instrumentation (FRIDA mode)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-Q",
|
||||
dest="qemu_mode",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="use binary-only instrumentation (QEMU mode)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-U",
|
||||
dest="unicorn_mode",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="use unicorn-based instrumentation (Unicorn mode)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-X", dest="nyx_mode", action="store_true", default=False, help="use Nyx mode"
|
||||
)
|
||||
|
||||
group = parser.add_argument_group("Minimization settings")
|
||||
group.add_argument(
|
||||
"--crash-dir",
|
||||
dest="crash_dir",
|
||||
metavar="dir",
|
||||
default=None,
|
||||
help="move crashes to a separate dir, always deduplicated",
|
||||
)
|
||||
group.add_argument(
|
||||
"-A",
|
||||
dest="allow_any",
|
||||
action="store_true",
|
||||
help="allow crashes and timeouts (not recommended)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-C",
|
||||
dest="crash_only",
|
||||
action="store_true",
|
||||
help="keep crashing inputs, reject everything else",
|
||||
)
|
||||
group.add_argument(
|
||||
"-e",
|
||||
dest="edge_mode",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="solve for edge coverage only, ignore hit counts",
|
||||
)
|
||||
|
||||
group = parser.add_argument_group("Misc")
|
||||
group.add_argument(
|
||||
"-T",
|
||||
dest="workers",
|
||||
type=lambda x: cpu_count if x == "all" else int(x),
|
||||
default=1,
|
||||
help="number of concurrent worker (default: %(default)d)",
|
||||
)
|
||||
group.add_argument(
|
||||
"--as_queue",
|
||||
action="store_true",
|
||||
help='output file name like "id:000000,hash:value"',
|
||||
)
|
||||
group.add_argument(
|
||||
"--no-dedup", action="store_true", help="skip deduplication step for corpus files"
|
||||
)
|
||||
group.add_argument("--debug", action="store_true")
|
||||
|
||||
parser.add_argument("exe", metavar="/path/to/target_app")
|
||||
parser.add_argument("args", nargs="*")
|
||||
|
||||
args = parser.parse_args()
|
||||
logger = None
|
||||
afl_showmap_bin = None
|
||||
tuple_index_type_code = "I"
|
||||
file_index_type_code = None
|
||||
|
||||
|
||||
def init():
|
||||
global logger
|
||||
log_level = logging.DEBUG if args.debug else logging.INFO
|
||||
logging.basicConfig(
|
||||
level=log_level, format="%(asctime)s - %(levelname)s - %(message)s"
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
if args.stdin_file and args.workers > 1:
|
||||
logger.error("-f is only supported with one worker (-T 1)")
|
||||
sys.exit(1)
|
||||
|
||||
if args.memory_limit != "none" and args.memory_limit < 5:
|
||||
logger.error("dangerously low memory limit")
|
||||
sys.exit(1)
|
||||
|
||||
if args.time_limit != "none" and args.time_limit < 10:
|
||||
logger.error("dangerously low timeout")
|
||||
sys.exit(1)
|
||||
|
||||
if not os.path.isfile(args.exe):
|
||||
logger.error('binary "%s" not found or not regular file', args.exe)
|
||||
sys.exit(1)
|
||||
|
||||
if not os.environ.get("AFL_SKIP_BIN_CHECK") and not any(
|
||||
[args.qemu_mode, args.frida_mode, args.unicorn_mode, args.nyx_mode]
|
||||
):
|
||||
if b"__AFL_SHM_ID" not in open(args.exe, "rb").read():
|
||||
logger.error("binary '%s' doesn't appear to be instrumented", args.exe)
|
||||
sys.exit(1)
|
||||
|
||||
for dn in args.input:
|
||||
if not os.path.isdir(dn) and not glob.glob(dn):
|
||||
logger.error('directory "%s" not found', dn)
|
||||
sys.exit(1)
|
||||
|
||||
global afl_showmap_bin
|
||||
searches = [
|
||||
None,
|
||||
os.path.dirname(__file__),
|
||||
os.getcwd(),
|
||||
]
|
||||
if os.environ.get("AFL_PATH"):
|
||||
searches.append(os.environ["AFL_PATH"])
|
||||
|
||||
for search in searches:
|
||||
afl_showmap_bin = shutil.which("afl-showmap", path=search)
|
||||
if afl_showmap_bin:
|
||||
break
|
||||
if not afl_showmap_bin:
|
||||
logger.fatal("cannot find afl-showmap, please set AFL_PATH")
|
||||
sys.exit(1)
|
||||
|
||||
trace_dir = os.path.join(args.output, ".traces")
|
||||
shutil.rmtree(trace_dir, ignore_errors=True)
|
||||
try:
|
||||
os.rmdir(args.output)
|
||||
except OSError:
|
||||
pass
|
||||
if os.path.exists(args.output):
|
||||
logger.error(
|
||||
'directory "%s" exists and is not empty - delete it first', args.output
|
||||
)
|
||||
sys.exit(1)
|
||||
if args.crash_dir and not os.path.exists(args.crash_dir):
|
||||
os.makedirs(args.crash_dir)
|
||||
os.makedirs(trace_dir)
|
||||
|
||||
logger.info("use %d workers (-T)", args.workers)
|
||||
|
||||
|
||||
def detect_type_code(size):
|
||||
for type_code in ["B", "H", "I", "L", "Q"]:
|
||||
if 256 ** array.array(type_code).itemsize > size:
|
||||
return type_code
|
||||
|
||||
|
||||
def afl_showmap(input_path=None, batch=None, afl_map_size=None, first=False):
|
||||
assert input_path or batch
|
||||
# yapf: disable
|
||||
cmd = [
|
||||
afl_showmap_bin,
|
||||
'-m', str(args.memory_limit),
|
||||
'-t', str(args.time_limit),
|
||||
'-Z', # cmin mode
|
||||
]
|
||||
# yapf: enable
|
||||
found_atat = False
|
||||
for arg in args.args:
|
||||
if "@@" in arg:
|
||||
found_atat = True
|
||||
|
||||
if args.stdin_file:
|
||||
assert args.workers == 1
|
||||
input_from_file = True
|
||||
stdin_file = args.stdin_file
|
||||
cmd += ["-H", stdin_file]
|
||||
elif found_atat:
|
||||
input_from_file = True
|
||||
stdin_file = os.path.join(args.output, f".input.{os.getpid()}")
|
||||
cmd += ["-H", stdin_file]
|
||||
else:
|
||||
input_from_file = False
|
||||
|
||||
if batch:
|
||||
input_from_file = True
|
||||
filelist = os.path.join(args.output, f".filelist.{os.getpid()}")
|
||||
with open(filelist, "w") as f:
|
||||
for _, path in batch:
|
||||
f.write(path + "\n")
|
||||
cmd += ["-I", filelist]
|
||||
output_path = os.path.join(args.output, f".showmap.{os.getpid()}")
|
||||
cmd += ["-o", output_path]
|
||||
else:
|
||||
if input_from_file:
|
||||
shutil.copy(input_path, stdin_file)
|
||||
cmd += ["-o", "-"]
|
||||
|
||||
if args.frida_mode:
|
||||
cmd += ["-O"]
|
||||
if args.qemu_mode:
|
||||
cmd += ["-Q"]
|
||||
if args.unicorn_mode:
|
||||
cmd += ["-U"]
|
||||
if args.nyx_mode:
|
||||
cmd += ["-X"]
|
||||
if args.edge_mode:
|
||||
cmd += ["-e"]
|
||||
cmd += ["--", args.exe] + args.args
|
||||
|
||||
env = os.environ.copy()
|
||||
env["AFL_QUIET"] = "1"
|
||||
env["ASAN_OPTIONS"] = "detect_leaks=0"
|
||||
if first:
|
||||
logger.debug("run command line: %s", subprocess.list2cmdline(cmd))
|
||||
env["AFL_CMIN_ALLOW_ANY"] = "1"
|
||||
if afl_map_size:
|
||||
env["AFL_MAP_SIZE"] = str(afl_map_size)
|
||||
if args.crash_only:
|
||||
env["AFL_CMIN_CRASHES_ONLY"] = "1"
|
||||
if args.allow_any:
|
||||
env["AFL_CMIN_ALLOW_ANY"] = "1"
|
||||
|
||||
if input_from_file:
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=env, bufsize=1048576)
|
||||
else:
|
||||
p = subprocess.Popen(
|
||||
cmd,
|
||||
stdin=open(input_path, "rb"),
|
||||
stdout=subprocess.PIPE,
|
||||
env=env,
|
||||
bufsize=1048576,
|
||||
)
|
||||
out = p.stdout.read()
|
||||
p.wait()
|
||||
|
||||
if batch:
|
||||
result = []
|
||||
for idx, input_path in batch:
|
||||
basename = os.path.basename(input_path)
|
||||
values = []
|
||||
try:
|
||||
trace_file = os.path.join(output_path, basename)
|
||||
with open(trace_file, "r") as f:
|
||||
values = list(map(int, f))
|
||||
crashed = len(values) == 0
|
||||
os.unlink(trace_file)
|
||||
except FileNotFoundError:
|
||||
a = None
|
||||
crashed = True
|
||||
values = [(t // 1000) * 9 + t % 1000 for t in values]
|
||||
a = array.array(tuple_index_type_code, values)
|
||||
result.append((idx, a, crashed))
|
||||
os.unlink(filelist)
|
||||
os.rmdir(output_path)
|
||||
return result
|
||||
else:
|
||||
values = []
|
||||
for line in out.split():
|
||||
if not line.isdigit():
|
||||
continue
|
||||
values.append(int(line))
|
||||
values = [(t // 1000) * 9 + t % 1000 for t in values]
|
||||
a = array.array(tuple_index_type_code, values)
|
||||
crashed = p.returncode in [2, 3]
|
||||
if input_from_file and stdin_file != args.stdin_file:
|
||||
os.unlink(stdin_file)
|
||||
return a, crashed
|
||||
|
||||
|
||||
class JobDispatcher(multiprocessing.Process):
|
||||
|
||||
def __init__(self, job_queue, jobs):
|
||||
super().__init__()
|
||||
self.job_queue = job_queue
|
||||
self.jobs = jobs
|
||||
|
||||
def run(self):
|
||||
for job in self.jobs:
|
||||
self.job_queue.put(job)
|
||||
self.job_queue.close()
|
||||
|
||||
|
||||
class Worker(multiprocessing.Process):
|
||||
|
||||
def __init__(self, idx, afl_map_size, q_in, p_out, r_out):
|
||||
super().__init__()
|
||||
self.idx = idx
|
||||
self.afl_map_size = afl_map_size
|
||||
self.q_in = q_in
|
||||
self.p_out = p_out
|
||||
self.r_out = r_out
|
||||
|
||||
def run(self):
|
||||
map_size = self.afl_map_size or 65536
|
||||
max_tuple = map_size * 9
|
||||
max_file_index = 256 ** array.array(file_index_type_code).itemsize - 1
|
||||
m = array.array(file_index_type_code, [max_file_index] * max_tuple)
|
||||
counter = collections.Counter()
|
||||
crashes = []
|
||||
|
||||
pack_name = os.path.join(args.output, ".traces", f"{self.idx}.pack")
|
||||
pack_pos = 0
|
||||
with open(pack_name, "wb") as trace_pack:
|
||||
while True:
|
||||
batch = self.q_in.get()
|
||||
if batch is None:
|
||||
break
|
||||
|
||||
for idx, r, crash in afl_showmap(
|
||||
batch=batch, afl_map_size=self.afl_map_size
|
||||
):
|
||||
counter.update(r)
|
||||
|
||||
used = False
|
||||
|
||||
if crash:
|
||||
crashes.append(idx)
|
||||
|
||||
# If we aren't saving crashes to a separate dir, handle them
|
||||
# the same as other inputs. However, unless AFL_CMIN_ALLOW_ANY=1,
|
||||
# afl_showmap will not return any coverage for crashes so they will
|
||||
# never be retained.
|
||||
if not crash or not args.crash_dir:
|
||||
for t in r:
|
||||
if idx < m[t]:
|
||||
m[t] = idx
|
||||
used = True
|
||||
|
||||
if used:
|
||||
tuple_count = len(r)
|
||||
r.tofile(trace_pack)
|
||||
self.p_out.put((idx, self.idx, pack_pos, tuple_count))
|
||||
pack_pos += tuple_count * r.itemsize
|
||||
else:
|
||||
self.p_out.put(None)
|
||||
|
||||
self.r_out.put((self.idx, m, counter, crashes))
|
||||
|
||||
|
||||
class CombineTraceWorker(multiprocessing.Process):
|
||||
|
||||
def __init__(self, pack_name, jobs, r_out):
|
||||
super().__init__()
|
||||
self.pack_name = pack_name
|
||||
self.jobs = jobs
|
||||
self.r_out = r_out
|
||||
|
||||
def run(self):
|
||||
already_have = set()
|
||||
with open(self.pack_name, "rb") as f:
|
||||
for pos, tuple_count in self.jobs:
|
||||
f.seek(pos)
|
||||
result = array.array(tuple_index_type_code)
|
||||
result.fromfile(f, tuple_count)
|
||||
already_have.update(result)
|
||||
self.r_out.put(already_have)
|
||||
|
||||
|
||||
def hash_file(path):
|
||||
m = hashlib.sha1()
|
||||
with open(path, "rb") as f:
|
||||
m.update(f.read())
|
||||
return m.digest()
|
||||
|
||||
|
||||
def dedup(files):
|
||||
with multiprocessing.Pool(args.workers) as pool:
|
||||
seen_hash = set()
|
||||
result = []
|
||||
hash_list = []
|
||||
# use large chunksize to reduce multiprocessing overhead
|
||||
chunksize = max(1, min(256, len(files) // args.workers))
|
||||
for i, h in enumerate(
|
||||
tqdm(
|
||||
pool.imap(hash_file, files, chunksize),
|
||||
desc="dedup",
|
||||
total=len(files),
|
||||
ncols=0,
|
||||
leave=(len(files) > 100000),
|
||||
)
|
||||
):
|
||||
if h in seen_hash:
|
||||
continue
|
||||
seen_hash.add(h)
|
||||
result.append(files[i])
|
||||
hash_list.append(h)
|
||||
return result, hash_list
|
||||
|
||||
|
||||
def is_afl_dir(dirnames, filenames):
|
||||
return (
|
||||
"queue" in dirnames
|
||||
and "hangs" in dirnames
|
||||
and "crashes" in dirnames
|
||||
and "fuzzer_setup" in filenames
|
||||
)
|
||||
|
||||
|
||||
def collect_files(input_paths):
|
||||
paths = []
|
||||
for s in input_paths:
|
||||
paths += glob.glob(s)
|
||||
|
||||
files = []
|
||||
with tqdm(desc="search", unit=" files", ncols=0) as pbar:
|
||||
for path in paths:
|
||||
for root, dirnames, filenames in os.walk(path, followlinks=True):
|
||||
for dirname in dirnames:
|
||||
if dirname.startswith("."):
|
||||
dirnames.remove(dirname)
|
||||
|
||||
if not args.crash_only and is_afl_dir(dirnames, filenames):
|
||||
continue
|
||||
|
||||
for filename in filenames:
|
||||
if filename.startswith("."):
|
||||
continue
|
||||
pbar.update(1)
|
||||
files.append(os.path.join(root, filename))
|
||||
return files
|
||||
|
||||
|
||||
def main():
|
||||
init()
|
||||
|
||||
files = collect_files(args.input)
|
||||
if len(files) == 0:
|
||||
logger.error("no inputs in the target directory - nothing to be done")
|
||||
sys.exit(1)
|
||||
logger.info("Found %d input files in %d directories", len(files), len(args.input))
|
||||
|
||||
if not args.no_dedup:
|
||||
files, hash_list = dedup(files)
|
||||
logger.info("Remain %d files after dedup", len(files))
|
||||
else:
|
||||
logger.info("Skipping file deduplication.")
|
||||
|
||||
global file_index_type_code
|
||||
file_index_type_code = detect_type_code(len(files))
|
||||
|
||||
logger.info("Sorting files.")
|
||||
with multiprocessing.Pool(args.workers) as pool:
|
||||
chunksize = max(1, min(512, len(files) // args.workers))
|
||||
size_list = list(pool.map(os.path.getsize, files, chunksize))
|
||||
idxes = sorted(range(len(files)), key=lambda x: size_list[x])
|
||||
files = [files[idx] for idx in idxes]
|
||||
hash_list = [hash_list[idx] for idx in idxes]
|
||||
|
||||
afl_map_size = None
|
||||
if b"AFL_DUMP_MAP_SIZE" in open(args.exe, "rb").read():
|
||||
output = subprocess.run(
|
||||
[args.exe], capture_output=True, env={"AFL_DUMP_MAP_SIZE": "1", "ASAN_OPTIONS": "detect_leaks=0"}
|
||||
).stdout
|
||||
afl_map_size = int(output)
|
||||
logger.info("Setting AFL_MAP_SIZE=%d", afl_map_size)
|
||||
|
||||
global tuple_index_type_code
|
||||
tuple_index_type_code = detect_type_code(afl_map_size * 9)
|
||||
|
||||
logger.info("Testing the target binary")
|
||||
tuples, _ = afl_showmap(files[0], afl_map_size=afl_map_size, first=True)
|
||||
if tuples:
|
||||
logger.info("ok, %d tuples recorded", len(tuples))
|
||||
else:
|
||||
logger.error("no instrumentation output detected")
|
||||
sys.exit(1)
|
||||
|
||||
job_queue = multiprocessing.Queue()
|
||||
progress_queue = multiprocessing.Queue()
|
||||
result_queue = multiprocessing.Queue()
|
||||
|
||||
workers = []
|
||||
for i in range(args.workers):
|
||||
p = Worker(i, afl_map_size, job_queue, progress_queue, result_queue)
|
||||
p.start()
|
||||
workers.append(p)
|
||||
|
||||
chunk = max(1, min(128, len(files) // args.workers))
|
||||
jobs = list(batched(enumerate(files), chunk))
|
||||
jobs += [None] * args.workers # sentinel
|
||||
|
||||
dispatcher = JobDispatcher(job_queue, jobs)
|
||||
dispatcher.start()
|
||||
|
||||
logger.info("Processing traces")
|
||||
effective = 0
|
||||
trace_info = {}
|
||||
for _ in tqdm(files, ncols=0, smoothing=0.01):
|
||||
r = progress_queue.get()
|
||||
if r is not None:
|
||||
idx, worker_idx, pos, tuple_count = r
|
||||
trace_info[idx] = worker_idx, pos, tuple_count
|
||||
effective += 1
|
||||
dispatcher.join()
|
||||
|
||||
logger.info("Obtaining trace results")
|
||||
ms = []
|
||||
crashes = []
|
||||
counter = collections.Counter()
|
||||
for _ in tqdm(range(args.workers), ncols=0):
|
||||
idx, m, c, crs = result_queue.get()
|
||||
ms.append(m)
|
||||
counter.update(c)
|
||||
crashes.extend(crs)
|
||||
workers[idx].join()
|
||||
best_idxes = list(map(min, zip(*ms)))
|
||||
|
||||
if not args.crash_dir:
|
||||
logger.info(
|
||||
"Found %d unique tuples across %d files (%d effective)",
|
||||
len(counter),
|
||||
len(files),
|
||||
effective,
|
||||
)
|
||||
else:
|
||||
logger.info(
|
||||
"Found %d unique tuples across %d files (%d effective, %d crashes)",
|
||||
len(counter),
|
||||
len(files),
|
||||
effective,
|
||||
len(crashes),
|
||||
)
|
||||
all_unique = counter.most_common()
|
||||
|
||||
logger.info("Processing candidates and writing output")
|
||||
already_have = set()
|
||||
count = 0
|
||||
|
||||
def save_file(idx):
|
||||
input_path = files[idx]
|
||||
fn = (
|
||||
base64.b16encode(hash_list[idx]).decode("utf8").lower()
|
||||
if not args.no_dedup
|
||||
else os.path.basename(input_path)
|
||||
)
|
||||
if args.as_queue:
|
||||
if args.no_dedup:
|
||||
fn = "id:%06d,orig:%s" % (count, fn)
|
||||
else:
|
||||
fn = "id:%06d,hash:%s" % (count, fn)
|
||||
output_path = os.path.join(args.output, fn)
|
||||
try:
|
||||
os.link(input_path, output_path)
|
||||
except OSError:
|
||||
shutil.copy(input_path, output_path)
|
||||
|
||||
jobs = [[] for i in range(args.workers)]
|
||||
saved = set()
|
||||
for t, c in all_unique:
|
||||
if c != 1:
|
||||
continue
|
||||
idx = best_idxes[t]
|
||||
if idx in saved:
|
||||
continue
|
||||
save_file(idx)
|
||||
saved.add(idx)
|
||||
count += 1
|
||||
|
||||
worker_idx, pos, tuple_count = trace_info[idx]
|
||||
job = (pos, tuple_count)
|
||||
jobs[worker_idx].append(job)
|
||||
|
||||
trace_packs = []
|
||||
workers = []
|
||||
for i in range(args.workers):
|
||||
pack_name = os.path.join(args.output, ".traces", f"{i}.pack")
|
||||
trace_f = open(pack_name, "rb")
|
||||
trace_packs.append(trace_f)
|
||||
|
||||
p = CombineTraceWorker(pack_name, jobs[i], result_queue)
|
||||
p.start()
|
||||
workers.append(p)
|
||||
|
||||
for _ in range(args.workers):
|
||||
result = result_queue.get()
|
||||
already_have.update(result)
|
||||
|
||||
for t, c in tqdm(list(reversed(all_unique)), ncols=0):
|
||||
if t in already_have:
|
||||
continue
|
||||
|
||||
idx = best_idxes[t]
|
||||
save_file(idx)
|
||||
count += 1
|
||||
|
||||
worker_idx, pos, tuple_count = trace_info[idx]
|
||||
trace_pack = trace_packs[worker_idx]
|
||||
trace_pack.seek(pos)
|
||||
result = array.array(tuple_index_type_code)
|
||||
result.fromfile(trace_pack, tuple_count)
|
||||
|
||||
already_have.update(result)
|
||||
|
||||
for f in trace_packs:
|
||||
f.close()
|
||||
|
||||
if args.crash_dir:
|
||||
logger.info("Saving crashes to %s", args.crash_dir)
|
||||
crash_files = [files[c] for c in crashes]
|
||||
|
||||
if args.no_dedup:
|
||||
# Unless we deduped previously, we have to dedup the crash files
|
||||
# now.
|
||||
crash_files, hash_list = dedup(crash_files)
|
||||
|
||||
for idx, crash_path in enumerate(crash_files):
|
||||
fn = base64.b16encode(hash_list[idx]).decode("utf8").lower()
|
||||
output_path = os.path.join(args.crash_dir, fn)
|
||||
try:
|
||||
os.link(crash_path, output_path)
|
||||
except OSError:
|
||||
try:
|
||||
shutil.copy(crash_path, output_path)
|
||||
except shutil.Error:
|
||||
# This error happens when src and dest are hardlinks of the
|
||||
# same file. We have nothing to do in this case, but handle
|
||||
# it gracefully.
|
||||
pass
|
||||
|
||||
if count == 1:
|
||||
logger.warning("all test cases had the same traces, check syntax!")
|
||||
logger.info('narrowed down to %s files, saved in "%s"', count, args.output)
|
||||
if not os.environ.get("AFL_KEEP_TRACES"):
|
||||
logger.info("Deleting trace files")
|
||||
trace_dir = os.path.join(args.output, ".traces")
|
||||
shutil.rmtree(trace_dir, ignore_errors=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -4,7 +4,7 @@ CFLAGS = -O3 -funroll-loops -fPIC
|
||||
all: aflpp-standalone
|
||||
|
||||
aflpp-standalone: aflpp-standalone.c
|
||||
$(CC) $(CFLAGS) -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) -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
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ aflpp-standalone core
|
||||
|
@ -1,19 +1,20 @@
|
||||
|
||||
CFLAGS = -g -O3 -funroll-loops -fPIC -D_STANDALONE_MODULE=1 -Wno-implicit-function-declaration
|
||||
CFLAGS = -g -O3 -funroll-loops -fPIC -D_STANDALONE_MODULE=1 -Wno-pointer-sign
|
||||
CXXFLAGS= -g -O3 -funroll-loops -fPIC -D_STANDALONE_MODULE=1
|
||||
|
||||
all: autotokens-standalone
|
||||
|
||||
autotokens.o: ../autotokens.cpp
|
||||
$(CXX) $(CXXFLAGS) -I../../../include -I. -I../.. -c ../autotokens.cpp
|
||||
$(CXX) $(CXXFLAGS) -g -I../../../include -I. -I../.. -c ../autotokens.cpp
|
||||
|
||||
autotokens-standalone: autotokens-standalone.c autotokens.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
|
||||
$(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
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ autotokens-standalone core
|
||||
|
@ -1,15 +1,28 @@
|
||||
#include "afl-fuzz.h"
|
||||
#include "afl-mutations.h"
|
||||
#include "forkserver.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
|
||||
static int max_havoc = 16, verbose;
|
||||
static unsigned char *dict, *mh = "16";
|
||||
static char _mh[4] = "16";
|
||||
static char *dict, *mh = _mh;
|
||||
|
||||
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[]) {
|
||||
|
||||
@ -144,7 +157,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
if (dict) {
|
||||
|
||||
load_extras(afl, dict);
|
||||
load_extras(afl, (u8*)dict);
|
||||
if (verbose)
|
||||
fprintf(stderr, "Loaded dictionary: %s (%u entries)\n", dict,
|
||||
afl->extras_cnt);
|
||||
|
@ -3,6 +3,34 @@
|
||||
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)
|
||||
- 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"
|
||||
@ -22,7 +50,6 @@
|
||||
- frida_mode:
|
||||
- fixes for new MacOS + M4 hardware
|
||||
|
||||
|
||||
### Version ++4.31c (release)
|
||||
- SAND mode added (docs/SAND.md) for more effecient fuzzing with sanitizers
|
||||
(thanks to @wtdcode !)
|
||||
|
12
docs/FAQ.md
12
docs/FAQ.md
@ -11,7 +11,7 @@ If you find an interesting or important question missing, submit it via
|
||||
AFL++ is a superior fork to Google's AFL - more speed, more and better
|
||||
mutations, more and better instrumentation, custom module support, etc.
|
||||
|
||||
American Fuzzy Lop (AFL) was developed by Michał "lcamtuf" Zalewski starting
|
||||
American Fuzzy Lop (AFL) was developed by Michal "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-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)
|
||||
/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)
|
||||
Target: x86_64-unknown-linux-gnu
|
||||
Thread model: posix
|
||||
InstalledDir: /prg/tmp/llvm-project/build/bin
|
||||
clang-13: note: diagnostic msg:
|
||||
clang-18: note: diagnostic msg:
|
||||
********************
|
||||
```
|
||||
|
||||
|
@ -21,7 +21,7 @@ If you want to build AFL++ yourself, you have many options. The easiest choice
|
||||
is to build and install everything:
|
||||
|
||||
NOTE: depending on your Debian/Ubuntu/Kali/... release, replace `-14` with
|
||||
whatever llvm version is available. We recommend llvm 13 or newer.
|
||||
whatever llvm version is available. We recommend llvm 14 or newer.
|
||||
|
||||
```shell
|
||||
sudo apt-get update
|
||||
|
@ -21,7 +21,7 @@ For a normal fuzzing workflow, we have:
|
||||
For SAND fuzzing workflow, this is slightly different:
|
||||
|
||||
1. Build target project _without_ any sanitizers to get `target_native`, which we will define as a "native binary". It is usually done by using `afl-clang-fast/lto(++)` to compile your project _without_ `AFL_USE_ASAN/UBSAN/MSAN`.
|
||||
2. Build target project with AFL_USE_ASAN=1 AFL_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.
|
||||
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.
|
||||
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_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
|
||||
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
|
||||
```
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
3. Start fuzzing
|
||||
|
||||
|
@ -111,6 +111,10 @@ 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.
|
||||
|
||||
@ -664,6 +668,24 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
Note that will not be exact and with slow targets it can take seconds
|
||||
until there is a slice for the time test.
|
||||
|
||||
- When using `AFL_PRELOAD` with a preload that disable `fork()` calls in
|
||||
the target, the forkserver becomes unable to fork.
|
||||
To overcome this issue, the `AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT`
|
||||
permits to be able to check in the preloaded library if the environment
|
||||
variable `AFL_FORKSERVER_PARENT` is set, to be able to use vanilla
|
||||
`fork()` in the forkserver, and the placeholder in the target.
|
||||
Here is a POC :
|
||||
```C
|
||||
// AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT=1 afl-fuzz ...
|
||||
pid_t fork(void)
|
||||
{
|
||||
if (getenv("AFL_FORKSERVER_PARENT") == NULL)
|
||||
return 0; // We are in the target
|
||||
else
|
||||
return real_fork(); // We are in the forkserver
|
||||
}
|
||||
```
|
||||
|
||||
## 6) Settings for afl-qemu-trace
|
||||
|
||||
The QEMU wrapper used to instrument binary-only code supports several settings:
|
||||
|
@ -45,7 +45,7 @@ E. CmpLog is our enhanced
|
||||
implementation, see
|
||||
[instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md)
|
||||
|
||||
F. Similar and compatible to clang 13+ sancov sanitize-coverage-allow/deny but
|
||||
F. Similar and compatible to clang 14+ sancov sanitize-coverage-allow/deny but
|
||||
for all llvm versions and all our compile modes, only instrument what should
|
||||
be instrumented, for more speed, directed fuzzing and less instability; see
|
||||
[instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md)
|
||||
|
@ -132,11 +132,15 @@ 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 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
|
||||
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
|
||||
[instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md).
|
||||
|
||||
If you use LTO, LLVM, or GCC_PLUGIN mode
|
||||
@ -865,10 +869,13 @@ 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 or
|
||||
libdesock may offer a relatively simple option, too - see:
|
||||
simple code changes to make them behave in a more traditional way. Preeny,
|
||||
libdesock or desockmulti may offer a relatively simple option, too - see:
|
||||
[https://github.com/zardus/preeny](https://github.com/zardus/preeny) or
|
||||
[https://github.com/fkie-cad/libdesock](https://github.com/fkie-cad/libdesock)
|
||||
[https://github.com/zyingp/desockmulti](https://github.com/zyingp/desockmulti)
|
||||
If these fail then try our own which might be a bit slower but is more
|
||||
reliable: [utils/libaflppdesock](../utils/libaflppdesock)
|
||||
|
||||
Some useful tips for modifying network-based services can be also found at:
|
||||
[https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop](https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop)
|
||||
|
@ -15,6 +15,7 @@ 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)
|
||||
@ -186,39 +187,13 @@ ifndef OS
|
||||
$(error "Operating system unsupported")
|
||||
endif
|
||||
|
||||
GUM_DEVKIT_VERSION=16.1.11
|
||||
GUM_DEVKIT_VERSION=17.0.7
|
||||
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)
|
||||
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
|
||||
GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gumjs.a
|
||||
|
||||
FRIDA_DIR:=$(PWD)build/frida-source/
|
||||
FRIDA_MAKEFILE:=$(FRIDA_DIR)Makefile
|
||||
@ -252,13 +227,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:
|
||||
CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
|
||||
XTOOLS_HOST=i686-linux-gnu CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
|
||||
|
||||
arm:
|
||||
CFLAGS="-marm" LDFLAGS="-marm" ARCH="armhf" TARGET_CC=arm-linux-gnueabihf-gcc TARGET_CXX=arm-linux-gnueabihf-g++ make all
|
||||
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
|
||||
|
||||
arm64:
|
||||
ARCH="arm64" TARGET_CC=aarch64-linux-gnu-gcc TARGET_CXX=aarch64-linux-gnu-g++ make all
|
||||
XTOOLS_HOST=aarch64-linux-gnu ARCH="arm64" TARGET_CC=aarch64-linux-gnu-gcc TARGET_CXX=aarch64-linux-gnu-g++ make all
|
||||
|
||||
$(BUILD_DIR):
|
||||
mkdir -p $(BUILD_DIR)
|
||||
@ -271,114 +246,29 @@ $(OBJ_DIR): | $(BUILD_DIR)
|
||||
$(FRIDA_BUILD_DIR): | $(BUILD_DIR)
|
||||
mkdir -p $@
|
||||
|
||||
#TODO Set architecture
|
||||
ifdef FRIDA_SOURCE
|
||||
$(FRIDA_MAKEFILE): | $(BUILD_DIR)
|
||||
git clone --recursive https://github.com/frida/frida.git $(FRIDA_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
|
||||
|
||||
.PHONY: $(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/ \
|
||||
$(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)
|
||||
|
||||
ifeq "$(OS)" "android"
|
||||
CFLAGS += -static-libstdc++
|
||||
endif
|
||||
else
|
||||
CFLAGS+=-I $(FRIDA_DIR)build/$(OS)-$(ARCH)/include/frida-1.0 \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
|
||||
|
||||
endif
|
||||
|
||||
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libunwind.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libdwarf.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libelf.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
|
||||
|
||||
CFLAGS+=-I $(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/include/frida-1.0 \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/
|
||||
|
||||
ifeq "$(OS)" "android"
|
||||
CFLAGS += -static-libstdc++
|
||||
endif
|
||||
|
||||
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libunwind.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libdwarf.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libelf.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
|
||||
|
||||
|
||||
else
|
||||
$(GUM_DEVKIT_TARBALL): | $(FRIDA_BUILD_DIR)
|
||||
|
@ -27,7 +27,6 @@ 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;
|
||||
@ -47,32 +46,6 @@ static gboolean asan_exclude_module(GumModule *module, gpointer user_data) {
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
static gboolean asan_exclude_module(const GumModuleDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
gchar *symbol_name = (gchar *)user_data;
|
||||
GumAddress address;
|
||||
|
||||
address = gum_module_find_export_by_name(details->name, symbol_name);
|
||||
if (address == 0) { return TRUE; }
|
||||
|
||||
/* If the reported address of the symbol is outside of the range of the module
|
||||
* then ignore it */
|
||||
if (address < details->range->base_address) { return TRUE; }
|
||||
if (address > (details->range->base_address + details->range->size)) {
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
ranges_add_exclude((GumMemoryRange *)details->range);
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void asan_exclude_module_by_symbol(gchar *symbol_name) {
|
||||
|
||||
gum_process_enumerate_modules(asan_exclude_module, symbol_name);
|
||||
|
@ -382,5 +382,5 @@ Afl.jsApiSetTraceable = Afl.jsApiGetFunction("js_api_set_traceable", "void", [])
|
||||
Afl.jsApiSetVerbose = Afl.jsApiGetFunction("js_api_set_verbose", "void", []);
|
||||
Afl.jsApiWrite = new NativeFunction(
|
||||
/* tslint:disable-next-line:no-null-keyword */
|
||||
Module.getExportByName(null, "write"), "int", ["int", "pointer", "int"]);
|
||||
Module.getGlobalExportByName("write"), "int", ["int", "pointer", "int"]);
|
||||
Afl.jsApiIjonSet = Afl.jsApiGetFunction("js_api_ijon_set", "void", ["uint32"]);
|
||||
|
@ -39,7 +39,6 @@ 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;
|
||||
@ -57,24 +56,6 @@ static gboolean lib_find_exe(GumModule *module, gpointer user_data) {
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
static gboolean lib_find_exe(const GumModuleDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
lib_details_t *lib_details = (lib_details_t *)user_data;
|
||||
|
||||
strncpy(lib_details->name, details->name, PATH_MAX);
|
||||
strncpy(lib_details->path, details->path, PATH_MAX);
|
||||
lib_details->name[PATH_MAX] = '\0';
|
||||
lib_details->path[PATH_MAX] = '\0';
|
||||
lib_details->base_address = details->range->base_address;
|
||||
lib_details->size = details->range->size;
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void lib_validate_hdr(Elf_Ehdr *hdr) {
|
||||
|
||||
if (hdr->e_ident[0] != ELFMAG0) FFATAL("Invalid e_ident[0]");
|
||||
|
@ -12,7 +12,6 @@ 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;
|
||||
@ -30,25 +29,6 @@ static gboolean lib_get_main_module(GumModule *module, gpointer user_data) {
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
static gboolean lib_get_main_module(const GumModuleDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
GumDarwinModule **ret = (GumDarwinModule **)user_data;
|
||||
GumDarwinModule *module = gum_darwin_module_new_from_memory(
|
||||
details->path, mach_task_self(), details->range->base_address,
|
||||
GUM_DARWIN_MODULE_FLAGS_NONE, NULL);
|
||||
|
||||
FVERBOSE("Found main module: %s", module->name);
|
||||
|
||||
*ret = module;
|
||||
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
gboolean lib_get_text_section(const GumDarwinSectionDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
|
@ -46,6 +46,7 @@ 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;
|
||||
@ -61,8 +62,12 @@ static int on_dlclose(void *handle) {
|
||||
FVERBOSE("on_dlclose: %s", lm->l_name);
|
||||
|
||||
ranges = g_array_new(FALSE, TRUE, sizeof(gum_range_t));
|
||||
gum_module_enumerate_ranges(lm->l_name, GUM_PAGE_EXECUTE, found_range,
|
||||
ranges);
|
||||
|
||||
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);
|
||||
|
||||
int ret = dlclose(handle);
|
||||
if (ret != 0) {
|
||||
|
@ -263,13 +263,8 @@ static int prefetch_on_fork(void) {
|
||||
|
||||
static void prefetch_hook_fork(void) {
|
||||
|
||||
#ifdef GUM_16_6_PLUS
|
||||
void *fork_addr =
|
||||
GSIZE_TO_POINTER(gum_module_find_global_export_by_name("fork"));
|
||||
#else
|
||||
void *fork_addr =
|
||||
GSIZE_TO_POINTER(gum_module_find_export_by_name(NULL, "fork"));
|
||||
#endif
|
||||
intercept_hook(fork_addr, prefetch_on_fork, NULL);
|
||||
|
||||
}
|
||||
|
@ -116,7 +116,6 @@ 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) {
|
||||
|
||||
@ -138,28 +137,6 @@ 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);
|
||||
|
@ -770,6 +770,7 @@ 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;
|
||||
@ -1139,6 +1140,7 @@ 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);
|
||||
@ -1180,7 +1182,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(void *);
|
||||
void splice_optout_py(void *);
|
||||
void deinit_py(void *);
|
||||
|
||||
#endif
|
||||
@ -1215,7 +1217,6 @@ 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
|
||||
@ -1258,6 +1259,7 @@ 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);
|
||||
@ -1278,7 +1280,6 @@ u8 fuzz_one(afl_state_t *);
|
||||
#ifdef HAVE_AFFINITY
|
||||
void bind_to_free_cpu(afl_state_t *);
|
||||
#endif
|
||||
void setup_post(afl_state_t *);
|
||||
void read_testcases(afl_state_t *, u8 *);
|
||||
void perform_dry_run(afl_state_t *);
|
||||
void pivot_inputs(afl_state_t *);
|
||||
|
@ -26,7 +26,7 @@
|
||||
/* Version string: */
|
||||
|
||||
// c = release, a = volatile github dev, e = experimental branch
|
||||
#define VERSION "++4.32c"
|
||||
#define VERSION "++4.33a"
|
||||
|
||||
/******************************************************
|
||||
* *
|
||||
@ -171,8 +171,9 @@
|
||||
#define EXEC_TM_ROUND 20U
|
||||
|
||||
/* 64bit arch MACRO */
|
||||
#if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__) || \
|
||||
(defined(__riscv) && __riscv_xlen == 64))
|
||||
#if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__) || \
|
||||
(defined(__riscv) && __riscv_xlen == 64) || defined(__powerpc64le__) || \
|
||||
defined(__s390x__) || defined(__loongarch64))
|
||||
#define WORD_SIZE_64 1
|
||||
#endif
|
||||
|
||||
@ -338,6 +339,10 @@
|
||||
|
||||
#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
|
||||
@ -423,9 +428,15 @@
|
||||
|
||||
#define SHM_ENV_VAR "__AFL_SHM_ID"
|
||||
|
||||
/* Environment variable used to pass SHM FUZZ ID to the called program. */
|
||||
/* Environment variable used to pass shared memory fuzz map id
|
||||
and the mapping size to the called program. */
|
||||
|
||||
#define SHM_FUZZ_ENV_VAR "__AFL_SHM_FUZZ_ID"
|
||||
#define SHM_FUZZ_MAP_SIZE_ENV_VAR "__AFL_SHM_FUZZ_MAP_SIZE"
|
||||
|
||||
/* Default size of the shared memory fuzz map.
|
||||
We add 4 byte for one u32 length field. */
|
||||
#define SHM_FUZZ_MAP_SIZE_DEFAULT (MAX_FILE + 4)
|
||||
|
||||
/* Other less interesting, internal-only variables. */
|
||||
|
||||
|
@ -10,6 +10,7 @@ static char *afl_environment_deprecated[] = {
|
||||
"AFL_DEFER_FORKSRV",
|
||||
"AFL_POST_LIBRARY",
|
||||
"AFL_PERSISTENT",
|
||||
"AFL_SAN_NO_INST",
|
||||
NULL
|
||||
|
||||
};
|
||||
@ -118,7 +119,8 @@ 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_SAN_NO_INST", "AFL_SAN_RECOVER", NULL};
|
||||
"AFL_SAN_ABSTRACTION", "AFL_LLVM_ONLY_FSRV", "AFL_GCC_ONLY_FRSV",
|
||||
"AFL_SAN_RECOVER", "AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT", NULL};
|
||||
|
||||
extern char *afl_environment_variables[];
|
||||
|
||||
|
@ -159,6 +159,8 @@ 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?
|
||||
@ -240,6 +242,7 @@ typedef enum fsrv_run_result {
|
||||
|
||||
void afl_fsrv_init(afl_forkserver_t *fsrv);
|
||||
void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from);
|
||||
void afl_fsrv_setup_preload(afl_forkserver_t *fsrv, char *argv0);
|
||||
void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
volatile u8 *stop_soon_p, u8 debug_child_output);
|
||||
u32 afl_fsrv_get_mapsize(afl_forkserver_t *fsrv, char **argv,
|
||||
|
@ -2,18 +2,6 @@
|
||||
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.
|
||||
|
||||
@ -33,82 +21,5 @@
|
||||
u32 hash32(u8 *key, u32 len, u32 seed);
|
||||
u64 hash64(u8 *key, u32 len, u64 seed);
|
||||
|
||||
#if 0
|
||||
|
||||
The following code is disabled because xxh3 is 30% faster
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
#define ROL64(_x, _r) ((((u64)(_x)) << (_r)) | (((u64)(_x)) >> (64 - (_r))))
|
||||
|
||||
static inline u32 hash32(u8 *key, u32 len, u32 seed) {
|
||||
|
||||
const u64 *data = (u64 *)key;
|
||||
u64 h1 = seed ^ len;
|
||||
|
||||
len >>= 3;
|
||||
|
||||
while (len--) {
|
||||
|
||||
u64 k1 = *data++;
|
||||
|
||||
k1 *= 0x87c37b91114253d5ULL;
|
||||
k1 = ROL64(k1, 31);
|
||||
k1 *= 0x4cf5ad432745937fULL;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = ROL64(h1, 27);
|
||||
h1 = h1 * 5 + 0x52dce729;
|
||||
|
||||
}
|
||||
|
||||
h1 ^= h1 >> 33;
|
||||
h1 *= 0xff51afd7ed558ccdULL;
|
||||
h1 ^= h1 >> 33;
|
||||
h1 *= 0xc4ceb9fe1a85ec53ULL;
|
||||
h1 ^= h1 >> 33;
|
||||
|
||||
return h1;
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define ROL32(_x, _r) ((((u32)(_x)) << (_r)) | (((u32)(_x)) >> (32 - (_r))))
|
||||
|
||||
static inline u32 hash32(const void *key, u32 len, u32 seed) {
|
||||
|
||||
const u32 *data = (u32 *)key;
|
||||
u32 h1 = seed ^ len;
|
||||
|
||||
len >>= 2;
|
||||
|
||||
while (len--) {
|
||||
|
||||
u32 k1 = *data++;
|
||||
|
||||
k1 *= 0xcc9e2d51;
|
||||
k1 = ROL32(k1, 15);
|
||||
k1 *= 0x1b873593;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = ROL32(h1, 13);
|
||||
h1 = h1 * 5 + 0xe6546b64;
|
||||
|
||||
}
|
||||
|
||||
h1 ^= h1 >> 16;
|
||||
h1 *= 0x85ebca6b;
|
||||
h1 ^= h1 >> 13;
|
||||
h1 *= 0xc2b2ae35;
|
||||
h1 ^= h1 >> 16;
|
||||
|
||||
return h1;
|
||||
|
||||
}
|
||||
|
||||
#endif /* ^__x86_64__ */
|
||||
#endif
|
||||
|
||||
#endif /* !_HAVE_HASH_H */
|
||||
|
||||
|
@ -327,13 +327,13 @@ class ModuleSanitizerCoverageLTOLegacyPass : public ModulePass {
|
||||
|
||||
};
|
||||
|
||||
if (!getenv("AFL_SAN_NO_INST")) {
|
||||
if (!getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
|
||||
return ModuleSancov.instrumentModule(M, DTCallback, PDTCallback);
|
||||
|
||||
} else {
|
||||
|
||||
if (getenv("AFL_DEBUG")) { DEBUGF("Instrument disabled\n"); }
|
||||
if (getenv("AFL_DEBUG")) { DEBUGF("Instrumentation disabled\n"); }
|
||||
return false;
|
||||
|
||||
}
|
||||
@ -389,14 +389,14 @@ PreservedAnalyses ModuleSanitizerCoverageLTO::run(Module &M,
|
||||
|
||||
};
|
||||
|
||||
if (!getenv("AFL_SAN_NO_INST")) {
|
||||
if (!getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
|
||||
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
|
||||
return PreservedAnalyses::none();
|
||||
|
||||
} else {
|
||||
|
||||
if (debug) { DEBUGF("Instrument disabled\n"); }
|
||||
if (debug) { DEBUGF("Instrumentation disabled\n"); }
|
||||
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#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"
|
||||
@ -76,9 +77,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"
|
||||
@ -206,7 +207,8 @@ class ModuleSanitizerCoverageAFL
|
||||
|
||||
SanitizerCoverageOptions Options;
|
||||
|
||||
uint32_t instr = 0, selects = 0, unhandled = 0, dump_cc = 0;
|
||||
uint32_t instr = 0, selects = 0, hidden = 0, unhandled = 0, skippedbb = 0,
|
||||
dump_cc = 0;
|
||||
GlobalVariable *AFLMapPtr = NULL;
|
||||
ConstantInt *One = NULL;
|
||||
ConstantInt *Zero = NULL;
|
||||
@ -272,14 +274,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_SAN_NO_INST")) {
|
||||
if (!getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
|
||||
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
|
||||
return PreservedAnalyses::none();
|
||||
|
||||
} else {
|
||||
|
||||
if (getenv("AFL_DEBUG")) { DEBUGF("Instrument disabled\n"); }
|
||||
if (getenv("AFL_DEBUG")) { DEBUGF("Instrumentation disabled\n"); }
|
||||
|
||||
}
|
||||
|
||||
@ -505,9 +507,16 @@ 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 selects.",
|
||||
instr, modeline, selects, unhandled);
|
||||
"%u handled and %u unhandled special instructions.%s",
|
||||
instr, modeline, selects + hidden, unhandled, buf);
|
||||
|
||||
}
|
||||
|
||||
@ -781,11 +790,14 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
|
||||
if (AllBlocks.empty()) return false;
|
||||
|
||||
uint32_t cnt_cov = 0, cnt_sel = 0, cnt_sel_inc = 0;
|
||||
uint32_t cnt_cov = 0, cnt_sel = 0, cnt_sel_inc = 0, cnt_hidden_sel = 0,
|
||||
cnt_hidden_sel_inc = 0, skip_blocks = 0;
|
||||
static uint32_t first = 1;
|
||||
|
||||
for (auto &BB : F) {
|
||||
|
||||
bool block_is_instrumented = false;
|
||||
|
||||
for (auto &IN : BB) {
|
||||
|
||||
CallInst *callInst = nullptr;
|
||||
@ -799,11 +811,11 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
if (!FuncName.compare(StringRef("dlopen")) ||
|
||||
!FuncName.compare(StringRef("_dlopen"))) {
|
||||
|
||||
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");
|
||||
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");
|
||||
continue;
|
||||
|
||||
}
|
||||
@ -811,53 +823,183 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
if (!FuncName.compare(StringRef("__afl_coverage_interesting"))) {
|
||||
|
||||
cnt_cov++;
|
||||
block_is_instrumented = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SelectInst *selectInst = nullptr;
|
||||
bool instrumentInst = false;
|
||||
ICmpInst *icmp;
|
||||
FCmpInst *fcmp;
|
||||
|
||||
if ((selectInst = dyn_cast<SelectInst>(&IN))) {
|
||||
if ((icmp = dyn_cast<ICmpInst>(&IN)) ||
|
||||
(fcmp = dyn_cast<FCmpInst>(&IN)) || isa<SelectInst>(&IN)) {
|
||||
|
||||
Value *c = selectInst->getCondition();
|
||||
auto t = c->getType();
|
||||
if (t->getTypeID() == llvm::Type::IntegerTyID) {
|
||||
// || isa<PHINode>(&IN)
|
||||
|
||||
cnt_sel++;
|
||||
cnt_sel_inc += 2;
|
||||
bool usedInBranch = false, usedInSelectDecision = false;
|
||||
|
||||
}
|
||||
for (auto *U : IN.users()) {
|
||||
|
||||
else if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
|
||||
if (isa<BranchInst>(U)) {
|
||||
|
||||
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
|
||||
if (tt) {
|
||||
usedInBranch = true;
|
||||
break;
|
||||
|
||||
cnt_sel++;
|
||||
cnt_sel_inc += (tt->getElementCount().getKnownMinValue() * 2);
|
||||
}
|
||||
|
||||
if (auto *sel = dyn_cast<SelectInst>(U)) {
|
||||
|
||||
if (icmp && sel->getCondition() == icmp) {
|
||||
|
||||
usedInSelectDecision = true;
|
||||
|
||||
} else if (fcmp && sel->getCondition() == fcmp) {
|
||||
|
||||
usedInSelectDecision = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CreateFunctionLocalArrays(F, AllBlocks, first + cnt_cov + cnt_sel_inc);
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
if (first) { first = 0; }
|
||||
selects += cnt_sel;
|
||||
hidden += cnt_hidden_sel;
|
||||
|
||||
uint32_t special = 0, local_selects = 0, skip_next = 0;
|
||||
uint32_t special = 0, local_selects = 0, skip_select = 0, skip_icmp = 0;
|
||||
// uint32_t skip_phi = 0;
|
||||
|
||||
for (auto &BB : F) {
|
||||
|
||||
// errs() << *(&BB) << "\n";
|
||||
|
||||
for (auto &IN : BB) {
|
||||
|
||||
// errs() << *(&IN) << "\n";
|
||||
CallInst *callInst = nullptr;
|
||||
|
||||
if ((callInst = dyn_cast<CallInst>(&IN))) {
|
||||
@ -875,15 +1017,6 @@ 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),
|
||||
@ -897,132 +1030,324 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
|
||||
}
|
||||
|
||||
SelectInst *selectInst = nullptr;
|
||||
bool instrumentInst = false;
|
||||
ICmpInst *icmp;
|
||||
FCmpInst *fcmp;
|
||||
|
||||
if (!skip_next && (selectInst = dyn_cast<SelectInst>(&IN))) {
|
||||
if ((icmp = dyn_cast<ICmpInst>(&IN)) ||
|
||||
(fcmp = dyn_cast<FCmpInst>(&IN)) || isa<SelectInst>(&IN)) {
|
||||
|
||||
uint32_t vector_cnt = 0;
|
||||
Value *condition = selectInst->getCondition();
|
||||
Value *result;
|
||||
auto t = condition->getType();
|
||||
IRBuilder<> IRB(selectInst->getNextNode());
|
||||
// || isa<PHINode>(&IN)
|
||||
|
||||
if (t->getTypeID() == llvm::Type::IntegerTyID) {
|
||||
bool usedInBranch = false, usedInSelectDecision = false;
|
||||
|
||||
if (!FunctionGuardArray) {
|
||||
for (auto *U : IN.users()) {
|
||||
|
||||
fprintf(stderr,
|
||||
"SANCOV: FunctionGuardArray is NULL, failed to emit "
|
||||
"instrumentation.");
|
||||
continue;
|
||||
if (isa<BranchInst>(U)) {
|
||||
|
||||
usedInBranch = true;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
auto GuardPtr1 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
|
||||
Int32PtrTy);
|
||||
if (auto *sel = dyn_cast<SelectInst>(U)) {
|
||||
|
||||
auto GuardPtr2 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
|
||||
Int32PtrTy);
|
||||
if (icmp && sel->getCondition() == icmp) {
|
||||
|
||||
result = IRB.CreateSelect(condition, GuardPtr1, GuardPtr2);
|
||||
usedInSelectDecision = true;
|
||||
break;
|
||||
|
||||
} else
|
||||
} else if (fcmp && sel->getCondition() == fcmp) {
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
|
||||
|
||||
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
|
||||
if (tt) {
|
||||
|
||||
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;
|
||||
|
||||
if (!FunctionGuardArray) {
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
usedInSelectDecision = true;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
if ((icmp = dyn_cast<ICmpInst>(&IN))) {
|
||||
|
||||
if (!icmp->getType()->isIntegerTy(1)) { continue; }
|
||||
|
||||
if (skip_icmp) {
|
||||
|
||||
skip_icmp--;
|
||||
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,
|
||||
ConstantInt::get(
|
||||
IntptrTy, (cnt_cov + local_selects++ +
|
||||
AllBlocks.size()))); newPhi->addIncoming(ptr, pred);
|
||||
|
||||
}
|
||||
|
||||
result = newPhi;
|
||||
skip_phi = 1;
|
||||
// fprintf(stderr, "Phi!\n");
|
||||
*/
|
||||
|
||||
} 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
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
|
||||
|
||||
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
|
||||
|
||||
if (tt) {
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else
|
||||
|
||||
#endif
|
||||
{
|
||||
{
|
||||
|
||||
// fprintf(stderr, "UNHANDLED: %u\n", t->getTypeID());
|
||||
unhandled++;
|
||||
continue;
|
||||
if (!be_quiet) {
|
||||
|
||||
WARNF("Warning: Unhandled ID type: %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);
|
||||
@ -1073,6 +1398,7 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
auto cf = IRB.CreateICmpEQ(Incr, Zero);
|
||||
auto carry = IRB.CreateZExt(cf, Int8Ty);
|
||||
Incr = IRB.CreateAdd(Incr, carry);
|
||||
skip_icmp++;
|
||||
|
||||
}
|
||||
|
||||
@ -1094,13 +1420,8 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
|
||||
}
|
||||
|
||||
skip_next = 1;
|
||||
instr += vector_cnt;
|
||||
|
||||
} else {
|
||||
|
||||
skip_next = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -1109,9 +1430,40 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
|
||||
if (AllBlocks.empty() && !special && !local_selects) return false;
|
||||
|
||||
if (!AllBlocks.empty())
|
||||
for (size_t i = 0, N = AllBlocks.size(); i < N; i++)
|
||||
InjectCoverageAtBlock(F, *AllBlocks[i], i, IsLeafFunc);
|
||||
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");
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
return true;
|
||||
|
||||
|
@ -119,6 +119,8 @@ 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;
|
||||
|
||||
@ -292,6 +294,25 @@ 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;
|
||||
|
||||
@ -305,8 +326,7 @@ static void __afl_map_shm_fuzz() {
|
||||
|
||||
}
|
||||
|
||||
map =
|
||||
(u8 *)mmap(0, MAX_FILE + sizeof(u32), PROT_READ, MAP_SHARED, shm_fd, 0);
|
||||
map = (u8 *)mmap(0, shm_fuzz_map_size, PROT_READ, MAP_SHARED, shm_fd, 0);
|
||||
|
||||
#else
|
||||
u32 shm_id = atoi(id_str);
|
||||
@ -362,6 +382,7 @@ static void __afl_map_shm(void) {
|
||||
if (getenv("AFL_DUMP_MAP_SIZE")) {
|
||||
|
||||
printf("%u\n", __afl_map_size);
|
||||
fflush(stdout);
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
@ -888,6 +909,12 @@ 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. */
|
||||
|
||||
@ -913,7 +940,12 @@ static void __afl_start_forkserver(void) {
|
||||
|
||||
}
|
||||
|
||||
if (write(FORKSRV_FD + 1, msg, 4) != 4) { _exit(1); }
|
||||
if (write(FORKSRV_FD + 1, msg, 4) != 4) {
|
||||
|
||||
errno = 0;
|
||||
_exit(1);
|
||||
|
||||
}
|
||||
|
||||
// Now send the parameters for the set options, increasing by option number
|
||||
|
||||
@ -1054,6 +1086,13 @@ static void __afl_start_forkserver(void) {
|
||||
|
||||
close(FORKSRV_FD);
|
||||
close(FORKSRV_FD + 1);
|
||||
|
||||
if (unlikely(__afl_forkserver_setenv)) {
|
||||
|
||||
unsetenv("AFL_FORKSERVER_PARENT");
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
@ -1226,6 +1265,15 @@ void __afl_manual_init(void) {
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_LLVM_ONLY_FSRV") || getenv("AFL_GCC_ONLY_FRSV")) {
|
||||
|
||||
fprintf(stderr,
|
||||
"DEBUG: Overwrite area_ptr to dummy due to "
|
||||
"AFL_LLVM_ONLY_FSRV/AFL_GCC_ONLY_FRSV\n");
|
||||
__afl_area_ptr = __afl_area_ptr_dummy;
|
||||
|
||||
}
|
||||
|
||||
if (!init_done) {
|
||||
|
||||
__afl_start_forkserver();
|
||||
|
@ -462,6 +462,7 @@ 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\
|
||||
@ -502,9 +503,10 @@ 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;
|
||||
register_callback(name, PLUGIN_INFO, NULL, &afl_plugin);
|
||||
if (!fsrv_only) { register_callback(name, PLUGIN_INFO, NULL, &afl_plugin); }
|
||||
|
||||
afl_pass *aflp = new afl_pass(quiet, inst_ratio);
|
||||
struct register_pass_info pass_info = {
|
||||
@ -516,14 +518,20 @@ int plugin_init(struct plugin_name_args *info,
|
||||
|
||||
};
|
||||
|
||||
register_callback(name, PLUGIN_PASS_MANAGER_SETUP, NULL, &pass_info);
|
||||
register_callback(name, PLUGIN_FINISH, afl_pass::plugin_finalize,
|
||||
pass_info.pass);
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -225,17 +225,17 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
if (getenv("AFL_DEBUG")) debug = 1;
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
if (getenv("AFL_SAN_NO_INST")) {
|
||||
if (getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
|
||||
if (debug) { fprintf(stderr, "Instrument disabled\n"); }
|
||||
if (debug) { fprintf(stderr, "Instrumentation disabled\n"); }
|
||||
return PreservedAnalyses::all();
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
if (getenv("AFL_SAN_NO_INST")) {
|
||||
if (getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
|
||||
if (debug) { fprintf(stderr, "Instrument disabled\n"); }
|
||||
if (debug) { fprintf(stderr, "Instrumentation disabled\n"); }
|
||||
return true;
|
||||
|
||||
}
|
||||
|
@ -64,6 +64,8 @@ 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> {
|
||||
|
||||
@ -92,6 +94,8 @@ 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 {
|
||||
|
||||
@ -106,7 +110,7 @@ class CmpLogInstructions : public ModulePass {
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool hookInstrs(Module &M);
|
||||
bool hookInstrs(Module &M, DomTreeCallback DTCallback);
|
||||
|
||||
};
|
||||
|
||||
@ -158,7 +162,16 @@ Iterator Unique(Iterator first, Iterator last) {
|
||||
|
||||
}
|
||||
|
||||
bool CmpLogInstructions::hookInstrs(Module &M) {
|
||||
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) {
|
||||
|
||||
std::vector<Instruction *> icomps;
|
||||
LLVMContext &C = M.getContext();
|
||||
@ -296,6 +309,7 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
|
||||
for (auto &F : M) {
|
||||
|
||||
if (!isInInstrumentList(&F, MNAME)) continue;
|
||||
const DominatorTree *DT = DTCallback(F);
|
||||
|
||||
for (auto &BB : F) {
|
||||
|
||||
@ -304,6 +318,12 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
|
||||
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);
|
||||
|
||||
}
|
||||
@ -681,11 +701,19 @@ 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);
|
||||
|
||||
bool ret = hookInstrs(M, DTCallback);
|
||||
verifyModule(M);
|
||||
|
||||
#if LLVM_MAJOR >= 11 /* use new pass manager */
|
||||
|
@ -1 +1 @@
|
||||
ef1cd9a8cb
|
||||
c43dd6e036
|
||||
|
Submodule qemu_mode/qemuafl updated: ef1cd9a8cb...c43dd6e036
@ -75,7 +75,6 @@ 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;
|
||||
@ -628,9 +627,7 @@ static void handle_stop_sig(int sig) {
|
||||
|
||||
static void set_up_environment(char **argv) {
|
||||
|
||||
u8 *x;
|
||||
char *afl_preload;
|
||||
char *frida_afl_preload = NULL;
|
||||
u8 *x;
|
||||
|
||||
fsrv.dev_null_fd = open("/dev/null", O_RDWR);
|
||||
if (fsrv.dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
|
||||
@ -672,57 +669,7 @@ static void set_up_environment(char **argv) {
|
||||
}
|
||||
|
||||
set_sanitizer_defaults();
|
||||
|
||||
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); }
|
||||
afl_fsrv_setup_preload(&fsrv, argv[0]);
|
||||
|
||||
}
|
||||
|
||||
@ -936,10 +883,9 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
case 'O': /* FRIDA mode */
|
||||
|
||||
if (frida_mode) { FATAL("Multiple -O options not supported"); }
|
||||
if (fsrv.frida_mode) { FATAL("Multiple -O options not supported"); }
|
||||
|
||||
frida_mode = 1;
|
||||
fsrv.frida_mode = frida_mode;
|
||||
fsrv.frida_mode = true;
|
||||
setenv("AFL_FRIDA_INST_SEED", "1", 1);
|
||||
|
||||
break;
|
||||
|
13
src/afl-cc.c
13
src/afl-cc.c
@ -244,7 +244,7 @@ static inline void insert_object(aflcc_state_t *aflcc, u8 *obj, u8 *fmt,
|
||||
/* Insert params into the new argv, make clang load the pass. */
|
||||
static inline void load_llvm_pass(aflcc_state_t *aflcc, u8 *pass) {
|
||||
|
||||
if (getenv("AFL_SAN_NO_INST")) {
|
||||
if (getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
|
||||
if (!be_quiet) { DEBUGF("SAND: Coverage instrumentation disabled\n"); }
|
||||
return;
|
||||
@ -2097,7 +2097,7 @@ void add_native_pcguard(aflcc_state_t *aflcc) {
|
||||
* anyway.
|
||||
*/
|
||||
if (aflcc->have_rust_asanrt) { return; }
|
||||
if (getenv("AFL_SAN_NO_INST")) {
|
||||
if (getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
|
||||
if (!be_quiet) { DEBUGF("SAND: Coverage instrumentation disabled\n"); }
|
||||
return;
|
||||
@ -2138,7 +2138,7 @@ void add_native_pcguard(aflcc_state_t *aflcc) {
|
||||
*/
|
||||
void add_optimized_pcguard(aflcc_state_t *aflcc) {
|
||||
|
||||
if (getenv("AFL_SAN_NO_INST")) {
|
||||
if (getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
|
||||
if (!be_quiet) { DEBUGF("SAND: Coverage instrumentation disabled\n"); }
|
||||
return;
|
||||
@ -2600,6 +2600,13 @@ 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);
|
||||
|
@ -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) + 1)) {
|
||||
if (afl_memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG))) {
|
||||
|
||||
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) + 1)) {
|
||||
if (afl_memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG))) {
|
||||
|
||||
if (!be_quiet) { OKF(cPIN "Deferred forkserver binary detected."); }
|
||||
setenv(DEFER_ENV_VAR, "1", 1);
|
||||
@ -819,7 +819,21 @@ void check_environment_vars(char **envp) {
|
||||
|
||||
WARNF("AFL environment variable %s is deprecated!",
|
||||
afl_environment_deprecated[i]);
|
||||
issue_detected = 1;
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -140,7 +140,7 @@ nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) {
|
||||
if (plugin->nyx_get_target_hash64 == NULL) { goto fail; }
|
||||
|
||||
plugin->nyx_config_free = dlsym(handle, "nyx_config_free");
|
||||
if (plugin->nyx_get_target_hash64 == NULL) { goto fail; }
|
||||
if (plugin->nyx_config_free == NULL) { goto fail; }
|
||||
|
||||
OKF("libnyx plugin is ready!");
|
||||
return plugin;
|
||||
@ -250,6 +250,16 @@ 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();
|
||||
@ -310,6 +320,38 @@ 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;
|
||||
@ -878,6 +920,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
|
||||
/* CHILD PROCESS */
|
||||
|
||||
if (unlikely(fsrv->setenv)) { setenv("AFL_FORKSERVER_PARENT", "1", 0); }
|
||||
|
||||
// enable terminating on sigpipe in the children
|
||||
struct sigaction sa;
|
||||
memset((char *)&sa, 0, sizeof(sa));
|
||||
|
@ -255,7 +255,8 @@ 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(). */
|
||||
|
||||
inline u8 has_new_bits_unclassified(afl_state_t *afl, u8 *virgin_map) {
|
||||
static inline u8 has_new_bits_unclassified(afl_state_t *afl, u8 *virgin_map,
|
||||
bool *classified) {
|
||||
|
||||
/* Handle the hot path first: no new coverage */
|
||||
u8 *end = afl->fsrv.trace_bits + afl->fsrv.map_size;
|
||||
@ -272,6 +273,7 @@ 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);
|
||||
|
||||
}
|
||||
@ -317,7 +319,15 @@ u8 *describe_op(afl_state_t *afl, u8 new_bits, size_t max_description_len) {
|
||||
|
||||
if (unlikely(afl->syncing_party)) {
|
||||
|
||||
sprintf(ret, "sync:%s,src:%06u", afl->syncing_party, afl->syncing_case);
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
@ -462,6 +472,46 @@ 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. */
|
||||
@ -469,8 +519,6 @@ void write_crash_readme(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)) {
|
||||
@ -479,7 +527,6 @@ 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))
|
||||
@ -493,13 +540,14 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
|
||||
u8 fn[PATH_MAX];
|
||||
u8 *queue_fn = "";
|
||||
u8 new_bits = 0, keeping = 0, res, is_timeout = 0, need_hash = 1;
|
||||
u8 keeping = 0, res, is_timeout = 0;
|
||||
u8 san_fault = 0, san_idx = 0, feed_san = 0;
|
||||
s32 fd;
|
||||
u64 cksum = 0;
|
||||
u32 cksum_simplified = 0, cksum_unique = 0;
|
||||
u8 san_fault = 0;
|
||||
u8 san_idx = 0;
|
||||
u8 feed_san = 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 */
|
||||
|
||||
afl->san_case_status = 0;
|
||||
|
||||
@ -509,10 +557,7 @@ 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)) {
|
||||
|
||||
classify_counts(&afl->fsrv);
|
||||
need_hash = 0;
|
||||
|
||||
cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
|
||||
calculate_cksum_if_necessary(afl, &cksum, &cksumed, &classified);
|
||||
|
||||
/* Saturated increment */
|
||||
if (likely(afl->n_fuzz[cksum % N_FUZZ_SIZE] < 0xFFFFFFFF))
|
||||
@ -547,7 +592,8 @@ 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 */
|
||||
new_bits = has_new_bits_unclassified(afl, afl->virgin_bits);
|
||||
calculate_new_bits_if_necessary(afl, &new_bits, &bits_counted,
|
||||
&classified);
|
||||
|
||||
if (unlikely(new_bits)) { feed_san = 1; }
|
||||
|
||||
@ -556,15 +602,9 @@ 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.
|
||||
if (!classified) {
|
||||
|
||||
classify_counts(&afl->fsrv);
|
||||
classified = 1;
|
||||
|
||||
}
|
||||
classify_if_necessary(afl, &classified);
|
||||
|
||||
cksum_unique =
|
||||
hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
|
||||
@ -624,22 +664,7 @@ 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. */
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
calculate_new_bits_if_necessary(afl, &new_bits, &bits_counted, &classified);
|
||||
|
||||
if (likely(!new_bits)) {
|
||||
|
||||
@ -662,6 +687,11 @@ 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) {
|
||||
@ -743,6 +773,8 @@ 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;
|
||||
@ -750,17 +782,8 @@ 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 (likely(cksum)) {
|
||||
if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
|
||||
|
||||
afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE;
|
||||
afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1;
|
||||
@ -859,7 +882,9 @@ may_save_fault:
|
||||
}
|
||||
|
||||
new_fault = fuzz_run_target(afl, &afl->fsrv, afl->hang_tmout);
|
||||
classify_counts(&afl->fsrv);
|
||||
classified = false;
|
||||
bits_counted = false;
|
||||
cksumed = false;
|
||||
|
||||
/* A corner case that one user reported bumping into: increasing the
|
||||
timeout actually uncovers a crash. Make sure we don't discard it if
|
||||
|
@ -589,8 +589,6 @@ 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);
|
||||
@ -653,17 +651,14 @@ 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);
|
||||
|
||||
}
|
||||
|
||||
@ -673,12 +668,21 @@ 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;
|
||||
@ -756,21 +760,10 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
|
||||
if (nl_cnt) {
|
||||
|
||||
u32 done = 0;
|
||||
|
||||
if (unlikely(afl->in_place_resume)) {
|
||||
|
||||
i = nl_cnt;
|
||||
|
||||
} else {
|
||||
|
||||
i = 0;
|
||||
|
||||
}
|
||||
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,
|
||||
@ -850,22 +843,12 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
|
||||
}
|
||||
|
||||
next_entry:
|
||||
if (unlikely(afl->in_place_resume)) {
|
||||
|
||||
if (unlikely(i == 0)) { done = 1; }
|
||||
|
||||
} else {
|
||||
|
||||
if (unlikely(++i >= (u32)nl_cnt)) { done = 1; }
|
||||
|
||||
}
|
||||
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) {
|
||||
@ -909,9 +892,21 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
|
||||
struct queue_entry *q;
|
||||
u32 cal_failures = 0, idx;
|
||||
u8 *use_mem;
|
||||
u8 *use_mem, done = 0;
|
||||
|
||||
for (idx = 0; idx < afl->queued_items; idx++) {
|
||||
if (afl->in_place_resume) {
|
||||
|
||||
idx = afl->queued_items;
|
||||
|
||||
} else {
|
||||
|
||||
idx = 0;
|
||||
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
if (afl->in_place_resume) { --idx; }
|
||||
|
||||
q = afl->queue_buf[idx];
|
||||
if (unlikely(!q || q->disabled)) { continue; }
|
||||
@ -1378,7 +1373,17 @@ 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) {
|
||||
|
||||
@ -1407,67 +1412,51 @@ 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] && !done); ++i) {
|
||||
for (i = idx + 1; likely(i < afl->queued_items && afl->queue_buf[i]); ++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;
|
||||
|
||||
if (p->exec_cksum == q->exec_cksum) {
|
||||
duplicates = 1;
|
||||
|
||||
duplicates = 1;
|
||||
// we keep the shorter file
|
||||
struct queue_entry *to_disable, *to_keep;
|
||||
if (p->len >= q->len) {
|
||||
|
||||
// we keep the shorter file
|
||||
if (p->len >= q->len) {
|
||||
to_disable = p;
|
||||
to_keep = q;
|
||||
|
||||
if (!p->was_fuzzed) {
|
||||
} else {
|
||||
|
||||
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
|
||||
|
||||
}
|
||||
to_disable = q;
|
||||
to_keep = p;
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -1557,8 +1546,9 @@ 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 (!strncmp(rsl, CASE_PREFIX, 3) &&
|
||||
sscanf(rsl + 3, "%06u", &orig_id) == 1 && orig_id == id) {
|
||||
if (afl->in_place_resume ||
|
||||
(!strncmp(rsl, CASE_PREFIX, 3) &&
|
||||
sscanf(rsl + 3, "%06u", &orig_id) == 1 && orig_id == id)) {
|
||||
|
||||
u8 *src_str;
|
||||
u32 src_id;
|
||||
@ -2801,9 +2791,9 @@ void fix_up_sync(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
if (strlen(afl->sync_id) > 50) {
|
||||
if (strlen(afl->sync_id) > SYNC_ID_MAX_LEN) {
|
||||
|
||||
FATAL("sync_id max length is 50 characters");
|
||||
FATAL("sync_id max length is %d characters", SYNC_ID_MAX_LEN);
|
||||
|
||||
}
|
||||
|
||||
@ -2911,11 +2901,16 @@ 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
|
||||
u8 *map = afl_shm_init(afl->shm_fuzz, MAX_FILE + sizeof(u32), 1);
|
||||
size_t shm_fuzz_map_size = SHM_FUZZ_MAP_SIZE_DEFAULT;
|
||||
u8 *map = afl_shm_init(afl->shm_fuzz, shm_fuzz_map_size, 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
|
||||
@ -3116,7 +3111,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) + 1)) {
|
||||
!afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR))) {
|
||||
|
||||
SAYF("\n" cLRD "[-] " cRST
|
||||
"Looks like the target binary is not instrumented! The fuzzer depends "
|
||||
@ -3147,7 +3142,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) + 1)) {
|
||||
afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR))) {
|
||||
|
||||
SAYF("\n" cLRD "[-] " cRST
|
||||
"This program appears to be instrumented with AFL++ compilers, but is "
|
||||
@ -3182,7 +3177,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) + 1)) {
|
||||
if (afl_memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG))) {
|
||||
|
||||
OKF(cPIN "Persistent mode binary detected.");
|
||||
setenv(PERSIST_ENV_VAR, "1", 1);
|
||||
@ -3209,7 +3204,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) + 1)) {
|
||||
afl_memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG))) {
|
||||
|
||||
OKF(cPIN "Deferred forkserver binary detected.");
|
||||
setenv(DEFER_ENV_VAR, "1", 1);
|
||||
|
@ -411,11 +411,12 @@ 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, %llu crashes saved, state: %s, "
|
||||
"Fuzzing test case #%u (%u total, %s%llu crashes saved%s, 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,
|
||||
afl->current_entry, afl->queued_items,
|
||||
afl->saved_crashes != 0 ? cRED : "", afl->saved_crashes, cRST,
|
||||
get_fuzzing_state(afl), afl->fuzz_mode ? "exploit" : "explore",
|
||||
afl->queue_cur->perf_score, afl->queue_cur->weight,
|
||||
afl->queue_cur->favored, afl->queue_cur->was_fuzzed,
|
||||
|
@ -26,8 +26,10 @@
|
||||
|
||||
#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
|
||||
@ -493,36 +495,41 @@ 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)) {
|
||||
}
|
||||
|
||||
fault = FSRV_RUN_NOINST;
|
||||
goto abort_calibration;
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
#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 (hnb > new_bits) { new_bits = hnb; }
|
||||
if (unlikely(hnb > new_bits)) { new_bits = hnb; }
|
||||
|
||||
}
|
||||
|
||||
@ -551,7 +558,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 && !afl->stage_cur &&
|
||||
if (!afl->non_instrumented_mode &&
|
||||
!count_bytes(afl, afl->fsrv.trace_bits)) {
|
||||
|
||||
fault = FSRV_RUN_NOINST;
|
||||
@ -560,17 +567,19 @@ 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 (q->exec_cksum != cksum) {
|
||||
|
||||
if (unlikely(q->exec_cksum != cksum)) {
|
||||
|
||||
hnb = has_new_bits(afl, afl->virgin_bits);
|
||||
if (hnb > new_bits) { new_bits = hnb; }
|
||||
|
||||
if (q->exec_cksum) {
|
||||
if (unlikely(hnb > new_bits)) { new_bits = hnb; }
|
||||
|
||||
if (likely(q->exec_cksum)) {
|
||||
|
||||
u32 i;
|
||||
|
||||
@ -697,6 +706,110 @@ 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) {
|
||||
@ -715,8 +828,7 @@ 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))) {
|
||||
|
||||
@ -724,12 +836,11 @@ 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];
|
||||
u32 min_accept = 0, next_min_accept = 0;
|
||||
|
||||
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;
|
||||
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)) {
|
||||
|
||||
@ -764,14 +875,7 @@ void sync_fuzzers(afl_state_t *afl) {
|
||||
|
||||
synced++;
|
||||
|
||||
/* 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. */
|
||||
// Skip anything that doesn't have a queue/ subdirectory.
|
||||
|
||||
sprintf(qd_path, "%s/%s/queue", afl->sync_dir, sd_ent->d_name);
|
||||
|
||||
@ -787,7 +891,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);
|
||||
|
||||
@ -802,6 +906,55 @@ 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);
|
||||
@ -855,34 +1008,37 @@ void sync_fuzzers(afl_state_t *afl) {
|
||||
|
||||
if (st.st_size && st.st_size <= MAX_FILE) {
|
||||
|
||||
u8 fault;
|
||||
u8 *mem = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (likely(next_min_accept < max_start_id ||
|
||||
!is_known_case(afl, namelist[o]->d_name))) {
|
||||
|
||||
if (mem == MAP_FAILED) { PFATAL("Unable to mmap '%s'", path); }
|
||||
/* See what happens. We rely on save_if_interesting() to catch major
|
||||
errors and save the test case. */
|
||||
|
||||
/* See what happens. We rely on save_if_interesting() to catch major
|
||||
errors and save the test case. */
|
||||
u8 *mem = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
|
||||
u32 new_len = write_to_testcase(afl, (void **)&mem, st.st_size, 1);
|
||||
if (mem == MAP_FAILED) { PFATAL("Unable to mmap '%s'", path); }
|
||||
|
||||
fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
|
||||
u32 new_len = write_to_testcase(afl, (void **)&mem, st.st_size, 1);
|
||||
|
||||
if (afl->stop_soon) {
|
||||
u8 fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
|
||||
|
||||
if (afl->stop_soon) {
|
||||
|
||||
munmap(mem, st.st_size);
|
||||
close(fd);
|
||||
|
||||
goto close_sync;
|
||||
|
||||
}
|
||||
|
||||
afl->syncing_party = sd_ent->d_name;
|
||||
afl->queued_imported += save_if_interesting(afl, mem, new_len, fault);
|
||||
show_stats(afl);
|
||||
afl->syncing_party = 0;
|
||||
munmap(mem, st.st_size);
|
||||
close(fd);
|
||||
|
||||
goto close_sync;
|
||||
|
||||
}
|
||||
|
||||
afl->syncing_party = sd_ent->d_name;
|
||||
afl->queued_imported += save_if_interesting(afl, mem, new_len, fault);
|
||||
show_stats(afl);
|
||||
afl->syncing_party = 0;
|
||||
|
||||
munmap(mem, st.st_size);
|
||||
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
@ -39,6 +39,9 @@ void sanfuzz_exec_child(afl_forkserver_t *fsrv, char **argv) {
|
||||
|
||||
}
|
||||
|
||||
// In case users provide the normally instrumented binaries, this servers as
|
||||
// the last resort to avoid collecting incorrect coverage.
|
||||
setenv("AFL_LLVM_ONLY_FSRV", "1", 0);
|
||||
execv(fsrv->target_path, argv);
|
||||
|
||||
}
|
||||
|
@ -148,6 +148,34 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) {
|
||||
|
||||
}
|
||||
|
||||
void afl_resize_map_buffers(afl_state_t *afl, u32 old_size, u32 new_size) {
|
||||
|
||||
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_size);
|
||||
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_size);
|
||||
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_size);
|
||||
afl->var_bytes = ck_realloc(afl->var_bytes, new_size);
|
||||
afl->top_rated = ck_realloc(afl->top_rated, new_size * sizeof(void *));
|
||||
afl->clean_trace = ck_realloc(afl->clean_trace, new_size);
|
||||
afl->clean_trace_custom = ck_realloc(afl->clean_trace_custom, new_size);
|
||||
afl->first_trace = ck_realloc(afl->first_trace, new_size);
|
||||
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_size);
|
||||
|
||||
if (old_size < new_size) {
|
||||
|
||||
u32 size_diff = new_size - old_size;
|
||||
|
||||
memset(afl->var_bytes + old_size, 0, size_diff);
|
||||
memset(afl->top_rated + old_size * sizeof(void *), 0,
|
||||
size_diff * sizeof(void *));
|
||||
memset(afl->clean_trace + old_size, 0, size_diff);
|
||||
memset(afl->clean_trace_custom + old_size, 0, size_diff);
|
||||
memset(afl->first_trace + old_size, 0, size_diff);
|
||||
memset(afl->map_tmp_buf + old_size, 0, size_diff);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*This sets up the environment variables for afl-fuzz into the afl_state
|
||||
* struct*/
|
||||
|
||||
|
@ -28,8 +28,13 @@
|
||||
#include "envs.h"
|
||||
#include <limits.h>
|
||||
|
||||
static char fuzzing_state[4][12] = {"started :-)", "in progress", "final phase",
|
||||
"finished..."};
|
||||
// 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};
|
||||
|
||||
char *get_fuzzing_state(afl_state_t *afl) {
|
||||
|
||||
@ -54,13 +59,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 >= 80 && percent_total >= 80)) {
|
||||
if (unlikely(percent_cur >= 75 && percent_total >= 75)) {
|
||||
|
||||
if (unlikely(afl->afl_env.afl_exit_when_done)) { afl->stop_soon = 2; }
|
||||
|
||||
return fuzzing_state[3];
|
||||
|
||||
} else if (unlikely(percent_cur >= 55 && percent_total >= 55)) {
|
||||
} else if (unlikely(percent_cur >= 50 && percent_total >= 50)) {
|
||||
|
||||
return fuzzing_state[2];
|
||||
|
||||
|
103
src/afl-fuzz.c
103
src/afl-fuzz.c
@ -1745,7 +1745,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,11 +2307,7 @@ 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)
|
||||
#ifdef __linux__
|
||||
|| (afl->fsrv.nyx_mode && target_hash == 0)
|
||||
#endif
|
||||
) {
|
||||
if (!target_hash || prev_target_hash != target_hash) {
|
||||
|
||||
ACTF("Target binary is different, cannot perform FAST RESUME!");
|
||||
|
||||
@ -2502,29 +2498,8 @@ 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->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);
|
||||
|
||||
}
|
||||
afl_resize_map_buffers(afl, map_size, MAP_SIZE);
|
||||
|
||||
}
|
||||
|
||||
@ -2552,31 +2527,7 @@ 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);
|
||||
|
||||
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_resize_map_buffers(afl, map_size, new_map_size);
|
||||
|
||||
afl_fsrv_kill(&afl->fsrv);
|
||||
afl_shm_deinit(&afl->shm);
|
||||
@ -2637,7 +2588,6 @@ 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;
|
||||
@ -2647,10 +2597,6 @@ 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 &&
|
||||
@ -2673,18 +2619,7 @@ 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->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_resize_map_buffers(afl, map_size, new_map_size);
|
||||
|
||||
afl_fsrv_kill(&afl->fsrv);
|
||||
afl_fsrv_kill(&afl->san_fsrvs[i]);
|
||||
@ -2750,31 +2685,7 @@ 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);
|
||||
|
||||
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_resize_map_buffers(afl, map_size, new_map_size);
|
||||
|
||||
afl_fsrv_kill(&afl->fsrv);
|
||||
afl_fsrv_kill(&afl->cmplog_fsrv);
|
||||
@ -3002,6 +2913,8 @@ 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) {
|
||||
|
@ -71,6 +71,7 @@ void afl_shm_deinit(sharedmem_t *shm) {
|
||||
if (shm->shmemfuzz_mode) {
|
||||
|
||||
unsetenv(SHM_FUZZ_ENV_VAR);
|
||||
unsetenv(SHM_FUZZ_MAP_SIZE_ENV_VAR);
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -714,61 +714,8 @@ 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();
|
||||
|
||||
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); }
|
||||
afl_fsrv_setup_preload(fsrv, argv[0]);
|
||||
|
||||
}
|
||||
|
||||
@ -1540,9 +1487,15 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
shm_fuzz->cmplog_mode = 0;
|
||||
atexit(at_exit_handler);
|
||||
|
||||
u8 *map = afl_shm_init(shm_fuzz, MAX_FILE + sizeof(u32), 1);
|
||||
size_t shm_fuzz_map_size = SHM_FUZZ_MAP_SIZE_DEFAULT;
|
||||
u8 *map = afl_shm_init(shm_fuzz, shm_fuzz_map_size, 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
|
||||
@ -1589,7 +1542,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 && new_map_size - map_size > MAP_SIZE)) {
|
||||
(new_map_size < map_size && map_size - new_map_size > MAP_SIZE)) {
|
||||
|
||||
if (!be_quiet)
|
||||
ACTF("Acquired new map size for target: %u bytes\n", new_map_size);
|
||||
|
@ -899,9 +899,7 @@ static void handle_stop_sig(int sig) {
|
||||
|
||||
static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
|
||||
|
||||
u8 *x;
|
||||
char *afl_preload;
|
||||
char *frida_afl_preload = NULL;
|
||||
u8 *x;
|
||||
|
||||
fsrv->dev_null_fd = open("/dev/null", O_RDWR);
|
||||
if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
|
||||
@ -945,57 +943,7 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
|
||||
}
|
||||
|
||||
set_sanitizer_defaults();
|
||||
|
||||
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); }
|
||||
afl_fsrv_setup_preload(fsrv, argv[0]);
|
||||
|
||||
}
|
||||
|
||||
@ -1481,9 +1429,16 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
/* initialize cmplog_mode */
|
||||
shm_fuzz->cmplog_mode = 0;
|
||||
u8 *map = afl_shm_init(shm_fuzz, MAX_FILE + sizeof(u32), 1);
|
||||
|
||||
size_t shm_fuzz_map_size = SHM_FUZZ_MAP_SIZE_DEFAULT;
|
||||
u8 *map = afl_shm_init(shm_fuzz, shm_fuzz_map_size, 1);
|
||||
shm_fuzz->shmemfuzz_mode = 1;
|
||||
if (!map) { FATAL("BUG: Zero return from afl_shm_init."); }
|
||||
|
||||
u8 *shm_fuzz_map_size_str = alloc_printf("%zu", shm_fuzz_map_size);
|
||||
setenv(SHM_FUZZ_MAP_SIZE_ENV_VAR, shm_fuzz_map_size_str, 1);
|
||||
ck_free(shm_fuzz_map_size_str);
|
||||
|
||||
#ifdef USEMMAP
|
||||
setenv(SHM_FUZZ_ENV_VAR, shm_fuzz->g_shm_file_path, 1);
|
||||
#else
|
||||
|
@ -49,7 +49,11 @@ 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
|
||||
|
||||
}
|
||||
|
||||
@ -77,6 +81,10 @@ int main(int argc, char **argv) {
|
||||
|
||||
}
|
||||
|
||||
#ifdef EXIT_AT_END
|
||||
exit(0);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
@ -16,7 +16,8 @@ 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
|
||||
test -e test-instr -a -e test-compcov && {
|
||||
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 && {
|
||||
{
|
||||
mkdir -p in
|
||||
echo 00000 > in/in
|
||||
@ -149,11 +150,63 @@ test -e ../afl-qemu-trace && {
|
||||
$ECHO "$RED[!] afl-fuzz is not working correctly with persistent qemu_mode"
|
||||
CODE=1
|
||||
}
|
||||
rm -rf in out errors
|
||||
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"
|
||||
}
|
||||
|
||||
test -e ../qemu_mode/unsigaction/unsigaction32.so && {
|
||||
${AFL_CC} -o test-unsigaction32 -m32 test-unsigaction.c >> errors 2>&1 && {
|
||||
./test-unsigaction32
|
||||
@ -212,7 +265,7 @@ test -e ../afl-qemu-trace && {
|
||||
CODE=1
|
||||
}
|
||||
|
||||
rm -f test-instr test-compcov
|
||||
rm -f test-instr test-compcov test-instr-exit-at-end
|
||||
} || {
|
||||
$ECHO "$YELLOW[-] qemu_mode is not compiled, cannot test"
|
||||
INCOMPLETE=1
|
||||
|
@ -18,7 +18,8 @@ ifneq "" "$(LLVM_BINDIR)"
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS := -O3 -funroll-loops -g -fPIC
|
||||
CFLAGS := -O3 -funroll-loops -g -fPIC -fno-lto
|
||||
AR ?= ar
|
||||
|
||||
ifdef IOS_SDK_PATH
|
||||
CFLAGS += -isysroot $(IOS_SDK_PATH)
|
||||
@ -30,7 +31,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:
|
||||
@ -38,13 +39,13 @@ debug:
|
||||
$(CC) -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c
|
||||
#$(CC) -S -emit-llvm -Wno-deprecated -I../../include $(CFLAGS) -D_DEBUG=\"1\" -c -o afl-performance.ll ../../src/afl-performance.c
|
||||
#$(CC) -S -emit-llvm -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c
|
||||
ar rc libAFLDriver.a afl-performance.o aflpp_driver.o
|
||||
$(AR) rc libAFLDriver.a afl-performance.o aflpp_driver.o
|
||||
|
||||
aflpp_qemu_driver.o: aflpp_qemu_driver.c
|
||||
-$(CC) $(CFLAGS) -O0 -funroll-loops -c aflpp_qemu_driver.c
|
||||
|
||||
libAFLQemuDriver.a: aflpp_qemu_driver.o
|
||||
@-ar rc libAFLQemuDriver.a aflpp_qemu_driver.o
|
||||
@-$(AR) rc libAFLQemuDriver.a aflpp_qemu_driver.o
|
||||
@-cp -vf libAFLQemuDriver.a ../../
|
||||
|
||||
aflpp_qemu_driver_hook.so: aflpp_qemu_driver_hook.o
|
||||
|
@ -64,6 +64,15 @@ 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;
|
||||
@ -106,14 +115,11 @@ __attribute__((weak)) void __asan_unpoison_memory_region(
|
||||
__attribute__((weak)) void *__asan_region_is_poisoned(void *beg, size_t size);
|
||||
|
||||
// Notify AFL about persistent mode.
|
||||
__attribute__((section(".rodata"), used,
|
||||
retain)) static const char AFL_PERSISTENT[] =
|
||||
"##SIG_AFL_PERSISTENT##";
|
||||
int __afl_persistent_loop(unsigned int);
|
||||
SECTION_RODATA static const char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
|
||||
int __afl_persistent_loop(unsigned int);
|
||||
|
||||
// Notify AFL about deferred forkserver.
|
||||
__attribute__((section(".rodata"), used,
|
||||
retain)) static const char AFL_DEFER_FORKSVR[] =
|
||||
SECTION_RODATA static const char AFL_DEFER_FORKSVR[] =
|
||||
"##SIG_AFL_DEFER_FORKSRV##";
|
||||
void __afl_manual_init();
|
||||
|
||||
|
12
utils/libaflppdesock/Makefile
Normal file
12
utils/libaflppdesock/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
# 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
|
46
utils/libaflppdesock/README.md
Normal file
46
utils/libaflppdesock/README.md
Normal file
@ -0,0 +1,46 @@
|
||||
# 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
|
||||
```
|
||||
|
||||
`
|
352
utils/libaflppdesock/libaflppdesock.c
Normal file
352
utils/libaflppdesock/libaflppdesock.c
Normal file
@ -0,0 +1,352 @@
|
||||
/* desocket library by Marc "vanHauser" Heuse <vh@thc.org>
|
||||
*
|
||||
* Use this library for fuzzing if preeny's desock and desock2 solutions
|
||||
* do not work for you - these would provide faster performance.
|
||||
*
|
||||
*/
|
||||
|
||||
// default: file descriptor 0 for stdin
|
||||
#define FUZZ_INPUT_FD 0
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void *handle;
|
||||
static bool do_fork, do_close, debug, running;
|
||||
static int port = -1;
|
||||
static int listen_fd = -1;
|
||||
|
||||
struct myin_addr {
|
||||
|
||||
unsigned int s_addr; // IPv4 address in network byte order
|
||||
|
||||
};
|
||||
|
||||
struct mysockaddr {
|
||||
|
||||
unsigned short int sin_family; // Address family: AF_INET
|
||||
unsigned short int sin_port; // Port number (network byte order)
|
||||
struct myin_addr sin_addr; // Internet address
|
||||
char sin_zero[8]; // Padding (unused)
|
||||
|
||||
};
|
||||
|
||||
#define RTLD_LAZY 0x00001
|
||||
|
||||
unsigned short int htons(unsigned short int hostshort) {
|
||||
|
||||
return (hostshort << 8) | (hostshort >> 8);
|
||||
|
||||
}
|
||||
|
||||
static void __get_handle() {
|
||||
|
||||
if (!(handle = dlopen("libc.so", RTLD_NOW))) {
|
||||
|
||||
if (!(handle = dlopen("libc.so.6", RTLD_NOW))) {
|
||||
|
||||
if (!(handle = dlopen("libc-orig.so", RTLD_LAZY))) {
|
||||
|
||||
if (!(handle = dlopen("cygwin1.dll", RTLD_LAZY))) {
|
||||
|
||||
if (!(handle = dlopen("libc.so", RTLD_NOW))) {
|
||||
|
||||
fprintf(stderr, "DESOCK: can not find libc!\n");
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (getenv("DESOCK_DEBUG")) { debug = true; }
|
||||
if (getenv("DESOCK_PORT")) { port = atoi(getenv("DESOCK_PORT")); }
|
||||
if (getenv("DESOCK_FORK")) { do_fork = true; }
|
||||
if (getenv("DESOCK_CLOSE_EXIT")) { do_close = true; }
|
||||
if (debug) fprintf(stderr, "DESOCK: initialized!\n");
|
||||
|
||||
}
|
||||
|
||||
int (*o_shutdown)(int socket, int how);
|
||||
int shutdown(int socket, int how) {
|
||||
|
||||
if (port != -1 && socket == FUZZ_INPUT_FD && running) {
|
||||
|
||||
running = false;
|
||||
if (do_close) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: exiting\n");
|
||||
_exit(0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (port == -1 && do_close) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: exiting\n");
|
||||
_exit(0);
|
||||
|
||||
}
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_shutdown) { o_shutdown = dlsym(handle, "shutdown"); }
|
||||
return o_shutdown(socket, how);
|
||||
|
||||
}
|
||||
|
||||
int (*o_close)(int socket);
|
||||
int close(int socket) {
|
||||
|
||||
if (port != -1 && socket == FUZZ_INPUT_FD && running) {
|
||||
|
||||
running = false;
|
||||
if (do_close) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: exiting\n");
|
||||
_exit(0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (listen_fd != -1 && socket == listen_fd) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: close bind\n");
|
||||
listen_fd = -1;
|
||||
|
||||
}
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_close) { o_close = dlsym(handle, "close"); }
|
||||
return o_close(socket);
|
||||
|
||||
}
|
||||
|
||||
int (*o_fork)(void);
|
||||
int fork() {
|
||||
|
||||
if (do_fork) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: fake fork\n");
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_fork) { o_fork = dlsym(handle, "fork"); }
|
||||
return o_fork();
|
||||
|
||||
}
|
||||
|
||||
int (*o_accept)(int sockfd, struct mysockaddr *addr,
|
||||
unsigned long int *addrlen);
|
||||
int accept(int sockfd, struct mysockaddr *addr, unsigned long int *addrlen) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_accept) { o_accept = dlsym(handle, "accept"); }
|
||||
if (!running && sockfd == listen_fd) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: intercepted accept on %d\n", sockfd);
|
||||
if (addr && addrlen) {
|
||||
|
||||
// we need to fill this!
|
||||
memset(addr, 0, *addrlen);
|
||||
addr->sin_family = 2; // AF_INET
|
||||
addr->sin_port = htons(1023); // Port 1023 in network byte order
|
||||
addr->sin_addr.s_addr = 0x0100007f;
|
||||
|
||||
}
|
||||
|
||||
running = true;
|
||||
return FUZZ_INPUT_FD;
|
||||
|
||||
}
|
||||
|
||||
return o_accept(sockfd, addr, addrlen);
|
||||
|
||||
}
|
||||
|
||||
int accept4(int sockfd, struct mysockaddr *addr, unsigned long int *addrlen,
|
||||
int flags) {
|
||||
|
||||
return accept(sockfd, addr, addrlen); // ignore flags
|
||||
|
||||
}
|
||||
|
||||
int (*o_listen)(int sockfd, int backlog);
|
||||
int listen(int sockfd, int backlog) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_listen) { o_listen = dlsym(handle, "listen"); }
|
||||
if (sockfd == listen_fd) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: intercepted listen on %d\n", sockfd);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return o_listen(sockfd, backlog);
|
||||
|
||||
}
|
||||
|
||||
int (*o_bind)(int sockfd, const struct mysockaddr *addr,
|
||||
unsigned long int addrlen);
|
||||
int bind(int sockfd, const struct mysockaddr *addr, unsigned long int addrlen) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_bind) { o_bind = dlsym(handle, "bind"); }
|
||||
if (addr->sin_port == htons(port)) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: intercepted bind on %d\n", sockfd);
|
||||
listen_fd = sockfd;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return o_bind(sockfd, addr, addrlen);
|
||||
|
||||
}
|
||||
|
||||
int (*o_setsockopt)(int sockfd, int level, int optname, const void *optval,
|
||||
unsigned long int optlen);
|
||||
int setsockopt(int sockfd, int level, int optname, const void *optval,
|
||||
unsigned long int optlen) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_setsockopt) { o_setsockopt = dlsym(handle, "setsockopt"); }
|
||||
if (listen_fd == sockfd) {
|
||||
|
||||
if (debug)
|
||||
fprintf(stderr, "DESOCK: intercepted setsockopt on %d for %d\n", sockfd,
|
||||
optname);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return o_setsockopt(sockfd, level, optname, optval, optlen);
|
||||
|
||||
}
|
||||
|
||||
int (*o_getsockopt)(int sockfd, int level, int optname, void *optval,
|
||||
unsigned long int *optlen);
|
||||
int getsockopt(int sockfd, int level, int optname, void *optval,
|
||||
unsigned long int *optlen) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_getsockopt) { o_getsockopt = dlsym(handle, "getsockopt"); }
|
||||
if (listen_fd == sockfd) {
|
||||
|
||||
if (debug)
|
||||
fprintf(stderr, "DESOCK: intercepted getsockopt on %d for %d\n", sockfd,
|
||||
optname);
|
||||
int *o = (int *)optval;
|
||||
if (o != NULL) {
|
||||
|
||||
*o = 1; // let's hope this is fine
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return o_getsockopt(sockfd, level, optname, optval, optlen);
|
||||
|
||||
}
|
||||
|
||||
int (*o_getpeername)(int sockfd, struct mysockaddr *addr,
|
||||
unsigned long int *addrlen);
|
||||
int getpeername(int sockfd, struct mysockaddr *addr,
|
||||
unsigned long int *addrlen) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_getpeername) { o_getpeername = dlsym(handle, "getpeername"); }
|
||||
if (port != -1 && sockfd == FUZZ_INPUT_FD) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: getpeername\n");
|
||||
if (addr && addrlen) {
|
||||
|
||||
// we need to fill this!
|
||||
memset(addr, 0, *addrlen);
|
||||
addr->sin_family = 2; // AF_INET
|
||||
addr->sin_port = htons(1023); // Port 1023 in network byte order
|
||||
addr->sin_addr.s_addr = 0x0100007f;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return o_getpeername(sockfd, addr, addrlen);
|
||||
|
||||
}
|
||||
|
||||
int (*o_getsockname)(int sockfd, struct mysockaddr *addr,
|
||||
unsigned long int *addrlen);
|
||||
int getsockname(int sockfd, struct mysockaddr *addr,
|
||||
unsigned long int *addrlen) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_getsockname) { o_getsockname = dlsym(handle, "getsockname"); }
|
||||
if (port != -1 && sockfd == FUZZ_INPUT_FD) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: getsockname\n");
|
||||
if (addr && addrlen) {
|
||||
|
||||
// we need to fill this!
|
||||
memset(addr, 0, *addrlen);
|
||||
addr->sin_family = 2; // AF_INET
|
||||
addr->sin_port = htons(port);
|
||||
addr->sin_addr.s_addr = 0x0100007f;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return o_getsockname(sockfd, addr, addrlen);
|
||||
|
||||
}
|
||||
|
||||
static FILE *(*o_fdopen)(int fd, const char *mode);
|
||||
FILE *fdopen(int fd, const char *mode) {
|
||||
|
||||
if (!o_fdopen) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
|
||||
o_fdopen = dlsym(handle, "fdopen");
|
||||
if (!o_fdopen) {
|
||||
|
||||
fprintf(stderr, "%s(): can not find fdopen\n", dlerror());
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (fd == FUZZ_INPUT_FD && strcmp(mode, "r") != 0) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: intercepted fdopen(r+) for %d\n", fd);
|
||||
return o_fdopen(fd, "r");
|
||||
|
||||
}
|
||||
|
||||
return o_fdopen(fd, mode);
|
||||
|
||||
}
|
||||
|
||||
/* TARGET SPECIFIC HOOKS - put extra needed code for your target here */
|
||||
|
@ -19,11 +19,11 @@ HELPER_PATH = $(PREFIX)/lib/afl
|
||||
VERSION = $(shell grep '^\#define VERSION ' ../../config.h | cut -d '"' -f2)
|
||||
|
||||
CFLAGS ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2
|
||||
CFLAGS += -I ../../include/ -Wall -g -Wno-pointer-sign
|
||||
override CFLAGS += -I ../../include/ -Wall -g -Wno-pointer-sign
|
||||
|
||||
CFLAGS_ADD=$(USEHUGEPAGE:1=-DUSEHUGEPAGE)
|
||||
CFLAGS_ADD += $(USENAMEDPAGE:1=-DUSENAMEDPAGE)
|
||||
CFLAGS += $(CFLAGS_ADD)
|
||||
override CFLAGS += $(CFLAGS_ADD)
|
||||
|
||||
all: libdislocator.so
|
||||
|
||||
@ -41,4 +41,3 @@ install: all
|
||||
install -m 755 -d $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 755 ../../libdislocator.so $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 644 -T README.md $${DESTDIR}$(HELPER_PATH)/README.dislocator.md
|
||||
|
||||
|
Reference in New Issue
Block a user