Compare commits

..

12 Commits
dev ... release

102 changed files with 2608 additions and 3611 deletions

View File

@ -9,79 +9,7 @@ on:
branches:
- dev # No need for stable-pull-request, as that equals dev-push
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
check-compiler-passes-old:
runs-on: ubuntu-22.04
strategy:
matrix:
version: [14, 15]
env:
AFL_SKIP_CPUFREQ: 1
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
steps:
- uses: actions/checkout@v4
- name: update
run: sudo apt-get update && sudo apt-get upgrade -y
- name: debug
run: apt-cache search plugin-dev | grep gcc-; echo; apt-cache search clang-format- | grep clang-format-
- name: install packages
run: sudo apt-get install -y -m -f build-essential git libtool libtool-bin automake flex bison libglib2.0-0 libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build python3-pip gcc-12-plugin-dev
- name: install llvm-tools
run: sudo apt install -y clang-${{ matrix.version }} llvm-${{ matrix.version }}
- name: install clang-rt (for llvm 15)
# because ubuntu-22.04 already has this package
if: matrix.version != '15'
run: sudo apt install -y libclang-${{ matrix.version }}-dev
- name: compiler installed
run: gcc -v; echo; clang -v
- name: build afl++
run: export NO_NYX=1; export ASAN_BUILD=1; export LLVM_CONFIG=llvm-config-${{ matrix.version }}; make ASAN_BUILD=1 NO_NYX=1 LLVM_CONFIG=llvm-config-${{ matrix.version }} all
- name: Check llvm passes
run: make ASAN_BUILD=1 NO_NYX=1 LLVM_CONFIG=llvm-config-${{ matrix.version }} llvm-build-test || exit 1
- name: run tests
run: sudo -E ./afl-system-config; make tests
check-compiler-passes-new:
runs-on: ubuntu-24.04
strategy:
matrix:
version: [16, 17, 18, 19, 20]
env:
AFL_SKIP_CPUFREQ: 1
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
steps:
- uses: actions/checkout@v4
- name: update
run: sudo apt-get update && sudo apt-get upgrade -y
- name: debug
run: apt-cache search plugin-dev | grep gcc-; echo; apt-cache search clang-format- | grep clang-format-
- name: install packages
run: sudo apt-get install -y -m -f build-essential git libtool libtool-bin automake flex bison libglib2.0-0 libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build python3-pip gcc-12-plugin-dev
- name: install llvm-tools (20)
if: matrix.version == '20'
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh ${{ matrix.version }}
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${{ matrix.version }} 200
- name: install llvm-tools
if: matrix.version != '20'
run: sudo apt install -y clang-${{ matrix.version }} llvm-${{ matrix.version }}
- name: install clang-rt
if: matrix.version != '20'
run: sudo apt install -y libclang-${{ matrix.version }}-dev
- name: compiler installed
run: gcc -v; echo; clang -v
- name: build afl++
run: export NO_NYX=1; export ASAN_BUILD=1; export LLVM_CONFIG=llvm-config-${{ matrix.version }}; make ASAN_BUILD=1 NO_NYX=1 LLVM_CONFIG=llvm-config-${{ matrix.version }} all
- name: Check llvm passes
run: make ASAN_BUILD=1 NO_NYX=1 LLVM_CONFIG=llvm-config-${{ matrix.version }} llvm-build-test || exit 1
- name: run tests
run: sudo -E ./afl-system-config; make tests
linux:
runs-on: "${{ matrix.os }}"
strategy:
@ -103,7 +31,7 @@ jobs:
- name: install gcc plugin
run: sudo apt-get install -y -m -f --install-suggests $(readlink /usr/bin/gcc)-plugin-dev
- name: build afl++
run: export NO_NYX=1; export ASAN_BUILD=1; export LLVM_CONFIG=llvm-config-15; make ASAN_BUILD=1 NO_NYX=1 LLVM_CONFIG=llvm-config-15 distrib
run: export NO_NYX=1; export ASAN_BUILD=1; export LLVM_CONFIG=llvm-config-12; make ASAN_BUILD=1 NO_NYX=1 LLVM_CONFIG=llvm-config-12 distrib
- name: run tests
run: sudo -E ./afl-system-config; make tests
macos:

View File

@ -9,10 +9,6 @@ on:
branches:
- dev # No need for stable-pull-request, as that equals dev-push
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
code-format-check:
name: Check code format

View File

@ -9,10 +9,6 @@ on:
branches:
- dev # No need for stable-pull-request, as that equals dev-push
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
analyze:
name: Analyze

View File

@ -10,10 +10,6 @@ on:
branches:
- dev # No need for stable-pull-request, as that equals dev-push
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build-and-test-amd64:
name: Test amd64 image

View File

@ -9,10 +9,6 @@ on:
branches:
- dev # No need for stable-pull-request, as that equals dev-push
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
name: Test Rust Custom Mutator Support

2
.gitignore vendored
View File

@ -108,8 +108,6 @@ utils/persistent_mode/persistent_demo
utils/persistent_mode/persistent_demo_new
utils/persistent_mode/persistent_demo_new_compat
utils/persistent_mode/test-instr
utils/qemu_persistent_hook/mipsel_test
utils/qemu_persistent_hook/test
utils/replay_record/persistent_demo_replay
utils/replay_record/persistent_demo_replay_compat
utils/replay_record/persistent_demo_replay_argparse

View File

@ -5,7 +5,7 @@
# GCC 11 is used instead of 12 because genhtml for afl-cov doesn't like it.
#
FROM ubuntu:24.04 AS aflplusplus
FROM ubuntu:22.04 AS aflplusplus
LABEL "maintainer"="AFL++ team <afl@aflplus.plus>"
LABEL "about"="AFLplusplus container image"
@ -17,7 +17,7 @@ ENV NO_NYX=1
### Only change these if you know what you are doing:
# Current recommended LLVM version is 16
ENV LLVM_VERSION=19
ENV LLVM_VERSION=16
# GCC 12 is producing compile errors for some targets so we stay at GCC 11
ENV GCC_VERSION=11
@ -32,8 +32,8 @@ RUN apt-get update && apt-get full-upgrade -y && \
apt-get install -y --no-install-recommends wget ca-certificates apt-utils && \
rm -rf /var/lib/apt/lists/*
#RUN echo "deb [signed-by=/etc/apt/keyrings/llvm-snapshot.gpg.key] http://apt.llvm.org/jammy/ llvm-toolchain-jammy-${LLVM_VERSION} main" > /etc/apt/sources.list.d/llvm.list && \
# wget -qO /etc/apt/keyrings/llvm-snapshot.gpg.key https://apt.llvm.org/llvm-snapshot.gpg.key
RUN echo "deb [signed-by=/etc/apt/keyrings/llvm-snapshot.gpg.key] http://apt.llvm.org/jammy/ llvm-toolchain-jammy-${LLVM_VERSION} main" > /etc/apt/sources.list.d/llvm.list && \
wget -qO /etc/apt/keyrings/llvm-snapshot.gpg.key https://apt.llvm.org/llvm-snapshot.gpg.key
RUN apt-get update && \
apt-get -y install --no-install-recommends \
@ -65,8 +65,8 @@ RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${GCC_VERSION} 0
update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${LLVM_VERSION} 0 && \
update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-${LLVM_VERSION} 0
#RUN wget -qO- https://sh.rustup.rs | CARGO_HOME=/etc/cargo sh -s -- -y -q --no-modify-path
#ENV PATH=$PATH:/etc/cargo/bin
RUN wget -qO- https://sh.rustup.rs | CARGO_HOME=/etc/cargo sh -s -- -y -q --no-modify-path
ENV PATH=$PATH:/etc/cargo/bin
RUN apt clean -y

View File

@ -31,7 +31,7 @@ PROGNAME = afl
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
PROGS = afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-cmin.py afl-whatsup afl-addseeds afl-system-config afl-persistent-config afl-cc
SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-addseeds afl-system-config afl-persistent-config afl-cc
HEADERS = include/afl-fuzz.h include/afl-mutations.h include/afl-persistent-replay.h include/afl-prealloc.h include/afl-record-compat.h include/alloc-inl.h include/android-ashmem.h include/cmplog.h include/common.h include/config.h include/coverage-32.h include/coverage-64.h include/debug.h include/envs.h include/forkserver.h include/hash.h include/list.h include/sharedmem.h include/snapshot-inl.h include/t1ha.h include/t1ha0_ia32aes_b.h include/t1ha_bits.h include/t1ha_selfcheck.h include/types.h include/xxhash.h
MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8)
ASAN_OPTIONS=detect_leaks=0
@ -76,16 +76,14 @@ ifdef IS_IOS
endif
ifeq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" ""
ifndef ASAN_BUILD
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
CFLAGS_FLTO ?= -flto=full
else
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
else
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
CFLAGS_FLTO ?= -flto=thin
else
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
else
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
CFLAGS_FLTO ?= -flto
endif
endif
endif
endif
@ -255,6 +253,17 @@ ifeq "$(PYTHON_INCLUDE)" ""
endif
endif
# Old Ubuntu and others dont have python/python2-config so we hardcode 2.7
ifeq "$(PYTHON_INCLUDE)" ""
ifneq "$(shell command -v python2.7 2>/dev/null)" ""
ifneq "$(shell command -v python2.7-config 2>/dev/null)" ""
PYTHON_INCLUDE := $(shell python2.7-config --includes)
PYTHON_LIB := $(shell python2.7-config --ldflags)
PYTHON_VERSION := $(strip $(shell python2.7 --version 2>&1))
endif
endif
endif
ifdef SOURCE_DATE_EPOCH
BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u "+%Y-%m-%d")
else
@ -304,8 +313,8 @@ ifeq "$(shell command -v svn >/dev/null && svn proplist . 2>/dev/null && echo 1
endif
ifeq "$(shell echo 'int main() { return 0;}' | $(CC) $(CFLAGS) -fsanitize=address -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -DASAN_BUILD -fno-lto
ASAN_LDFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -fno-lto
ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -DASAN_BUILD
ASAN_LDFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
endif
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
@ -345,11 +354,6 @@ llvm:
-$(MAKE) -j$(nproc) -f GNUmakefile.llvm
@test -e afl-cc || { echo "[-] Compiling afl-cc failed. You seem not to have a working compiler." ; exit 1; }
llvm-build-test:
$(MAKE) -j$(nproc) -f GNUmakefile.llvm
@test -e afl-cc || { echo "[-] Compiling afl-cc failed. You seem not to have a working compiler." ; exit 1; }
.PHONY: gcc_plugin
gcc_plugin:
ifneq "$(SYS)" "Darwin"

View File

@ -148,7 +148,7 @@ afl-common.o: ./src/afl-common.c
$(PASSES): instrumentation/afl-gcc-common.h
./afl-gcc-pass.so: instrumentation/afl-gcc-pass.so.cc | test_deps
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@ $(LDFLAGS)
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
ln -sf afl-cc afl-gcc-fast
ln -sf afl-cc afl-g++-fast
ln -sf afl-cc.8 afl-gcc-fast.8

View File

@ -32,8 +32,8 @@ VERSION = $(shell grep '^ *$(HASH)define VERSION ' ./config.h | cut -d '"' -
SYS = $(shell uname -s)
override LLVM_TOO_NEW_DEFAULT := 21
override LLVM_TOO_OLD_DEFAULT := 14
override LLVM_TOO_NEW_DEFAULT := 19
override LLVM_TOO_OLD_DEFAULT := 13
ifeq "$(SYS)" "OpenBSD"
LLVM_CONFIG ?= $(BIN_PATH)/llvm-config
@ -69,7 +69,7 @@ endif
LLVM_STDCXX := gnu++11
LLVM_LTO := 0
LLVM_UNSUPPORTED := $(shell echo "$(LLVMVER)" | grep -E -q '^[0-2]\.|^3\.[0-7]\.|^2[2-9]\.' && echo 1 || echo 0)
LLVM_UNSUPPORTED := $(shell echo "$(LLVMVER)" | grep -E -q '^[0-2]\.|^3\.[0-7]\.|^2[1-9]\.' && echo 1 || echo 0)
# Uncomment to see the values assigned above
# $(foreach var,_CLANG_VERSIONS_TO_TEST LLVM_CONFIG LLVMVER LLVM_MAJOR LLVM_MINOR LLVM_TOO_NEW LLVM_TOO_OLD LLVM_TOO_NEW_DEFAULT LLVM_TOO_OLD_DEFAULT LLVM_NEW_API LLVM_NEWER_API LLVM_13_OK LLVM_HAVE_LTO LLVM_BINDIR LLVM_LIBDIR LLVM_STDCXX LLVM_APPLE_XCODE LLVM_LTO LLVM_UNSUPPORTED,$(warning $(var) = $($(var))))
@ -470,7 +470,7 @@ endif
./afl-ld-lto: src/afl-ld-lto.c
ifeq "$(LLVM_LTO)" "1"
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ $(LDFLAGS)
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@
ifdef IS_IOS
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
endif

View File

@ -4,7 +4,7 @@
Release version: [4.32c](https://github.com/AFLplusplus/AFLplusplus/releases)
GitHub version: 4.33a
GitHub version: 4.32c
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 Scott Guest
Sangjun Park
```
</details>
@ -259,5 +259,3 @@ presented at WOOT'20:
```
</details>
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/AFLplusplus/AFLplusplus)

View File

@ -1,19 +1,12 @@
#!/usr/bin/env sh
THISPATH=`dirname ${0}`
# call afl-cmin.py if it can be executed successfully.
if $THISPATH/afl-cmin.py --help > /dev/null 2>&1; then
exec $THISPATH/afl-cmin.py "$@"
fi
SYS=$(uname -s)
test "$SYS" = "Darwin" && {
echo Error: afl-cmin does not work on Apple currently. please use afl-cmin.bash instead.
exit 1
}
export AFL_QUIET=1
export ASAN_OPTIONS=detect_leaks=0
THISPATH=`dirname ${0}`
export PATH="${THISPATH}:$PATH"
awk -f - -- ${@+"$@"} <<'EOF'
#!/usr/bin/awk -f

View File

@ -1,760 +0,0 @@
#!/usr/bin/env python3
# Copyright 2016-2025 Google Inc.
# Copyright 2025 AFLplusplus Project. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import argparse
import array
import base64
import collections
import glob
import hashlib
import itertools
import logging
import multiprocessing
import os
import shutil
import subprocess
import sys
# https://more-itertools.readthedocs.io/en/stable/_modules/more_itertools/recipes.html#batched
from sys import hexversion
def _batched(iterable, n, *, strict=False):
"""Batch data into tuples of length *n*. If the number of items in
*iterable* is not divisible by *n*:
* The last batch will be shorter if *strict* is ``False``.
* :exc:`ValueError` will be raised if *strict* is ``True``.
>>> list(batched('ABCDEFG', 3))
[('A', 'B', 'C'), ('D', 'E', 'F'), ('G',)]
On Python 3.13 and above, this is an alias for :func:`itertools.batched`.
"""
if n < 1:
raise ValueError('n must be at least one')
iterator = iter(iterable)
while batch := tuple(itertools.islice(iterator, n)):
if strict and len(batch) != n:
raise ValueError('batched(): incomplete batch')
yield batch
if hexversion >= 0x30D00A2: # pragma: no cover
from itertools import batched as itertools_batched
def batched(iterable, n, *, strict=False):
return itertools_batched(iterable, n, strict=strict)
else:
batched = _batched
batched.__doc__ = _batched.__doc__
try:
from tqdm import tqdm
except ImportError:
print('Hint: install python module "tqdm" to show progress bar')
class tqdm:
def __init__(self, data=None, *args, **argd):
self.data = data
def __iter__(self):
yield from self.data
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
pass
def update(self, *args):
pass
parser = argparse.ArgumentParser()
cpu_count = multiprocessing.cpu_count()
group = parser.add_argument_group("Required parameters")
group.add_argument(
"-i",
dest="input",
action="append",
metavar="dir",
required=True,
help="input directory with the starting corpus",
)
group.add_argument(
"-o",
dest="output",
metavar="dir",
required=True,
help="output directory for minimized files",
)
group = parser.add_argument_group("Execution control settings")
group.add_argument(
"-f",
dest="stdin_file",
metavar="file",
help="location read by the fuzzed program (stdin)",
)
group.add_argument(
"-m",
dest="memory_limit",
default="none",
metavar="megs",
type=lambda x: x if x == "none" else int(x),
help="memory limit for child process (default: %(default)s)",
)
group.add_argument(
"-t",
dest="time_limit",
default=5000,
metavar="msec",
type=lambda x: x if x == "none" else int(x),
help="timeout for each run (default: %(default)s)",
)
group.add_argument(
"-O",
dest="frida_mode",
action="store_true",
default=False,
help="use binary-only instrumentation (FRIDA mode)",
)
group.add_argument(
"-Q",
dest="qemu_mode",
action="store_true",
default=False,
help="use binary-only instrumentation (QEMU mode)",
)
group.add_argument(
"-U",
dest="unicorn_mode",
action="store_true",
default=False,
help="use unicorn-based instrumentation (Unicorn mode)",
)
group.add_argument(
"-X", dest="nyx_mode", action="store_true", default=False, help="use Nyx mode"
)
group = parser.add_argument_group("Minimization settings")
group.add_argument(
"--crash-dir",
dest="crash_dir",
metavar="dir",
default=None,
help="move crashes to a separate dir, always deduplicated",
)
group.add_argument(
"-A",
dest="allow_any",
action="store_true",
help="allow crashes and timeouts (not recommended)",
)
group.add_argument(
"-C",
dest="crash_only",
action="store_true",
help="keep crashing inputs, reject everything else",
)
group.add_argument(
"-e",
dest="edge_mode",
action="store_true",
default=False,
help="solve for edge coverage only, ignore hit counts",
)
group = parser.add_argument_group("Misc")
group.add_argument(
"-T",
dest="workers",
type=lambda x: cpu_count if x == "all" else int(x),
default=1,
help="number of concurrent worker (default: %(default)d)",
)
group.add_argument(
"--as_queue",
action="store_true",
help='output file name like "id:000000,hash:value"',
)
group.add_argument(
"--no-dedup", action="store_true", help="skip deduplication step for corpus files"
)
group.add_argument("--debug", action="store_true")
parser.add_argument("exe", metavar="/path/to/target_app")
parser.add_argument("args", nargs="*")
args = parser.parse_args()
logger = None
afl_showmap_bin = None
tuple_index_type_code = "I"
file_index_type_code = None
def init():
global logger
log_level = logging.DEBUG if args.debug else logging.INFO
logging.basicConfig(
level=log_level, format="%(asctime)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)
if args.stdin_file and args.workers > 1:
logger.error("-f is only supported with one worker (-T 1)")
sys.exit(1)
if args.memory_limit != "none" and args.memory_limit < 5:
logger.error("dangerously low memory limit")
sys.exit(1)
if args.time_limit != "none" and args.time_limit < 10:
logger.error("dangerously low timeout")
sys.exit(1)
if not os.path.isfile(args.exe):
logger.error('binary "%s" not found or not regular file', args.exe)
sys.exit(1)
if not os.environ.get("AFL_SKIP_BIN_CHECK") and not any(
[args.qemu_mode, args.frida_mode, args.unicorn_mode, args.nyx_mode]
):
if b"__AFL_SHM_ID" not in open(args.exe, "rb").read():
logger.error("binary '%s' doesn't appear to be instrumented", args.exe)
sys.exit(1)
for dn in args.input:
if not os.path.isdir(dn) and not glob.glob(dn):
logger.error('directory "%s" not found', dn)
sys.exit(1)
global afl_showmap_bin
searches = [
None,
os.path.dirname(__file__),
os.getcwd(),
]
if os.environ.get("AFL_PATH"):
searches.append(os.environ["AFL_PATH"])
for search in searches:
afl_showmap_bin = shutil.which("afl-showmap", path=search)
if afl_showmap_bin:
break
if not afl_showmap_bin:
logger.fatal("cannot find afl-showmap, please set AFL_PATH")
sys.exit(1)
trace_dir = os.path.join(args.output, ".traces")
shutil.rmtree(trace_dir, ignore_errors=True)
try:
os.rmdir(args.output)
except OSError:
pass
if os.path.exists(args.output):
logger.error(
'directory "%s" exists and is not empty - delete it first', args.output
)
sys.exit(1)
if args.crash_dir and not os.path.exists(args.crash_dir):
os.makedirs(args.crash_dir)
os.makedirs(trace_dir)
logger.info("use %d workers (-T)", args.workers)
def detect_type_code(size):
for type_code in ["B", "H", "I", "L", "Q"]:
if 256 ** array.array(type_code).itemsize > size:
return type_code
def afl_showmap(input_path=None, batch=None, afl_map_size=None, first=False):
assert input_path or batch
# yapf: disable
cmd = [
afl_showmap_bin,
'-m', str(args.memory_limit),
'-t', str(args.time_limit),
'-Z', # cmin mode
]
# yapf: enable
found_atat = False
for arg in args.args:
if "@@" in arg:
found_atat = True
if args.stdin_file:
assert args.workers == 1
input_from_file = True
stdin_file = args.stdin_file
cmd += ["-H", stdin_file]
elif found_atat:
input_from_file = True
stdin_file = os.path.join(args.output, f".input.{os.getpid()}")
cmd += ["-H", stdin_file]
else:
input_from_file = False
if batch:
input_from_file = True
filelist = os.path.join(args.output, f".filelist.{os.getpid()}")
with open(filelist, "w") as f:
for _, path in batch:
f.write(path + "\n")
cmd += ["-I", filelist]
output_path = os.path.join(args.output, f".showmap.{os.getpid()}")
cmd += ["-o", output_path]
else:
if input_from_file:
shutil.copy(input_path, stdin_file)
cmd += ["-o", "-"]
if args.frida_mode:
cmd += ["-O"]
if args.qemu_mode:
cmd += ["-Q"]
if args.unicorn_mode:
cmd += ["-U"]
if args.nyx_mode:
cmd += ["-X"]
if args.edge_mode:
cmd += ["-e"]
cmd += ["--", args.exe] + args.args
env = os.environ.copy()
env["AFL_QUIET"] = "1"
env["ASAN_OPTIONS"] = "detect_leaks=0"
if first:
logger.debug("run command line: %s", subprocess.list2cmdline(cmd))
env["AFL_CMIN_ALLOW_ANY"] = "1"
if afl_map_size:
env["AFL_MAP_SIZE"] = str(afl_map_size)
if args.crash_only:
env["AFL_CMIN_CRASHES_ONLY"] = "1"
if args.allow_any:
env["AFL_CMIN_ALLOW_ANY"] = "1"
if input_from_file:
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=env, bufsize=1048576)
else:
p = subprocess.Popen(
cmd,
stdin=open(input_path, "rb"),
stdout=subprocess.PIPE,
env=env,
bufsize=1048576,
)
out = p.stdout.read()
p.wait()
if batch:
result = []
for idx, input_path in batch:
basename = os.path.basename(input_path)
values = []
try:
trace_file = os.path.join(output_path, basename)
with open(trace_file, "r") as f:
values = list(map(int, f))
crashed = len(values) == 0
os.unlink(trace_file)
except FileNotFoundError:
a = None
crashed = True
values = [(t // 1000) * 9 + t % 1000 for t in values]
a = array.array(tuple_index_type_code, values)
result.append((idx, a, crashed))
os.unlink(filelist)
os.rmdir(output_path)
return result
else:
values = []
for line in out.split():
if not line.isdigit():
continue
values.append(int(line))
values = [(t // 1000) * 9 + t % 1000 for t in values]
a = array.array(tuple_index_type_code, values)
crashed = p.returncode in [2, 3]
if input_from_file and stdin_file != args.stdin_file:
os.unlink(stdin_file)
return a, crashed
class JobDispatcher(multiprocessing.Process):
def __init__(self, job_queue, jobs):
super().__init__()
self.job_queue = job_queue
self.jobs = jobs
def run(self):
for job in self.jobs:
self.job_queue.put(job)
self.job_queue.close()
class Worker(multiprocessing.Process):
def __init__(self, idx, afl_map_size, q_in, p_out, r_out):
super().__init__()
self.idx = idx
self.afl_map_size = afl_map_size
self.q_in = q_in
self.p_out = p_out
self.r_out = r_out
def run(self):
map_size = self.afl_map_size or 65536
max_tuple = map_size * 9
max_file_index = 256 ** array.array(file_index_type_code).itemsize - 1
m = array.array(file_index_type_code, [max_file_index] * max_tuple)
counter = collections.Counter()
crashes = []
pack_name = os.path.join(args.output, ".traces", f"{self.idx}.pack")
pack_pos = 0
with open(pack_name, "wb") as trace_pack:
while True:
batch = self.q_in.get()
if batch is None:
break
for idx, r, crash in afl_showmap(
batch=batch, afl_map_size=self.afl_map_size
):
counter.update(r)
used = False
if crash:
crashes.append(idx)
# If we aren't saving crashes to a separate dir, handle them
# the same as other inputs. However, unless AFL_CMIN_ALLOW_ANY=1,
# afl_showmap will not return any coverage for crashes so they will
# never be retained.
if not crash or not args.crash_dir:
for t in r:
if idx < m[t]:
m[t] = idx
used = True
if used:
tuple_count = len(r)
r.tofile(trace_pack)
self.p_out.put((idx, self.idx, pack_pos, tuple_count))
pack_pos += tuple_count * r.itemsize
else:
self.p_out.put(None)
self.r_out.put((self.idx, m, counter, crashes))
class CombineTraceWorker(multiprocessing.Process):
def __init__(self, pack_name, jobs, r_out):
super().__init__()
self.pack_name = pack_name
self.jobs = jobs
self.r_out = r_out
def run(self):
already_have = set()
with open(self.pack_name, "rb") as f:
for pos, tuple_count in self.jobs:
f.seek(pos)
result = array.array(tuple_index_type_code)
result.fromfile(f, tuple_count)
already_have.update(result)
self.r_out.put(already_have)
def hash_file(path):
m = hashlib.sha1()
with open(path, "rb") as f:
m.update(f.read())
return m.digest()
def dedup(files):
with multiprocessing.Pool(args.workers) as pool:
seen_hash = set()
result = []
hash_list = []
# use large chunksize to reduce multiprocessing overhead
chunksize = max(1, min(256, len(files) // args.workers))
for i, h in enumerate(
tqdm(
pool.imap(hash_file, files, chunksize),
desc="dedup",
total=len(files),
ncols=0,
leave=(len(files) > 100000),
)
):
if h in seen_hash:
continue
seen_hash.add(h)
result.append(files[i])
hash_list.append(h)
return result, hash_list
def is_afl_dir(dirnames, filenames):
return (
"queue" in dirnames
and "hangs" in dirnames
and "crashes" in dirnames
and "fuzzer_setup" in filenames
)
def collect_files(input_paths):
paths = []
for s in input_paths:
paths += glob.glob(s)
files = []
with tqdm(desc="search", unit=" files", ncols=0) as pbar:
for path in paths:
for root, dirnames, filenames in os.walk(path, followlinks=True):
for dirname in dirnames:
if dirname.startswith("."):
dirnames.remove(dirname)
if not args.crash_only and is_afl_dir(dirnames, filenames):
continue
for filename in filenames:
if filename.startswith("."):
continue
pbar.update(1)
files.append(os.path.join(root, filename))
return files
def main():
init()
files = collect_files(args.input)
if len(files) == 0:
logger.error("no inputs in the target directory - nothing to be done")
sys.exit(1)
logger.info("Found %d input files in %d directories", len(files), len(args.input))
if not args.no_dedup:
files, hash_list = dedup(files)
logger.info("Remain %d files after dedup", len(files))
else:
logger.info("Skipping file deduplication.")
global file_index_type_code
file_index_type_code = detect_type_code(len(files))
logger.info("Sorting files.")
with multiprocessing.Pool(args.workers) as pool:
chunksize = max(1, min(512, len(files) // args.workers))
size_list = list(pool.map(os.path.getsize, files, chunksize))
idxes = sorted(range(len(files)), key=lambda x: size_list[x])
files = [files[idx] for idx in idxes]
hash_list = [hash_list[idx] for idx in idxes]
afl_map_size = None
if b"AFL_DUMP_MAP_SIZE" in open(args.exe, "rb").read():
output = subprocess.run(
[args.exe], capture_output=True, env={"AFL_DUMP_MAP_SIZE": "1", "ASAN_OPTIONS": "detect_leaks=0"}
).stdout
afl_map_size = int(output)
logger.info("Setting AFL_MAP_SIZE=%d", afl_map_size)
global tuple_index_type_code
tuple_index_type_code = detect_type_code(afl_map_size * 9)
logger.info("Testing the target binary")
tuples, _ = afl_showmap(files[0], afl_map_size=afl_map_size, first=True)
if tuples:
logger.info("ok, %d tuples recorded", len(tuples))
else:
logger.error("no instrumentation output detected")
sys.exit(1)
job_queue = multiprocessing.Queue()
progress_queue = multiprocessing.Queue()
result_queue = multiprocessing.Queue()
workers = []
for i in range(args.workers):
p = Worker(i, afl_map_size, job_queue, progress_queue, result_queue)
p.start()
workers.append(p)
chunk = max(1, min(128, len(files) // args.workers))
jobs = list(batched(enumerate(files), chunk))
jobs += [None] * args.workers # sentinel
dispatcher = JobDispatcher(job_queue, jobs)
dispatcher.start()
logger.info("Processing traces")
effective = 0
trace_info = {}
for _ in tqdm(files, ncols=0, smoothing=0.01):
r = progress_queue.get()
if r is not None:
idx, worker_idx, pos, tuple_count = r
trace_info[idx] = worker_idx, pos, tuple_count
effective += 1
dispatcher.join()
logger.info("Obtaining trace results")
ms = []
crashes = []
counter = collections.Counter()
for _ in tqdm(range(args.workers), ncols=0):
idx, m, c, crs = result_queue.get()
ms.append(m)
counter.update(c)
crashes.extend(crs)
workers[idx].join()
best_idxes = list(map(min, zip(*ms)))
if not args.crash_dir:
logger.info(
"Found %d unique tuples across %d files (%d effective)",
len(counter),
len(files),
effective,
)
else:
logger.info(
"Found %d unique tuples across %d files (%d effective, %d crashes)",
len(counter),
len(files),
effective,
len(crashes),
)
all_unique = counter.most_common()
logger.info("Processing candidates and writing output")
already_have = set()
count = 0
def save_file(idx):
input_path = files[idx]
fn = (
base64.b16encode(hash_list[idx]).decode("utf8").lower()
if not args.no_dedup
else os.path.basename(input_path)
)
if args.as_queue:
if args.no_dedup:
fn = "id:%06d,orig:%s" % (count, fn)
else:
fn = "id:%06d,hash:%s" % (count, fn)
output_path = os.path.join(args.output, fn)
try:
os.link(input_path, output_path)
except OSError:
shutil.copy(input_path, output_path)
jobs = [[] for i in range(args.workers)]
saved = set()
for t, c in all_unique:
if c != 1:
continue
idx = best_idxes[t]
if idx in saved:
continue
save_file(idx)
saved.add(idx)
count += 1
worker_idx, pos, tuple_count = trace_info[idx]
job = (pos, tuple_count)
jobs[worker_idx].append(job)
trace_packs = []
workers = []
for i in range(args.workers):
pack_name = os.path.join(args.output, ".traces", f"{i}.pack")
trace_f = open(pack_name, "rb")
trace_packs.append(trace_f)
p = CombineTraceWorker(pack_name, jobs[i], result_queue)
p.start()
workers.append(p)
for _ in range(args.workers):
result = result_queue.get()
already_have.update(result)
for t, c in tqdm(list(reversed(all_unique)), ncols=0):
if t in already_have:
continue
idx = best_idxes[t]
save_file(idx)
count += 1
worker_idx, pos, tuple_count = trace_info[idx]
trace_pack = trace_packs[worker_idx]
trace_pack.seek(pos)
result = array.array(tuple_index_type_code)
result.fromfile(trace_pack, tuple_count)
already_have.update(result)
for f in trace_packs:
f.close()
if args.crash_dir:
logger.info("Saving crashes to %s", args.crash_dir)
crash_files = [files[c] for c in crashes]
if args.no_dedup:
# Unless we deduped previously, we have to dedup the crash files
# now.
crash_files, hash_list = dedup(crash_files)
for idx, crash_path in enumerate(crash_files):
fn = base64.b16encode(hash_list[idx]).decode("utf8").lower()
output_path = os.path.join(args.crash_dir, fn)
try:
os.link(crash_path, output_path)
except OSError:
try:
shutil.copy(crash_path, output_path)
except shutil.Error:
# This error happens when src and dest are hardlinks of the
# same file. We have nothing to do in this case, but handle
# it gracefully.
pass
if count == 1:
logger.warning("all test cases had the same traces, check syntax!")
logger.info('narrowed down to %s files, saved in "%s"', count, args.output)
if not os.environ.get("AFL_KEEP_TRACES"):
logger.info("Deleting trace files")
trace_dir = os.path.join(args.output, ".traces")
shutil.rmtree(trace_dir, ignore_errors=True)
if __name__ == "__main__":
main()

View File

@ -4,7 +4,7 @@ CFLAGS = -O3 -funroll-loops -fPIC
all: aflpp-standalone
aflpp-standalone: aflpp-standalone.c
$(CC) $(CFLAGS) -w -DBIN_PATH=\"foo\" -I../../../include -I. -o aflpp-standalone aflpp-standalone.c ../../../src/afl-performance.c ../../../src/afl-fuzz-extras.c ../../../src/afl-common.c
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -o aflpp-standalone aflpp-standalone.c ../../../src/afl-performance.c ../../../src/afl-fuzz-extras.c ../../../src/afl-common.c
clean:
rm -f *.o *~ aflpp-standalone core

View File

@ -1,20 +1,19 @@
CFLAGS = -g -O3 -funroll-loops -fPIC -D_STANDALONE_MODULE=1 -Wno-pointer-sign
CFLAGS = -g -O3 -funroll-loops -fPIC -D_STANDALONE_MODULE=1 -Wno-implicit-function-declaration
CXXFLAGS= -g -O3 -funroll-loops -fPIC -D_STANDALONE_MODULE=1
all: autotokens-standalone
autotokens.o: ../autotokens.cpp
$(CXX) $(CXXFLAGS) -g -I../../../include -I. -I../.. -c ../autotokens.cpp
$(CXX) $(CXXFLAGS) -I../../../include -I. -I../.. -c ../autotokens.cpp
autotokens-standalone: autotokens-standalone.c autotokens.o
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c autotokens-standalone.c
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-performance.c
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-fuzz-extras.c
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-fuzz-queue.c
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-common.c
$(CXX) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -o autotokens-standalone *.o
@rm -f ../../../src/afl-common.o ../../../src/afl-fuzz-queue.o ../../../src/afl-fuzz-extras.o ../../../src/afl-performance.o
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c autotokens-standalone.c
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-performance.c
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-fuzz-extras.c
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-fuzz-queue.c
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-common.c
$(CXX) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -o autotokens-standalone *.o
clean:
rm -f *.o *~ autotokens-standalone core

View File

@ -1,28 +1,15 @@
#include "afl-fuzz.h"
#include "afl-mutations.h"
#include "forkserver.h"
#include <unistd.h>
#include <getopt.h>
static int max_havoc = 16, verbose;
static char _mh[4] = "16";
static char *dict, *mh = _mh;
static unsigned char *dict, *mh = "16";
extern int module_disabled;
void *afl_custom_init(afl_state_t *, unsigned int);
u8 afl_custom_queue_get(void *data, const u8 *filename);
size_t afl_custom_fuzz(void *data, u8 *buf, size_t buf_size, u8 **out_buf,
u8 *add_buf, size_t add_buf_size, size_t max_size);
u32 write_to_testcase(afl_state_t *afl, void **mem, u32 a, u32 b) {
return 0;
}
fsrv_run_result_t fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv,
u32 i) {
return FSRV_RUN_OK;
}
int main(int argc, char *argv[]) {
@ -157,7 +144,7 @@ int main(int argc, char *argv[]) {
if (dict) {
load_extras(afl, (u8*)dict);
load_extras(afl, dict);
if (verbose)
fprintf(stderr, "Loaded dictionary: %s (%u entries)\n", dict,
afl->extras_cnt);

View File

@ -3,7 +3,8 @@
These are example and helper files for the custom mutator feature.
See [docs/custom_mutators.md](../../docs/custom_mutators.md) for more information
Note that if you compile with python3.7 you must use python3 scripts.
Note that if you compile with python3.7 you must use python3 scripts, and if
you use python2.7 to compile python2 scripts!
simple_example.c - most simplest example. generates a random sized buffer
filled with 'A'

View File

@ -56,7 +56,7 @@ if [ ! -f "../../src/afl-performance.o" ]; then
fi
PYTHONBIN=`command -v python3 || command -v python || echo python3`
PYTHONBIN=`command -v python3 || command -v python || command -v python2 || echo python3`
MAKECMD=make
TARCMD=tar

View File

@ -52,7 +52,7 @@ if [ ! -f "../../config.h" ]; then
fi
PYTHONBIN=`command -v python3 || command -v python || echo python3`
PYTHONBIN=`command -v python3 || command -v python || command -v python2 || echo python3`
MAKECMD=make
TARCMD=tar

View File

@ -3,36 +3,6 @@
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_EXITPOINT` support added
- `AFL_QEMU_BLOCK_COV` block coverage support added
- 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"
@ -52,6 +22,7 @@
- frida_mode:
- fixes for new MacOS + M4 hardware
### Version ++4.31c (release)
- SAND mode added (docs/SAND.md) for more effecient fuzzing with sanitizers
(thanks to @wtdcode !)

View File

@ -11,7 +11,7 @@ If you find an interesting or important question missing, submit it via
AFL++ is a superior fork to Google's AFL - more speed, more and better
mutations, more and better instrumentation, custom module support, etc.
American Fuzzy Lop (AFL) was developed by Michal "lcamtuf" Zalewski starting
American Fuzzy Lop (AFL) was developed by Michał "lcamtuf" Zalewski starting
in 2013/2014, and when he left Google end of 2017 he stopped developing it.
At the end of 2019, the Google fuzzing team took over maintenance of AFL,
@ -284,14 +284,14 @@ If you find an interesting or important question missing, submit it via
afl-cc/afl-clang-fast/afl-clang-lto:
```
/prg/tmp/llvm-project/build/bin/clang-18: symbol lookup error: /usr/local/bin/../lib/afl//cmplog-instructions-pass.so: undefined symbol: _ZNK4llvm8TypeSizecvmEv
clang-18: error: unable to execute command: No such file or directory
clang-18: error: clang frontend command failed due to signal (use -v to see invocation)
clang version 18.0.0 (https://github.com/llvm/llvm-project 1d7cf550721c51030144f3cd295c5789d51c4aad)
/prg/tmp/llvm-project/build/bin/clang-13: symbol lookup error: /usr/local/bin/../lib/afl//cmplog-instructions-pass.so: undefined symbol: _ZNK4llvm8TypeSizecvmEv
clang-13: error: unable to execute command: No such file or directory
clang-13: error: clang frontend command failed due to signal (use -v to see invocation)
clang version 13.0.0 (https://github.com/llvm/llvm-project 1d7cf550721c51030144f3cd295c5789d51c4aad)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /prg/tmp/llvm-project/build/bin
clang-18: note: diagnostic msg:
clang-13: note: diagnostic msg:
********************
```

View File

@ -21,7 +21,7 @@ If you want to build AFL++ yourself, you have many options. The easiest choice
is to build and install everything:
NOTE: depending on your Debian/Ubuntu/Kali/... release, replace `-14` with
whatever llvm version is available. We recommend llvm 14 or newer.
whatever llvm version is available. We recommend llvm 13 or newer.
```shell
sudo apt-get update

View File

@ -21,7 +21,7 @@ For a normal fuzzing workflow, we have:
For SAND fuzzing workflow, this is slightly different:
1. Build target project _without_ any sanitizers to get `target_native`, which we will define as a "native binary". It is usually done by using `afl-clang-fast/lto(++)` to compile your project _without_ `AFL_USE_ASAN/UBSAN/MSAN`.
2. Build target project with AFL_USE_ASAN=1 AFL_LLVM_ONLY_FSRV=1 to get `target_asan`. Do note this step can be repeated for multiple sanitizers, like MSAN, UBSAN etc. It is also possible to have ASAN and UBSAN to build together.
2. Build target project with AFL_USE_ASAN=1 AFL_SAN_NO_INST=1 to get `target_asan`. Do note this step can be repeated for multiple sanitizers, like MSAN, UBSAN etc. It is also possible to have ASAN and UBSAN to build together.
3. Fuzz the target with `afl-fuzz -i seeds -o out -w ./target_asan -- ./target_native`. Note `-w` can be specified multiple times.
Then you get:
@ -44,11 +44,11 @@ Just like the normal building process, except using `afl-clang-fast`
2. Build the sanitizers-enabled binaries.
```bash
AFL_LLVM_ONLY_FSRV=1 AFL_USE_UBSAN=1 AFL_USE_ASAN=1 afl-clang-fast test-instr.c -o ./asanubsan
AFL_LLVM_ONLY_FSRV=1 AFL_USE_MSAN=1 afl-clang-fast test-instr.c -o ./msan
AFL_SAN_NO_INST=1 AFL_USE_UBSAN=1 AFL_USE_ASAN=1 afl-clang-fast test-instr.c -o ./asanubsan
AFL_SAN_NO_INST=1 AFL_USE_MSAN=1 afl-clang-fast test-instr.c -o ./msan
```
Do note `AFL_LLVM_ONLY_FSRV=1` is crucial, this enables forkservers but disables pc instrumentation. You are allowed to reuse sanitizers-enabled binaries, i.e. binaries built _without_ `AFL_LLVM_ONLY_FSRV=1`, at a cost of reduced speed.
Do note `AFL_SAN_NO_INST=1` is crucial, this enables forkservers but disables pc instrumentation. Do not reuse sanitizers-enabled binaries built _without_ `AFL_SAN_NO_INST=1`. This will mess up SAND execution pattern.
3. Start fuzzing

View File

@ -111,10 +111,6 @@ fairly broad use of environment variables instead:
- Note: both `AFL_CFISAN_VERBOSE=1` and `AFL_UBSAN_VERBOSE=1` are disabled by default as verbose output can significantly slow down fuzzing performance. Use these options only during debugging or when additional crash diagnostics are required
- `AFL_LLVM_ONLY_FSRV`/`AFL_GCC_ONLY_FSRV` will inject forkserver but not pc instrumentation. Please note this is different compared to `AFL_LLVM_DISABLE_INSTRUMENTATION`, which will totally disable forkserver implementation. This env is pretty useful in two cases:
- [SAND](./SAND.md). In this case, the binaries built in this way will serve as extra oracles. Check the corresponding documents for details.
- Compatible with LibAFL ForkserverExecutor implementation and thus faster to repeatedly run, compared to simple CommandExecutor.
- `TMPDIR` is used by afl-as for temporary files; if this variable is not set,
the tool defaults to /tmp.
@ -668,41 +664,6 @@ checks or alter some of the more exotic semantics of the tool:
Note that will not be exact and with slow targets it can take seconds
until there is a slice for the time test.
- When using `AFL_PRELOAD` with a preload that disable `fork()` calls in
the target, the forkserver becomes unable to fork.
To overcome this issue, the `AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT`
permits to be able to check in the preloaded library if the environment
variable `AFL_FORKSERVER_PARENT` is set, to be able to use vanilla
`fork()` in the forkserver, and the placeholder in the target.
Here is a POC :
```C
// AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT=1 afl-fuzz ...
pid_t fork(void)
{
if (getenv("AFL_FORKSERVER_PARENT") == NULL)
return 0; // We are in the target
else
return real_fork(); // We are in the forkserver
}
```
- `AFL_FORKSRV_UID` allows you to specify the UID that should be used when
running the fork server. When setting this variable, user should ensure
afl-fuzz binary has enough privileges to modify the UID (e.g. CAP\_SETUID
capability in Linux system).
- `AFL_FORKSRV_GID` allows you to specify the GID and the supplementary group
IDs that should be used when running the fork server. When setting this
variable, user should ensure afl-fuzz binary has enough privileges to
modify the GIDs (e.g. CAP\_SETGID capability in Linux system).
- When both `AFL_FORKSRV_UID` and `AFL_FORKSRV_GID` are set, afl-fuzz binary
and the fork server no longer share any IDs. Thus, afl-fuzz binary changes
the group owner of the created files to ensure that the fork server can
still access them. In such case, user should ensure afl-fuzz binary has
enough privileges to modify the ownership of entities (e.g. CAP\_CHOWN
capability in Linux system).
## 6) Settings for afl-qemu-trace
The QEMU wrapper used to instrument binary-only code supports several settings:
@ -741,10 +702,6 @@ The QEMU wrapper used to instrument binary-only code supports several settings:
of the basic blocks, which can be useful when dealing with very complex
binaries.
- You can switch to block coverage that has less chances of colliding (but
on the other hand coverage is on blocks, not edges) with
`AFL_QEMU_BLOCK_COV`.
- Setting `AFL_QEMU_COMPCOV` enables the CompareCoverage tracing of all cmp
and sub in x86 and x86_64. This is an alias of `AFL_COMPCOV_LEVEL=1` when
`AFL_COMPCOV_LEVEL` is not specified.

View File

@ -45,7 +45,7 @@ E. CmpLog is our enhanced
implementation, see
[instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md)
F. Similar and compatible to clang 14+ sancov sanitize-coverage-allow/deny but
F. Similar and compatible to clang 13+ sancov sanitize-coverage-allow/deny but
for all llvm versions and all our compile modes, only instrument what should
be instrumented, for more speed, directed fuzzing and less instability; see
[instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md)

View File

@ -16,8 +16,7 @@ FRIDA mode and QEMU mode in persistent mode are the fastest - if persistent mode
is possible and the stability is high enough.
Otherwise, try Zafl, RetroWrite, Dyninst, and if these fail, too, then try
standard FRIDA/QEMU mode with `AFL_ENTRYPOINT` + `AFL_EXITPOINT` to where you
need it.
standard FRIDA/QEMU mode with `AFL_ENTRYPOINT` to where you need it.
If your target is non-linux, then use unicorn_mode.

View File

@ -132,15 +132,11 @@ options are available:
locations. This technique is very fast and good - if the target does not
transform input data before comparison. Therefore, this technique is called
`input to state` or `redqueen`. If you want to use this technique, then you
have to compile the target with `AFL_LLVM_CMPLOG=1`.
You could use the resulting binary for both normal fuzzing and `-c` CMPLOG
mode (with `-c 0`), however this will result in a performance loss of about
20%.
It is therefore better to compile a specific CMPLOG target with
`AFL_LLVM_ONLY_FSRV=1 AFL_LLVM_CMPLOG=1` and pass this binary name via
`-c cmplog-fuzzing-target` and compile target again normally with `afl-cc`
and use this is the fuzzing target as usual.
You can read more about this in
have to compile the target twice, once specifically with/for this mode by
setting `AFL_LLVM_CMPLOG=1`, and pass this binary to afl-fuzz via the `-c`
parameter. Note that you can compile also just a cmplog binary and use that
for both, however, there will be a performance penalty. You can read more
about this in
[instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md).
If you use LTO, LLVM, or GCC_PLUGIN mode
@ -869,13 +865,10 @@ Here are some of the most important caveats for AFL++:
- There is no direct support for fuzzing network services, background daemons,
or interactive apps that require UI interaction to work. You may need to make
simple code changes to make them behave in a more traditional way. Preeny,
libdesock or desockmulti may offer a relatively simple option, too - see:
simple code changes to make them behave in a more traditional way. Preeny or
libdesock may offer a relatively simple option, too - see:
[https://github.com/zardus/preeny](https://github.com/zardus/preeny) or
[https://github.com/fkie-cad/libdesock](https://github.com/fkie-cad/libdesock)
[https://github.com/zyingp/desockmulti](https://github.com/zyingp/desockmulti)
If these fail then try our own which might be a bit slower but is more
reliable: [utils/libaflppdesock](../utils/libaflppdesock)
Some useful tips for modifying network-based services can be also found at:
[https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop](https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop)

View File

@ -15,7 +15,6 @@ JS_OBJ:=$(BUILD_DIR)api.o
SOURCES:=$(wildcard $(SRC_DIR)**/*.c) $(wildcard $(SRC_DIR)*.c)
OBJS:=$(foreach src,$(SOURCES),$(OBJ_DIR)$(notdir $(patsubst %.c, %.o, $(src))))
XTOOLS_HOST?=x86_64-linux-gnu
TARGET_CC?=$(CC)
TARGET_CXX?=$(CXX)
HOST_CC?=$(CC)
@ -187,13 +186,39 @@ ifndef OS
$(error "Operating system unsupported")
endif
GUM_DEVKIT_VERSION=17.0.7
GUM_DEVKIT_VERSION=16.1.11
GUM_DEVKIT_FILENAME=frida-gumjs-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar.xz
GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(GUM_DEVKIT_VERSION)/$(GUM_DEVKIT_FILENAME)"
ifeq ($(OS),macos)
# Extract the major version
GUM_VERSION_MAJOR := $(shell echo "$(GUM_DEVKIT_VERSION)" | sed -E 's/\..*//')
# Extract the minor version (assumes format "MAJOR.MINOR[.PATCH...]")
GUM_VERSION_MINOR := $(shell echo "$(GUM_DEVKIT_VERSION)" | sed -E 's/^[^.]*\.//; s/\..*//')
# Evaluate the version condition in a separate shell call
IS_GUM_16_6_PLUS := $(shell \
if (( $(GUM_VERSION_MAJOR) > 16 || ( $(GUM_VERSION_MAJOR) == 16 && $(GUM_VERSION_MINOR) >= 6 ) )); then \
echo 1; \
fi)
else
IS_GUM_16_6_PLUS := $(shell VERSION="$(GUM_DEVKIT_VERSION)"; \
MAJOR=$${VERSION%%.*}; \
MINOR=$${VERSION#*.}; MINOR=$${MINOR%%.*}; \
if [ $$MAJOR -gt 16 ] || { [ $$MAJOR -eq 16 ] && [ $$MINOR -ge 6 ]; }; then \
echo 1; \
fi)
endif
CFLAGS += $(if $(IS_GUM_16_6_PLUS),-DGUM_16_6_PLUS)
GUM_DEVKIT_TARBALL:=$(FRIDA_BUILD_DIR)$(GUM_DEVKIT_FILENAME)
GUM_DEVIT_HEADER=$(FRIDA_BUILD_DIR)frida-gumjs.h
ifdef FRIDA_SOURCE
GUM_DEVIT_LIBRARY=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gumjs-1.0.a
else
GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gumjs.a
endif
GUM_DEVIT_HEADER=$(FRIDA_BUILD_DIR)frida-gumjs.h
FRIDA_DIR:=$(PWD)build/frida-source/
FRIDA_MAKEFILE:=$(FRIDA_DIR)Makefile
@ -227,13 +252,13 @@ BIN2C_SRC:=$(PWD)util/bin2c.c
all: $(FRIDA_TRACE) $(FRIDA_TRACE_LIB) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_QEMU_DRIVER_HOOK_OBJ) $(ADDR_BIN)
32:
XTOOLS_HOST=i686-linux-gnu CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
arm:
XTOOLS_HOST=arm-linux-gnueabihf CFLAGS="-marm" LDFLAGS="-marm" ARCH="armhf" TARGET_CC=arm-linux-gnueabihf-gcc TARGET_CXX=arm-linux-gnueabihf-g++ make all
CFLAGS="-marm" LDFLAGS="-marm" ARCH="armhf" TARGET_CC=arm-linux-gnueabihf-gcc TARGET_CXX=arm-linux-gnueabihf-g++ make all
arm64:
XTOOLS_HOST=aarch64-linux-gnu ARCH="arm64" TARGET_CC=aarch64-linux-gnu-gcc TARGET_CXX=aarch64-linux-gnu-g++ make all
ARCH="arm64" TARGET_CC=aarch64-linux-gnu-gcc TARGET_CXX=aarch64-linux-gnu-g++ make all
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
@ -246,29 +271,114 @@ $(OBJ_DIR): | $(BUILD_DIR)
$(FRIDA_BUILD_DIR): | $(BUILD_DIR)
mkdir -p $@
#TODO Set architecture
ifdef FRIDA_SOURCE
$(FRIDA_MAKEFILE): | $(BUILD_DIR)
git clone https://github.com/frida/frida-gum.git $(FRIDA_DIR)
cd $(FRIDA_DIR) && \
./configure \
--host=$(XTOOLS_HOST) \
--enable-tests \
--enable-gumpp \
--enable-gumjs \
--with-devkits=gum,gumjs
git clone --recursive https://github.com/frida/frida.git $(FRIDA_DIR)
.PHONY: $(GUM_DEVIT_LIBRARY)
$(GUM_DEVIT_LIBRARY): $(FRIDA_MAKEFILE) | $(FRIDA_BUILD_DIR)
echo $(GUM_DEVIT_LIBRARY) $(FRIDA_MAKEFILE) $(FRIDA_BUILD_DIR)
cd $(FRIDA_DIR) && make FRIDA_V8=disabled
cp $(FRIDA_DIR)build/bindings/gumjs/devkit/frida-gumjs.h $(GUM_DEVIT_HEADER)
cp $(FRIDA_DIR)build/bindings/gumjs/devkit/libfrida-gumjs.a $(GUM_DEVIT_LIBRARY)
$(GUM_DEVIT_LIBRARY): $(FRIDA_MAKEFILE)
cd $(FRIDA_DIR) && make gum-$(OS)$(GUM_ARCH) FRIDA_V8=disabled
$(GUM_DEVIT_HEADER): $(FRIDA_MAKEFILE) | $(FRIDA_BUILD_DIR)
echo "#include <stdio.h>" > $@
echo "#include <unistd.h>" >> $@
echo "#include <gum/gumreturnaddress.h>" >> $@
echo "#include <gum/gumbacktracer.h>" >> $@
echo "#include <gum/gumsymbolutil.h>" >> $@
echo "#include <gum/gumstalker.h>" >> $@
echo "#include <gum/gumlibc.h>" >> $@
echo "#include <gumjs/gumscriptbackend.h>" >> $@
ifeq "$(OS)" "macos"
CFLAGS+=-I $(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/include/frida-1.0 \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libiconv.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libv8-8.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgmodule-2.0.a \
else ifeq "$(ARCH)" "arm64"
CFLAGS+=-I $(FRIDA_DIR)build/$(OS)-$(ARCH)/include/frida-1.0 \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
ifeq "$(OS)" "android"
CFLAGS += -static-libstdc++
endif
else
CFLAGS+=-I $(FRIDA_DIR)build/$(OS)-$(ARCH)/include/frida-1.0 \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
endif
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libunwind.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libdwarf.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libelf.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
CFLAGS+=-I $(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/include/frida-1.0 \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/
ifeq "$(OS)" "android"
CFLAGS += -static-libstdc++
endif
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libunwind.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libdwarf.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libelf.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
else
$(GUM_DEVKIT_TARBALL): | $(FRIDA_BUILD_DIR)

View File

@ -27,6 +27,7 @@ void asan_init(void) {
}
#ifdef GUM_16_6_PLUS
static gboolean asan_exclude_module(GumModule *module, gpointer user_data) {
gchar *symbol_name = (gchar *)user_data;
@ -46,6 +47,32 @@ static gboolean asan_exclude_module(GumModule *module, gpointer user_data) {
}
#else
static gboolean asan_exclude_module(const GumModuleDetails *details,
gpointer user_data) {
gchar *symbol_name = (gchar *)user_data;
GumAddress address;
address = gum_module_find_export_by_name(details->name, symbol_name);
if (address == 0) { return TRUE; }
/* If the reported address of the symbol is outside of the range of the module
* then ignore it */
if (address < details->range->base_address) { return TRUE; }
if (address > (details->range->base_address + details->range->size)) {
return TRUE;
}
ranges_add_exclude((GumMemoryRange *)details->range);
return FALSE;
}
#endif
void asan_exclude_module_by_symbol(gchar *symbol_name) {
gum_process_enumerate_modules(asan_exclude_module, symbol_name);

View File

@ -382,5 +382,5 @@ Afl.jsApiSetTraceable = Afl.jsApiGetFunction("js_api_set_traceable", "void", [])
Afl.jsApiSetVerbose = Afl.jsApiGetFunction("js_api_set_verbose", "void", []);
Afl.jsApiWrite = new NativeFunction(
/* tslint:disable-next-line:no-null-keyword */
Module.getGlobalExportByName("write"), "int", ["int", "pointer", "int"]);
Module.getExportByName(null, "write"), "int", ["int", "pointer", "int"]);
Afl.jsApiIjonSet = Afl.jsApiGetFunction("js_api_ijon_set", "void", ["uint32"]);

View File

@ -39,6 +39,7 @@ typedef struct {
static guint64 text_base = 0;
static guint64 text_limit = 0;
#ifdef GUM_16_6_PLUS
static gboolean lib_find_exe(GumModule *module, gpointer user_data) {
lib_details_t *lib_details = (lib_details_t *)user_data;
@ -56,6 +57,24 @@ static gboolean lib_find_exe(GumModule *module, gpointer user_data) {
}
#else
static gboolean lib_find_exe(const GumModuleDetails *details,
gpointer user_data) {
lib_details_t *lib_details = (lib_details_t *)user_data;
strncpy(lib_details->name, details->name, PATH_MAX);
strncpy(lib_details->path, details->path, PATH_MAX);
lib_details->name[PATH_MAX] = '\0';
lib_details->path[PATH_MAX] = '\0';
lib_details->base_address = details->range->base_address;
lib_details->size = details->range->size;
return FALSE;
}
#endif
static void lib_validate_hdr(Elf_Ehdr *hdr) {
if (hdr->e_ident[0] != ELFMAG0) FFATAL("Invalid e_ident[0]");

View File

@ -12,6 +12,7 @@ extern void gum_darwin_enumerate_modules(mach_port_t task,
static guint64 text_base = 0;
static guint64 text_limit = 0;
#ifdef GUM_16_6_PLUS
static gboolean lib_get_main_module(GumModule *module, gpointer user_data) {
GumDarwinModule **ret = (GumDarwinModule **)user_data;
@ -29,6 +30,25 @@ static gboolean lib_get_main_module(GumModule *module, gpointer user_data) {
}
#else
static gboolean lib_get_main_module(const GumModuleDetails *details,
gpointer user_data) {
GumDarwinModule **ret = (GumDarwinModule **)user_data;
GumDarwinModule *module = gum_darwin_module_new_from_memory(
details->path, mach_task_self(), details->range->base_address,
GUM_DARWIN_MODULE_FLAGS_NONE, NULL);
FVERBOSE("Found main module: %s", module->name);
*ret = module;
return FALSE;
}
#endif
gboolean lib_get_text_section(const GumDarwinSectionDetails *details,
gpointer user_data) {

View File

@ -46,7 +46,6 @@ gboolean found_range(const GumRangeDetails *details, gpointer user_data) {
static int on_dlclose(void *handle) {
GArray *ranges = NULL;
GumModule *module = NULL;
struct link_map *lm = NULL;
gum_range_t *range = NULL;
GumAddress base;
@ -62,12 +61,8 @@ static int on_dlclose(void *handle) {
FVERBOSE("on_dlclose: %s", lm->l_name);
ranges = g_array_new(FALSE, TRUE, sizeof(gum_range_t));
module = gum_process_find_module_by_name(lm->l_name);
if (module == NULL) { FATAL("Failed to find module: %s", lm->l_name); }
gum_module_enumerate_ranges(module, GUM_PAGE_EXECUTE, found_range, ranges);
gum_module_enumerate_ranges(lm->l_name, GUM_PAGE_EXECUTE, found_range,
ranges);
int ret = dlclose(handle);
if (ret != 0) {

View File

@ -263,8 +263,13 @@ static int prefetch_on_fork(void) {
static void prefetch_hook_fork(void) {
#ifdef GUM_16_6_PLUS
void *fork_addr =
GSIZE_TO_POINTER(gum_module_find_global_export_by_name("fork"));
#else
void *fork_addr =
GSIZE_TO_POINTER(gum_module_find_export_by_name(NULL, "fork"));
#endif
intercept_hook(fork_addr, prefetch_on_fork, NULL);
}

View File

@ -116,6 +116,7 @@ static void convert_address_token(gchar *token, GumMemoryRange *range) {
}
#ifdef GUM_16_6_PLUS
static gboolean convert_name_token_for_module(GumModule *module,
gpointer user_data) {
@ -137,6 +138,28 @@ static gboolean convert_name_token_for_module(GumModule *module,
}
#else
static gboolean convert_name_token_for_module(const GumModuleDetails *details,
gpointer user_data) {
convert_name_ctx_t *ctx = (convert_name_ctx_t *)user_data;
if (details->path == NULL) { return true; };
if (!g_str_has_suffix(details->path, ctx->suffix)) { return true; };
FVERBOSE("Found module - prefix: %s, 0x%016" G_GINT64_MODIFIER
"x-0x%016" G_GINT64_MODIFIER "x %s",
ctx->suffix, details->range->base_address,
details->range->base_address + details->range->size, details->path);
*ctx->range = *details->range;
ctx->done = true;
return false;
}
#endif
static void convert_name_token(gchar *token, GumMemoryRange *range) {
gchar *suffix = g_strconcat("/", token, NULL);

View File

@ -462,10 +462,7 @@ typedef struct afl_env_vars {
afl_no_startup_calibration, afl_no_warn_instability,
afl_post_process_keep_original, afl_crashing_seeds_as_new_crash,
afl_final_sync, afl_ignore_seed_problems, afl_disable_redundant,
afl_sha1_filenames, afl_no_sync, afl_no_fastresume, afl_forksrv_uid_set,
afl_forksrv_gid_set;
u16 afl_forksrv_nb_supl_gids;
afl_sha1_filenames, afl_no_sync, afl_no_fastresume;
u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path,
*afl_hang_tmout, *afl_forksrv_init_tmout, *afl_preload,
@ -476,12 +473,6 @@ typedef struct afl_env_vars {
s32 afl_pizza_mode;
uid_t afl_forksrv_uid;
gid_t afl_forksrv_gid;
gid_t *afl_forksrv_supl_gids;
} afl_env_vars_t;
struct afl_pass_stat {
@ -564,10 +555,6 @@ typedef struct afl_state {
*orig_cmdline, /* Original command line */
*infoexec; /* Command to execute on a new crash */
mode_t perm, /* File permission when creating files */
dir_perm; /* File permission when creating directories */
u8 chown_needed; /* Group owner of files needs to be modified */
u32 hang_tmout, /* Timeout used for hang det (ms) */
stats_update_freq; /* Stats update frequency (execs) */
@ -783,7 +770,6 @@ typedef struct afl_state {
#define FOREIGN_SYNCS_MAX 32U
u8 foreign_sync_cnt;
struct foreign_sync foreign_syncs[FOREIGN_SYNCS_MAX];
char *foreign_file;
#ifdef _AFL_DOCUMENT_MUTATIONS
u8 do_document;
@ -1153,7 +1139,6 @@ struct custom_mutator {
void afl_state_init(afl_state_t *, uint32_t map_size);
void afl_state_deinit(afl_state_t *);
void afl_resize_map_buffers(afl_state_t *, u32 old_size, u32 new_size);
/* Set stop_soon flag on all children, kill all children */
void afl_states_stop(void);
@ -1195,7 +1180,7 @@ u8 havoc_mutation_probability_py(void *);
u8 queue_get_py(void *, const u8 *);
const char *introspection_py(void *);
u8 queue_new_entry_py(void *, const u8 *, const u8 *);
void splice_optout_py(void *);
void splice_optout(void *);
void deinit_py(void *);
#endif
@ -1230,6 +1215,7 @@ u8 *describe_op(afl_state_t *, u8, size_t);
#endif
u8 save_if_interesting(afl_state_t *, void *, u32, u8);
u8 has_new_bits(afl_state_t *, u8 *);
u8 has_new_bits_unclassified(afl_state_t *, u8 *);
#ifndef AFL_SHOWMAP
void classify_counts(afl_forkserver_t *);
#endif
@ -1272,7 +1258,6 @@ int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen);
/* Run */
void check_sync_fuzzers(afl_state_t *);
void sync_fuzzers(afl_state_t *);
u32 write_to_testcase(afl_state_t *, void **, u32, u32);
u8 calibrate_case(afl_state_t *, struct queue_entry *, u8 *, u32, u8);
@ -1293,6 +1278,7 @@ u8 fuzz_one(afl_state_t *);
#ifdef HAVE_AFFINITY
void bind_to_free_cpu(afl_state_t *);
#endif
void setup_post(afl_state_t *);
void read_testcases(afl_state_t *, u8 *);
void perform_dry_run(afl_state_t *);
void pivot_inputs(afl_state_t *);
@ -1456,7 +1442,7 @@ char *sha1_hex_for_file(const char *fname, u32 len);
* enabled. */
static inline int permissive_create(afl_state_t *afl, const char *fn) {
int fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, afl->perm);
int fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (unlikely(fd < 0)) {
if (!(afl->afl_env.afl_sha1_filenames && errno == EEXIST)) {
@ -1467,12 +1453,6 @@ static inline int permissive_create(afl_state_t *afl, const char *fn) {
}
if (afl->chown_needed) {
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
}
return fd;
}

View File

@ -144,10 +144,10 @@ u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms);
u32 get_map_size(void);
/* create a stream file */
FILE *create_ffile(u8 *fn, mode_t perm);
FILE *create_ffile(u8 *fn);
/* create a file */
s32 create_file(u8 *fn, mode_t perm);
s32 create_file(u8 *fn);
/* memmem implementation as not all platforms support this */
void *afl_memmem(const void *haystack, size_t haystacklen, const void *needle,

View File

@ -26,7 +26,7 @@
/* Version string: */
// c = release, a = volatile github dev, e = experimental branch
#define VERSION "++4.33a"
#define VERSION "++4.32c"
/******************************************************
* *
@ -49,9 +49,6 @@
Default: 300 (seconds) */
#define STRATEGY_SWITCH_TIME 1000
/* Default file permission umode when creating directories */
#define DEFAULT_DIRS_PERMISSION 0700
/* Default file permission umode when creating files (default: 0600) */
#define DEFAULT_PERMISSION 0600
@ -174,9 +171,8 @@
#define EXEC_TM_ROUND 20U
/* 64bit arch MACRO */
#if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__) || \
(defined(__riscv) && __riscv_xlen == 64) || defined(__powerpc64le__) || \
defined(__s390x__) || defined(__loongarch64))
#if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__) || \
(defined(__riscv) && __riscv_xlen == 64))
#define WORD_SIZE_64 1
#endif
@ -342,10 +338,6 @@
#define AVG_SMOOTHING 16
/* Max length of sync id (the id after -M and -S) */
#define SYNC_ID_MAX_LEN 50
/* Sync interval (every n havoc cycles): */
#define SYNC_INTERVAL 8
@ -431,15 +423,9 @@
#define SHM_ENV_VAR "__AFL_SHM_ID"
/* Environment variable used to pass shared memory fuzz map id
and the mapping size to the called program. */
/* Environment variable used to pass SHM FUZZ ID to the called program. */
#define SHM_FUZZ_ENV_VAR "__AFL_SHM_FUZZ_ID"
#define SHM_FUZZ_MAP_SIZE_ENV_VAR "__AFL_SHM_FUZZ_MAP_SIZE"
/* Default size of the shared memory fuzz map.
We add 4 byte for one u32 length field. */
#define SHM_FUZZ_MAP_SIZE_DEFAULT (MAX_FILE + 4)
/* Other less interesting, internal-only variables. */

View File

@ -10,7 +10,6 @@ static char *afl_environment_deprecated[] = {
"AFL_DEFER_FORKSRV",
"AFL_POST_LIBRARY",
"AFL_PERSISTENT",
"AFL_SAN_NO_INST",
NULL
};
@ -34,19 +33,18 @@ static char *afl_environment_variables[] = {
"AFL_DISABLE_TRIM", "AFL_NO_TRIM", "AFL_DISABLE_LLVM_INSTRUMENTATION",
"AFL_DONT_OPTIMIZE", "AFL_DRIVER_STDERR_DUPLICATE_FILENAME",
"AFL_DUMB_FORKSRV", "AFL_EARLY_FORKSERVER", "AFL_ENTRYPOINT",
"AFL_EXITPOINT", "AFL_EXIT_WHEN_DONE", "AFL_EXIT_ON_TIME",
"AFL_EXIT_ON_SEED_ISSUES", "AFL_FAST_CAL", "AFL_FINAL_SYNC", "AFL_FORCE_UI",
"AFL_FRIDA_DEBUG_MAPS", "AFL_FRIDA_DRIVER_NO_HOOK",
"AFL_FRIDA_EXCLUDE_RANGES", "AFL_FRIDA_INST_CACHE_SIZE",
"AFL_FRIDA_INST_COVERAGE_ABSOLUTE", "AFL_FRIDA_INST_COVERAGE_FILE",
"AFL_FRIDA_INST_DEBUG_FILE", "AFL_FRIDA_INST_INSN", "AFL_FRIDA_INST_JIT",
"AFL_FRIDA_INST_NO_CACHE", "AFL_FRIDA_INST_NO_DYNAMIC_LOAD",
"AFL_FRIDA_INST_NO_OPTIMIZE", "AFL_FRIDA_INST_NO_PREFETCH",
"AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH", "AFL_FRIDA_INST_NO_SUPPRESS",
"AFL_FRIDA_INST_RANGES", "AFL_FRIDA_INST_REGS_FILE", "AFL_FRIDA_INST_SEED",
"AFL_FRIDA_INST_TRACE", "AFL_FRIDA_INST_TRACE_UNIQUE",
"AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE", "AFL_FRIDA_JS_SCRIPT",
"AFL_FRIDA_OUTPUT_STDOUT", "AFL_FRIDA_OUTPUT_STDERR",
"AFL_EXIT_WHEN_DONE", "AFL_EXIT_ON_TIME", "AFL_EXIT_ON_SEED_ISSUES",
"AFL_FAST_CAL", "AFL_FINAL_SYNC", "AFL_FORCE_UI", "AFL_FRIDA_DEBUG_MAPS",
"AFL_FRIDA_DRIVER_NO_HOOK", "AFL_FRIDA_EXCLUDE_RANGES",
"AFL_FRIDA_INST_CACHE_SIZE", "AFL_FRIDA_INST_COVERAGE_ABSOLUTE",
"AFL_FRIDA_INST_COVERAGE_FILE", "AFL_FRIDA_INST_DEBUG_FILE",
"AFL_FRIDA_INST_INSN", "AFL_FRIDA_INST_JIT", "AFL_FRIDA_INST_NO_CACHE",
"AFL_FRIDA_INST_NO_DYNAMIC_LOAD", "AFL_FRIDA_INST_NO_OPTIMIZE",
"AFL_FRIDA_INST_NO_PREFETCH", "AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH",
"AFL_FRIDA_INST_NO_SUPPRESS", "AFL_FRIDA_INST_RANGES",
"AFL_FRIDA_INST_REGS_FILE", "AFL_FRIDA_INST_SEED", "AFL_FRIDA_INST_TRACE",
"AFL_FRIDA_INST_TRACE_UNIQUE", "AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE",
"AFL_FRIDA_JS_SCRIPT", "AFL_FRIDA_OUTPUT_STDOUT", "AFL_FRIDA_OUTPUT_STDERR",
"AFL_FRIDA_PERSISTENT_ADDR", "AFL_FRIDA_PERSISTENT_CNT",
"AFL_FRIDA_PERSISTENT_DEBUG", "AFL_FRIDA_PERSISTENT_HOOK",
"AFL_FRIDA_PERSISTENT_RET", "AFL_FRIDA_STALKER_ADJACENT_BLOCKS",
@ -103,8 +101,8 @@ static char *afl_environment_variables[] = {
"AFL_PERSISTENT_RECORD", "AFL_POST_PROCESS_KEEP_ORIGINAL", "AFL_PRELOAD",
"AFL_TARGET_ENV", "AFL_PYTHON_MODULE", "AFL_QEMU_CUSTOM_BIN",
"AFL_QEMU_COMPCOV", "AFL_QEMU_COMPCOV_DEBUG", "AFL_QEMU_DEBUG_MAPS",
"AFL_QEMU_BLOCK_COV", "AFL_QEMU_DISABLE_CACHE", "AFL_QEMU_DRIVER_NO_HOOK",
"AFL_QEMU_FORCE_DFL", "AFL_QEMU_PERSISTENT_ADDR", "AFL_QEMU_PERSISTENT_CNT",
"AFL_QEMU_DISABLE_CACHE", "AFL_QEMU_DRIVER_NO_HOOK", "AFL_QEMU_FORCE_DFL",
"AFL_QEMU_PERSISTENT_ADDR", "AFL_QEMU_PERSISTENT_CNT",
"AFL_QEMU_PERSISTENT_GPR", "AFL_QEMU_PERSISTENT_HOOK",
"AFL_QEMU_PERSISTENT_MEM", "AFL_QEMU_PERSISTENT_RET",
"AFL_QEMU_PERSISTENT_RETADDR_OFFSET", "AFL_QEMU_PERSISTENT_EXITS",
@ -120,9 +118,7 @@ static char *afl_environment_variables[] = {
"AFL_CFISAN_VERBOSE", "AFL_USE_LSAN", "AFL_WINE_PATH", "AFL_NO_SNAPSHOT",
"AFL_EXPAND_HAVOC_NOW", "AFL_USE_FASAN", "AFL_USE_QASAN",
"AFL_PRINT_FILENAMES", "AFL_PIZZA_MODE", "AFL_NO_FASTRESUME",
"AFL_SAN_ABSTRACTION", "AFL_LLVM_ONLY_FSRV", "AFL_GCC_ONLY_FRSV",
"AFL_SAN_RECOVER", "AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT",
"AFL_FORKSRV_UID", "AFL_FORKSRV_GID", NULL};
"AFL_SAN_ABSTRACTION", "AFL_SAN_NO_INST", "AFL_SAN_RECOVER", NULL};
extern char *afl_environment_variables[];

View File

@ -159,8 +159,6 @@ typedef struct afl_forkserver {
u8 uses_asan; /* Target uses ASAN/LSAN/MSAN? (bit 0/1/2 respectively) */
bool setenv; /* setenv() to discriminate the forkserver? */
bool debug; /* debug mode? */
u8 san_but_not_instrumented; /* Is it sanitizer enabled but not instrumented?
@ -187,16 +185,6 @@ typedef struct afl_forkserver {
s32 persistent_record_pid;
#endif
u8 uid_set;
uid_t uid;
u8 gid_set;
pid_t gid;
u16 nb_supl_gids;
pid_t *supl_gids;
mode_t perm;
u8 chown_needed;
/* Function to kick off the forkserver child */
void (*init_child_func)(struct afl_forkserver *fsrv, char **argv);
@ -252,7 +240,6 @@ typedef enum fsrv_run_result {
void afl_fsrv_init(afl_forkserver_t *fsrv);
void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from);
void afl_fsrv_setup_preload(afl_forkserver_t *fsrv, char *argv0);
void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
volatile u8 *stop_soon_p, u8 debug_child_output);
u32 afl_fsrv_get_mapsize(afl_forkserver_t *fsrv, char **argv,

View File

@ -2,6 +2,18 @@
american fuzzy lop++ - hashing function
---------------------------------------
The hash32() function is a variant of MurmurHash3, a good
non-cryptosafe hashing function developed by Austin Appleby.
For simplicity, this variant does *NOT* accept buffer lengths
that are not divisible by 8 bytes. The 32-bit version is otherwise
similar to the original; the 64-bit one is a custom hack with
mostly-unproven properties.
Austin's original code is public domain.
Other code written by Michal Zalewski
Copyright 2016 Google Inc. All rights reserved.
Copyright 2019-2024 AFLplusplus Project. All rights reserved.
@ -21,5 +33,82 @@
u32 hash32(u8 *key, u32 len, u32 seed);
u64 hash64(u8 *key, u32 len, u64 seed);
#if 0
The following code is disabled because xxh3 is 30% faster
#ifdef __x86_64__
#define ROL64(_x, _r) ((((u64)(_x)) << (_r)) | (((u64)(_x)) >> (64 - (_r))))
static inline u32 hash32(u8 *key, u32 len, u32 seed) {
const u64 *data = (u64 *)key;
u64 h1 = seed ^ len;
len >>= 3;
while (len--) {
u64 k1 = *data++;
k1 *= 0x87c37b91114253d5ULL;
k1 = ROL64(k1, 31);
k1 *= 0x4cf5ad432745937fULL;
h1 ^= k1;
h1 = ROL64(h1, 27);
h1 = h1 * 5 + 0x52dce729;
}
h1 ^= h1 >> 33;
h1 *= 0xff51afd7ed558ccdULL;
h1 ^= h1 >> 33;
h1 *= 0xc4ceb9fe1a85ec53ULL;
h1 ^= h1 >> 33;
return h1;
}
#else
#define ROL32(_x, _r) ((((u32)(_x)) << (_r)) | (((u32)(_x)) >> (32 - (_r))))
static inline u32 hash32(const void *key, u32 len, u32 seed) {
const u32 *data = (u32 *)key;
u32 h1 = seed ^ len;
len >>= 2;
while (len--) {
u32 k1 = *data++;
k1 *= 0xcc9e2d51;
k1 = ROL32(k1, 15);
k1 *= 0x1b873593;
h1 ^= k1;
h1 = ROL32(h1, 13);
h1 = h1 * 5 + 0xe6546b64;
}
h1 ^= h1 >> 16;
h1 *= 0x85ebca6b;
h1 ^= h1 >> 13;
h1 *= 0xc2b2ae35;
h1 ^= h1 >> 16;
return h1;
}
#endif /* ^__x86_64__ */
#endif
#endif /* !_HAVE_HASH_H */

View File

@ -57,8 +57,7 @@ typedef struct sharedmem {
} sharedmem_t;
u8 *afl_shm_init(sharedmem_t *, size_t, unsigned char non_instrumented_mode,
mode_t mode, int gid);
u8 *afl_shm_init(sharedmem_t *, size_t, unsigned char non_instrumented_mode);
void afl_shm_deinit(sharedmem_t *);
#endif

View File

@ -327,13 +327,13 @@ class ModuleSanitizerCoverageLTOLegacyPass : public ModulePass {
};
if (!getenv("AFL_LLVM_ONLY_FSRV")) {
if (!getenv("AFL_SAN_NO_INST")) {
return ModuleSancov.instrumentModule(M, DTCallback, PDTCallback);
} else {
if (getenv("AFL_DEBUG")) { DEBUGF("Instrumentation disabled\n"); }
if (getenv("AFL_DEBUG")) { DEBUGF("Instrument disabled\n"); }
return false;
}
@ -389,14 +389,14 @@ PreservedAnalyses ModuleSanitizerCoverageLTO::run(Module &M,
};
if (!getenv("AFL_LLVM_ONLY_FSRV")) {
if (!getenv("AFL_SAN_NO_INST")) {
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
return PreservedAnalyses::none();
} else {
if (debug) { DEBUGF("Instrumentation disabled\n"); }
if (debug) { DEBUGF("Instrument disabled\n"); }
}

View File

@ -13,7 +13,6 @@
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
// #include "llvm/IR/Verifier.h"
#if LLVM_VERSION_MAJOR >= 15
#if LLVM_VERSION_MAJOR < 17
#include "llvm/ADT/Triple.h"
@ -77,9 +76,9 @@
#else
#include "llvm/Transforms/Utils/Instrumentation.h"
#endif
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include "llvm/ADT/STLExtras.h"
#include "config.h"
#include "debug.h"
@ -207,8 +206,7 @@ class ModuleSanitizerCoverageAFL
SanitizerCoverageOptions Options;
uint32_t instr = 0, selects = 0, hidden = 0, unhandled = 0, skippedbb = 0,
dump_cc = 0;
uint32_t instr = 0, selects = 0, unhandled = 0, dump_cc = 0;
GlobalVariable *AFLMapPtr = NULL;
ConstantInt *One = NULL;
ConstantInt *Zero = NULL;
@ -224,6 +222,9 @@ llvmGetPassPluginInfo() {
/* lambda to insert our pass into the pass pipeline. */
[](PassBuilder &PB) {
#if LLVM_VERSION_MAJOR == 13
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
#endif
#if LLVM_VERSION_MAJOR >= 16
PB.registerOptimizerEarlyEPCallback([](ModulePassManager &MPM,
OptimizationLevel OL
@ -271,14 +272,14 @@ PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M,
// TODO: Support LTO or llvm classic?
// Note we still need afl-compiler-rt so we just disable the instrumentation
// here.
if (!getenv("AFL_LLVM_ONLY_FSRV")) {
if (!getenv("AFL_SAN_NO_INST")) {
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
return PreservedAnalyses::none();
} else {
if (getenv("AFL_DEBUG")) { DEBUGF("Instrumentation disabled\n"); }
if (getenv("AFL_DEBUG")) { DEBUGF("Instrument disabled\n"); }
}
@ -504,16 +505,9 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
getenv("AFL_USE_TSAN") ? ", TSAN" : "",
getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
char buf[32] = "";
if (skippedbb) {
snprintf(buf, sizeof(buf), " %u instrumentations saved.", skippedbb);
}
OKF("Instrumented %u locations with no collisions (%s mode) of which are "
"%u handled and %u unhandled special instructions.%s",
instr, modeline, selects + hidden, unhandled, buf);
"%u handled and %u unhandled selects.",
instr, modeline, selects, unhandled);
}
@ -787,14 +781,11 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
if (AllBlocks.empty()) return false;
uint32_t cnt_cov = 0, cnt_sel = 0, cnt_sel_inc = 0, cnt_hidden_sel = 0,
cnt_hidden_sel_inc = 0, skip_blocks = 0;
uint32_t cnt_cov = 0, cnt_sel = 0, cnt_sel_inc = 0;
static uint32_t first = 1;
for (auto &BB : F) {
bool block_is_instrumented = false;
for (auto &IN : BB) {
CallInst *callInst = nullptr;
@ -808,11 +799,11 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
if (!FuncName.compare(StringRef("dlopen")) ||
!FuncName.compare(StringRef("_dlopen"))) {
WARNF(
"dlopen() detected. To have coverage for a library that your "
"target dlopen()'s this must either happen before __AFL_INIT() "
"or you must use AFL_PRELOAD to preload all dlopen()'ed "
"libraries!\n");
fprintf(stderr,
"WARNING: dlopen() detected. To have coverage for a library "
"that your target dlopen()'s this must either happen before "
"__AFL_INIT() or you must use AFL_PRELOAD to preload all "
"dlopen()'ed libraries!\n");
continue;
}
@ -820,183 +811,53 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
if (!FuncName.compare(StringRef("__afl_coverage_interesting"))) {
cnt_cov++;
block_is_instrumented = true;
}
}
bool instrumentInst = false;
ICmpInst *icmp;
FCmpInst *fcmp;
SelectInst *selectInst = nullptr;
if ((icmp = dyn_cast<ICmpInst>(&IN)) ||
(fcmp = dyn_cast<FCmpInst>(&IN)) || isa<SelectInst>(&IN)) {
if ((selectInst = dyn_cast<SelectInst>(&IN))) {
// || isa<PHINode>(&IN)
Value *c = selectInst->getCondition();
auto t = c->getType();
if (t->getTypeID() == llvm::Type::IntegerTyID) {
bool usedInBranch = false, usedInSelectDecision = false;
cnt_sel++;
cnt_sel_inc += 2;
for (auto *U : IN.users()) {
}
if (isa<BranchInst>(U)) {
else if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
usedInBranch = true;
break;
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
if (tt) {
}
if (auto *sel = dyn_cast<SelectInst>(U)) {
if (icmp && sel->getCondition() == icmp) {
usedInSelectDecision = true;
} else if (fcmp && sel->getCondition() == fcmp) {
usedInSelectDecision = true;
}
cnt_sel++;
cnt_sel_inc += (tt->getElementCount().getKnownMinValue() * 2);
}
}
if (!usedInBranch && !usedInSelectDecision) {
// errs() << "Instrument! " << *(&IN) << "\n";
instrumentInst = true;
}
}
if (instrumentInst) {
block_is_instrumented = true;
SelectInst *selectInst;
ICmpInst *icmp;
FCmpInst *fcmp;
// PHINode *phiInst;
// errs() << "IN: " << *(&IN) << "\n";
/* if ((phiInst = dyn_cast<PHINode>(&IN))) {
cnt_hidden_sel++;
cnt_hidden_sel_inc += phiInst->getNumIncomingValues();
} else*/
if ((icmp = dyn_cast<ICmpInst>(&IN))) {
if (icmp->getType()->isIntegerTy(1)) {
cnt_sel++;
cnt_sel_inc += 2;
} else {
unhandled++;
}
} else if ((fcmp = dyn_cast<FCmpInst>(&IN))) {
if (fcmp->getType()->isIntegerTy(1)) {
cnt_sel++;
cnt_sel_inc += 2;
} else {
unhandled++;
}
} else if ((selectInst = dyn_cast<SelectInst>(&IN))) {
Value *c = selectInst->getCondition();
auto t = c->getType();
if (t->getTypeID() == llvm::Type::IntegerTyID) {
cnt_sel++;
cnt_sel_inc += 2;
} else if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
if (tt) {
cnt_sel++;
cnt_sel_inc += (tt->getElementCount().getKnownMinValue() * 2);
}
} else {
if (!be_quiet) {
WARNF("unknown select ID type: %u\n", t->getTypeID());
}
}
} /*else {
cnt_hidden_sel++;
cnt_hidden_sel_inc += 2;
}*/
}
}
if (block_is_instrumented && &BB != &BB.getParent()->getEntryBlock() &&
llvm::is_contained(AllBlocks, &BB)) {
Instruction *instr = &*BB.begin();
LLVMContext &Ctx = BB.getContext();
MDNode *md = MDNode::get(Ctx, MDString::get(Ctx, "skipinstrument"));
instr->setMetadata("tag", md);
skip_blocks++;
}
}
uint32_t xtra = 0;
if (skip_blocks < first + cnt_cov + cnt_sel_inc + cnt_hidden_sel_inc) {
xtra = first + cnt_cov + cnt_sel_inc + cnt_hidden_sel_inc - skip_blocks;
}
CreateFunctionLocalArrays(F, AllBlocks, xtra);
if (!FunctionGuardArray) {
WARNF(
"SANCOV: FunctionGuardArray is NULL, failed to emit instrumentation.");
return false;
}
CreateFunctionLocalArrays(F, AllBlocks, first + cnt_cov + cnt_sel_inc);
if (first) { first = 0; }
selects += cnt_sel;
hidden += cnt_hidden_sel;
uint32_t special = 0, local_selects = 0, skip_select = 0, skip_icmp = 0;
// uint32_t skip_phi = 0;
uint32_t special = 0, local_selects = 0, skip_next = 0;
for (auto &BB : F) {
// errs() << *(&BB) << "\n";
for (auto &IN : BB) {
// errs() << *(&IN) << "\n";
CallInst *callInst = nullptr;
if ((callInst = dyn_cast<CallInst>(&IN))) {
@ -1014,6 +875,15 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
IRBuilder<> IRB(callInst);
#endif
if (!FunctionGuardArray) {
fprintf(stderr,
"SANCOV: FunctionGuardArray is NULL, failed to emit "
"instrumentation.");
continue;
}
Value *GuardPtr = IRB.CreateIntToPtr(
IRB.CreateAdd(
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
@ -1027,322 +897,132 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
}
bool instrumentInst = false;
ICmpInst *icmp;
FCmpInst *fcmp;
SelectInst *selectInst = nullptr;
if ((icmp = dyn_cast<ICmpInst>(&IN)) ||
(fcmp = dyn_cast<FCmpInst>(&IN)) || isa<SelectInst>(&IN)) {
if (!skip_next && (selectInst = dyn_cast<SelectInst>(&IN))) {
// || isa<PHINode>(&IN)
bool usedInBranch = false, usedInSelectDecision = false;
for (auto *U : IN.users()) {
if (isa<BranchInst>(U)) {
usedInBranch = true;
break;
}
if (auto *sel = dyn_cast<SelectInst>(U)) {
if (icmp && sel->getCondition() == icmp) {
usedInSelectDecision = true;
break;
} else if (fcmp && sel->getCondition() == fcmp) {
usedInSelectDecision = true;
break;
}
}
}
if (!usedInBranch && !usedInSelectDecision) {
// errs() << "Instrument! " << *(&IN) << "\n";
instrumentInst = true;
}
}
if (instrumentInst) {
Value *result = nullptr;
uint32_t vector_cnt = 0;
SelectInst *selectInst;
// PHINode *phi = nullptr, *newPhi = nullptr;
IRBuilder<> IRB(IN.getNextNode());
Value *condition = selectInst->getCondition();
Value *result;
auto t = condition->getType();
IRBuilder<> IRB(selectInst->getNextNode());
if ((icmp = dyn_cast<ICmpInst>(&IN))) {
if (t->getTypeID() == llvm::Type::IntegerTyID) {
if (!icmp->getType()->isIntegerTy(1)) { continue; }
if (!FunctionGuardArray) {
if (skip_icmp) {
skip_icmp--;
fprintf(stderr,
"SANCOV: FunctionGuardArray is NULL, failed to emit "
"instrumentation.");
continue;
}
if (debug) {
if (DILocation *Loc = IN.getDebugLoc()) {
llvm::errs() << "DEBUG " << Loc->getFilename() << ":"
<< Loc->getLine() << ":";
std::string path =
Loc->getDirectory().str() + "/" + Loc->getFilename().str();
std::ifstream sourceFile(path);
std::string lineContent;
for (unsigned line = 1; line <= Loc->getLine(); ++line)
std::getline(sourceFile, lineContent);
llvm::errs() << lineContent << "\n";
}
errs() << *(&IN) << "\n";
}
auto res = icmp;
auto GuardPtr1 = IRB.CreateInBoundsGEP(
FunctionGuardArray->getValueType(), FunctionGuardArray,
{IRB.getInt64(0),
IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))});
auto GuardPtr2 = IRB.CreateInBoundsGEP(
FunctionGuardArray->getValueType(), FunctionGuardArray,
{IRB.getInt64(0),
IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))});
result = IRB.CreateSelect(res, GuardPtr1, GuardPtr2);
skip_select = 1;
// fprintf(stderr, "Icmp!\n");
} else if ((fcmp = dyn_cast<FCmpInst>(&IN))) {
if (!fcmp->getType()->isIntegerTy(1)) { continue; }
if (debug) {
if (DILocation *Loc = IN.getDebugLoc()) {
llvm::errs() << "DEBUG " << Loc->getFilename() << ":"
<< Loc->getLine() << ":";
std::string path =
Loc->getDirectory().str() + "/" + Loc->getFilename().str();
std::ifstream sourceFile(path);
std::string lineContent;
for (unsigned line = 1; line <= Loc->getLine(); ++line)
std::getline(sourceFile, lineContent);
llvm::errs() << lineContent << "\n";
}
errs() << *(&IN) << "\n";
}
auto res = fcmp;
auto GuardPtr1 = IRB.CreateInBoundsGEP(
FunctionGuardArray->getValueType(), FunctionGuardArray,
{IRB.getInt64(0),
IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))});
auto GuardPtr2 = IRB.CreateInBoundsGEP(
FunctionGuardArray->getValueType(), FunctionGuardArray,
{IRB.getInt64(0),
IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))});
result = IRB.CreateSelect(res, GuardPtr1, GuardPtr2);
skip_select = 1;
// fprintf(stderr, "Fcmp!\n");
/*} else if ((phi = dyn_cast<PHINode>(&IN))) {
if (skip_phi) {
skip_phi = 0;
// errs() << "SKIP: " << *(&IN) << "\n";
continue;
}
// errs() << "-->PHI: " << *(&IN) << "\n";
// continue;
Instruction *insertBefore =
&*phi->getParent()->getFirstInsertionPt(); newPhi =
PHINode::Create(Int32PtrTy, 0, "", insertBefore); BasicBlock
*phiBlock = phi->getParent();
for (BasicBlock *pred : predecessors(phiBlock)) {
IRBuilder<> predBuilder(pred->getTerminator());
Value *ptr = predBuilder.CreateInBoundsGEP(
FunctionGuardArray->getValueType(), FunctionGuardArray,
auto GuardPtr1 = IRB.CreateIntToPtr(
IRB.CreateAdd(
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
ConstantInt::get(
IntptrTy, (cnt_cov + local_selects++ +
AllBlocks.size()))); newPhi->addIncoming(ptr, pred);
IntptrTy,
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
Int32PtrTy);
}
auto GuardPtr2 = IRB.CreateIntToPtr(
IRB.CreateAdd(
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
ConstantInt::get(
IntptrTy,
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
Int32PtrTy);
result = newPhi;
skip_phi = 1;
// fprintf(stderr, "Phi!\n");
*/
result = IRB.CreateSelect(condition, GuardPtr1, GuardPtr2);
} else if ((selectInst = dyn_cast<SelectInst>(&IN))) {
} else
if (skip_select) {
#if LLVM_VERSION_MAJOR >= 14
if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
skip_select = 0;
continue;
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
if (tt) {
} else {
uint32_t elements = tt->getElementCount().getFixedValue();
vector_cnt = elements;
if (elements) {
// fprintf(stderr, "Select!\n");
FixedVectorType *GuardPtr1 =
FixedVectorType::get(Int32PtrTy, elements);
FixedVectorType *GuardPtr2 =
FixedVectorType::get(Int32PtrTy, elements);
Value *x, *y;
}
if (!FunctionGuardArray) {
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 (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;
fprintf(stderr,
"SANCOV: FunctionGuardArray is NULL, failed to emit "
"instrumentation.");
continue;
}
}
Value *val1 = IRB.CreateIntToPtr(
IRB.CreateAdd(
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
ConstantInt::get(
IntptrTy,
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
Int32PtrTy);
x = IRB.CreateInsertElement(GuardPtr1, val1, (uint64_t)0);
} else
Value *val2 = IRB.CreateIntToPtr(
IRB.CreateAdd(
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
ConstantInt::get(
IntptrTy,
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
Int32PtrTy);
y = IRB.CreateInsertElement(GuardPtr2, val2, (uint64_t)0);
{
for (uint64_t i = 1; i < elements; i++) {
if (!be_quiet) {
val1 = IRB.CreateIntToPtr(
IRB.CreateAdd(
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
ConstantInt::get(IntptrTy, (cnt_cov + local_selects++ +
AllBlocks.size()) *
4)),
Int32PtrTy);
x = IRB.CreateInsertElement(x, val1, i);
WARNF("Warning: Unhandled ID type: %u\n", t->getTypeID());
val2 = IRB.CreateIntToPtr(
IRB.CreateAdd(
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
ConstantInt::get(IntptrTy, (cnt_cov + local_selects++ +
AllBlocks.size()) *
4)),
Int32PtrTy);
y = IRB.CreateInsertElement(y, val2, i);
}
result = IRB.CreateSelect(condition, x, y);
}
unhandled++;
continue;
}
} else
#endif
{
// fprintf(stderr, "UNHANDLED: %u\n", t->getTypeID());
unhandled++;
continue;
}
uint32_t vector_cur = 0;
/* Load SHM pointer */
/*
if (newPhi) {
auto *inst = dyn_cast<Instruction>(result);
PHINode *nphi;
while ((nphi = dyn_cast<PHINode>(inst))) {
// fprintf(stderr, "NEXT!\n");
inst = inst->getNextNode();
}
IRB.SetInsertPoint(inst);
}
*/
LoadInst *MapPtr =
IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr);
@ -1374,7 +1054,9 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
if (use_threadsafe_counters) {
IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One,
#if LLVM_VERSION_MAJOR >= 13
llvm::MaybeAlign(1),
#endif
llvm::AtomicOrdering::Monotonic);
} else {
@ -1391,7 +1073,6 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
auto cf = IRB.CreateICmpEQ(Incr, Zero);
auto carry = IRB.CreateZExt(cf, Int8Ty);
Incr = IRB.CreateAdd(Incr, carry);
skip_icmp++;
}
@ -1413,8 +1094,13 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
}
skip_next = 1;
instr += vector_cnt;
} else {
skip_next = 0;
}
}
@ -1423,40 +1109,9 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
if (AllBlocks.empty() && !special && !local_selects) return false;
uint32_t skipped = 0;
if (!AllBlocks.empty()) {
for (size_t i = 0, N = AllBlocks.size(); i < N; i++) {
auto instr = AllBlocks[i]->begin();
if (instr->getMetadata("skipinstrument")) {
skipped++;
// fprintf(stderr, "Skipped!\n");
} else {
InjectCoverageAtBlock(F, *AllBlocks[i], i - skipped, IsLeafFunc);
}
}
}
skippedbb += skipped;
/*
if (verifyFunction(F, &errs())) {
errs() << "Broken function after instrumentation\n";
F.print(errs(), nullptr);
report_fatal_error("Invalid IR");
}
*/
if (!AllBlocks.empty())
for (size_t i = 0, N = AllBlocks.size(); i < N; i++)
InjectCoverageAtBlock(F, *AllBlocks[i], i, IsLeafFunc);
return true;
@ -1626,7 +1281,10 @@ void ModuleSanitizerCoverageAFL::InjectCoverageAtBlock(Function &F,
if (use_threadsafe_counters) {
IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One,
llvm::MaybeAlign(1), llvm::AtomicOrdering::Monotonic);
#if LLVM_VERSION_MAJOR >= 13
llvm::MaybeAlign(1),
#endif
llvm::AtomicOrdering::Monotonic);
} else {
@ -1694,3 +1352,4 @@ std::string ModuleSanitizerCoverageAFL::getSectionEnd(
return "__stop___" + Section;
}

View File

@ -119,8 +119,6 @@ u64 __afl_map_addr;
u32 __afl_first_final_loc;
u32 __afl_old_forkserver;
u8 __afl_forkserver_setenv = 0;
#ifdef __AFL_CODE_COVERAGE
typedef struct afl_module_info_t afl_module_info_t;
@ -294,25 +292,6 @@ static void __afl_map_shm_fuzz() {
u8 *map = NULL;
#ifdef USEMMAP
// Newer afl-fuzz versions will set a shm_fuzz page size env, else fall back
size_t shm_fuzz_map_size = SHM_FUZZ_MAP_SIZE_DEFAULT;
char *map_size_env = getenv(SHM_FUZZ_MAP_SIZE_ENV_VAR);
if (map_size_env != NULL) {
char *endptr;
errno = 0;
shm_fuzz_map_size = (size_t)strtoul(map_size_env, &endptr, 10);
if (errno != 0 || shm_fuzz_map_size == 0) {
perror("shm_fuzz mapping size parsing");
send_forkserver_error(FS_ERROR_SHM_OPEN);
_exit(1);
}
}
const char *shm_file_path = id_str;
int shm_fd = -1;
@ -326,7 +305,8 @@ static void __afl_map_shm_fuzz() {
}
map = (u8 *)mmap(0, shm_fuzz_map_size, PROT_READ, MAP_SHARED, shm_fd, 0);
map =
(u8 *)mmap(0, MAX_FILE + sizeof(u32), PROT_READ, MAP_SHARED, shm_fd, 0);
#else
u32 shm_id = atoi(id_str);
@ -382,7 +362,6 @@ static void __afl_map_shm(void) {
if (getenv("AFL_DUMP_MAP_SIZE")) {
printf("%u\n", __afl_map_size);
fflush(stdout);
exit(-1);
}
@ -909,12 +888,6 @@ 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. */
@ -940,12 +913,7 @@ static void __afl_start_forkserver(void) {
}
if (write(FORKSRV_FD + 1, msg, 4) != 4) {
errno = 0;
_exit(1);
}
if (write(FORKSRV_FD + 1, msg, 4) != 4) { _exit(1); }
// Now send the parameters for the set options, increasing by option number
@ -1086,13 +1054,6 @@ static void __afl_start_forkserver(void) {
close(FORKSRV_FD);
close(FORKSRV_FD + 1);
if (unlikely(__afl_forkserver_setenv)) {
unsetenv("AFL_FORKSERVER_PARENT");
}
return;
}
@ -1265,15 +1226,6 @@ void __afl_manual_init(void) {
}
if (getenv("AFL_LLVM_ONLY_FSRV") || getenv("AFL_GCC_ONLY_FRSV")) {
fprintf(stderr,
"DEBUG: Overwrite area_ptr to dummy due to "
"AFL_LLVM_ONLY_FSRV/AFL_GCC_ONLY_FRSV\n");
__afl_area_ptr = __afl_area_ptr_dummy;
}
if (!init_done) {
__afl_start_forkserver();

View File

@ -44,8 +44,8 @@ static const struct pass_data afl_cmplog_pass_data = {
.properties_provided = 0,
.properties_destroyed = 0,
.todo_flags_start = 0,
.todo_flags_finish =
(TODO_update_ssa | TODO_cleanup_cfg | TODO_rebuild_cgraph_edges),
.todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg | TODO_verify_il |
TODO_rebuild_cgraph_edges),
};

View File

@ -44,8 +44,8 @@ static const struct pass_data afl_cmptrs_pass_data = {
.properties_provided = 0,
.properties_destroyed = 0,
.todo_flags_start = 0,
.todo_flags_finish =
(TODO_update_ssa | TODO_cleanup_cfg | TODO_rebuild_cgraph_edges),
.todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg | TODO_verify_il |
TODO_rebuild_cgraph_edges),
};

View File

@ -65,6 +65,7 @@
The new pass is to be a GIMPLE_PASS. Given the sort of
instrumentation it's supposed to do, its todo_flags_finish will
certainly need TODO_update_ssa, and TODO_cleanup_cfg.
TODO_verify_il is probably desirable, at least during debugging.
TODO_rebuild_cgraph_edges is required only in the out-of-line
instrumentation mode.
@ -147,7 +148,7 @@ static constexpr struct pass_data afl_pass_data = {
.properties_provided = 0,
.properties_destroyed = 0,
.todo_flags_start = 0,
.todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg),
.todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg | TODO_verify_il),
};
@ -461,7 +462,6 @@ static struct plugin_info afl_plugin = {
.help = G_("AFL gcc plugin\n\
\n\
Set AFL_QUIET in the environment to silence it.\n\
Set AFL_GCC_ONLY_FRSV in the environment to disable instrumentation.\n\
\n\
Set AFL_INST_RATIO in the environment to a number from 0 to 100\n\
to control how likely a block will be chosen for instrumentation.\n\
@ -502,10 +502,9 @@ int plugin_init(struct plugin_name_args *info,
case it was specified in the command line's -frandom-seed for
reproducible instrumentation. */
srandom(get_random_seed(false));
bool fsrv_only = !!getenv("AFL_GCC_ONLY_FRSV");
const char *name = info->base_name;
if (!fsrv_only) { register_callback(name, PLUGIN_INFO, NULL, &afl_plugin); }
register_callback(name, PLUGIN_INFO, NULL, &afl_plugin);
afl_pass *aflp = new afl_pass(quiet, inst_ratio);
struct register_pass_info pass_info = {
@ -517,20 +516,14 @@ int plugin_init(struct plugin_name_args *info,
};
if (!fsrv_only) {
register_callback(name, PLUGIN_PASS_MANAGER_SETUP, NULL, &pass_info);
register_callback(name, PLUGIN_FINISH, afl_pass::plugin_finalize,
pass_info.pass);
}
register_callback(name, PLUGIN_PASS_MANAGER_SETUP, NULL, &pass_info);
register_callback(name, PLUGIN_FINISH, afl_pass::plugin_finalize,
pass_info.pass);
if (!quiet)
ACTF(G_("%s instrumentation at ratio of %u%% in %s mode."),
aflp->out_of_line ? G_("Call-based") : G_("Inline"), inst_ratio,
getenv("AFL_HARDEN") ? G_("hardened") : G_("non-hardened"));
else if (fsrv_only)
ACTF("Instrumentation disabled due to AFL_GCC_ONLY_FRSV");
return 0;

View File

@ -85,7 +85,10 @@ char *getBBName(const llvm::BasicBlock *BB) {
std::string Str;
raw_string_ostream OS(Str);
#if LLVM_VERSION_MAJOR >= 4 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7)
BB->printAsOperand(OS, false);
#endif
name = strdup(OS.str().c_str());
return name;
@ -336,6 +339,9 @@ void scanForDangerousFunctions(llvm::Module *M) {
if (!M) return;
#if LLVM_VERSION_MAJOR >= 4 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 9)
for (GlobalIFunc &IF : M->ifuncs()) {
StringRef ifunc_name = IF.getName();
@ -402,6 +408,8 @@ void scanForDangerousFunctions(llvm::Module *M) {
}
#endif
}
static std::string getSourceName(llvm::Function *F) {
@ -412,6 +420,8 @@ static std::string getSourceName(llvm::Function *F) {
IRBuilder<> IRB(&(*IP));
DebugLoc Loc = IP->getDebugLoc();
#if LLVM_VERSION_MAJOR >= 4 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7)
if (Loc) {
StringRef instFilename;
@ -432,6 +442,20 @@ static std::string getSourceName(llvm::Function *F) {
}
#else
if (!Loc.isUnknown()) {
DILocation cDILoc(Loc.getAsMDNode(F->getContext()));
StringRef instFilename = cDILoc.getFilename();
/* Continue only if we know where we actually are */
return instFilename.str();
}
#endif
return std::string("");
}

View File

@ -18,6 +18,9 @@
#include <sys/time.h>
#include "llvm/Config/llvm-config.h"
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5
typedef long double max_align_t;
#endif
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LegacyPassManager.h"
@ -29,16 +32,27 @@
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#endif
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/CFG.h"
#if LLVM_VERSION_MAJOR > 3 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/CFG.h"
#else
#include "llvm/DebugInfo.h"
#include "llvm/Support/CFG.h"
#endif
#define MNAME M.getSourceFileName()
#define FMNAME F.getParent()->getSourceFileName()
#if LLVM_VERSION_MAJOR >= 16
#if LLVM_VERSION_MAJOR >= 11
#define MNAME M.getSourceFileName()
#define FMNAME F.getParent()->getSourceFileName()
#if LLVM_VERSION_MAJOR >= 16
// None becomes deprecated
// the standard std::nullopt_t is recommended instead
// from C++17 and onwards.
constexpr std::nullopt_t None = std::nullopt;
#endif
#else
#define MNAME std::string("")
#define FMNAME std::string("")
#endif
char *getBBName(const llvm::BasicBlock *BB);

View File

@ -39,9 +39,13 @@
#include "llvm/Config/llvm-config.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/IR/PassManager.h"
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/IR/PassManager.h"
#else
#include "llvm/IR/LegacyPassManager.h"
#endif
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/DebugInfo.h"
@ -68,6 +72,7 @@ using namespace llvm;
namespace {
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
class AFLdict2filePass : public PassInfoMixin<AFLdict2filePass> {
std::ofstream of;
@ -76,16 +81,35 @@ class AFLdict2filePass : public PassInfoMixin<AFLdict2filePass> {
public:
AFLdict2filePass() {
#else
class AFLdict2filePass : public ModulePass {
std::ofstream of;
void dict2file(u8 *, u32);
public:
static char ID;
AFLdict2filePass() : ModulePass(ID) {
#endif
if (getenv("AFL_DEBUG")) debug = 1;
}
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
#else
bool runOnModule(Module &M) override;
#endif
};
} // namespace
#if LLVM_MAJOR >= 11
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
llvmGetPassPluginInfo() {
@ -93,12 +117,15 @@ llvmGetPassPluginInfo() {
/* lambda to insert our pass into the pass pipeline. */
[](PassBuilder &PB) {
#if LLVM_VERSION_MAJOR <= 13
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
#endif
PB.registerOptimizerLastEPCallback([](ModulePassManager &MPM,
OptimizationLevel OL
#if LLVM_VERSION_MAJOR >= 20
#if LLVM_VERSION_MAJOR >= 20
,
ThinOrFullLTOPhase Phase
#endif
#endif
) {
MPM.addPass(AFLdict2filePass());
@ -109,6 +136,10 @@ llvmGetPassPluginInfo() {
}
#else
char AFLdict2filePass::ID = 0;
#endif
void AFLdict2filePass::dict2file(u8 *mem, u32 len) {
u32 i, j, binary = 0;
@ -148,8 +179,14 @@ void AFLdict2filePass::dict2file(u8 *mem, u32 len) {
}
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
PreservedAnalyses AFLdict2filePass::run(Module &M, ModuleAnalysisManager &MAM) {
#else
bool AFLdict2filePass::runOnModule(Module &M) {
#endif
DenseMap<Value *, std::string *> valueMap;
char *ptr;
int found = 0, handle_main = 1;
@ -176,8 +213,12 @@ PreservedAnalyses AFLdict2filePass::run(Module &M, ModuleAnalysisManager &MAM) {
if (!ptr) {
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
auto PA = PreservedAnalyses::all();
return PA;
#else
return true;
#endif
}
@ -713,7 +754,32 @@ PreservedAnalyses AFLdict2filePass::run(Module &M, ModuleAnalysisManager &MAM) {
}
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
auto PA = PreservedAnalyses::all();
return PA;
#else
return false;
#endif
}
#if LLVM_VERSION_MAJOR < 11 /* use old pass manager */
static void registerAFLdict2filePass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) {
PM.add(new AFLdict2filePass());
}
static RegisterPass<AFLdict2filePass> X("afl-dict2file",
"AFL++ dict2file instrumentation pass",
false, false);
static RegisterStandardPasses RegisterAFLdict2filePass(
PassManagerBuilder::EP_OptimizerLast, registerAFLdict2filePass);
static RegisterStandardPasses RegisterAFLdict2filePass0(
PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLdict2filePass);
#endif

View File

@ -43,7 +43,9 @@
#include "llvm/Passes/PassBuilder.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/CFG.h"
#include "llvm/Passes/OptimizationLevel.h"
#if LLVM_VERSION_MAJOR >= 14 /* how about stable interfaces? */
#include "llvm/Passes/OptimizationLevel.h"
#endif
#include "afl-llvm-common.h"
@ -78,6 +80,9 @@ llvmGetPassPluginInfo() {
/* lambda to insert our pass into the pass pipeline. */
[](PassBuilder &PB) {
#if LLVM_VERSION_MAJOR <= 13
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
#endif
PB.registerOptimizerLastEPCallback([](ModulePassManager &MPM,
OptimizationLevel OL
#if LLVM_VERSION_MAJOR >= 20
@ -130,8 +135,15 @@ PreservedAnalyses AFLcheckIfInstrument::run(Module &M,
auto &Ctx = F.getContext();
AttributeList Attrs = F.getAttributes();
#if LLVM_VERSION_MAJOR >= 14
AttributeList NewAttrs = Attrs.addFnAttribute(Ctx, "skipinstrument");
F.setAttributes(NewAttrs);
#else
AttrBuilder NewAttrs;
NewAttrs.addAttribute("skipinstrument");
F.setAttributes(
Attrs.addAttributes(Ctx, AttributeList::FunctionIndex, NewAttrs));
#endif
}
@ -142,3 +154,20 @@ PreservedAnalyses AFLcheckIfInstrument::run(Module &M,
}
#if 0
static void registerAFLcheckIfInstrumentpass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) {
PM.add(new AFLcheckIfInstrument());
}
static RegisterStandardPasses RegisterAFLcheckIfInstrumentpass(
PassManagerBuilder::EP_ModuleOptimizerEarly,
registerAFLcheckIfInstrumentpass);
static RegisterStandardPasses RegisterAFLcheckIfInstrumentpass0(
PassManagerBuilder::EP_EnabledOnOptLevel0,
registerAFLcheckIfInstrumentpass);
#endif

View File

@ -38,17 +38,30 @@ typedef long double max_align_t;
#endif
#include "llvm/Pass.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/IR/PassManager.h"
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/IR/PassManager.h"
#else
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#endif
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Passes/OptimizationLevel.h"
#if LLVM_VERSION_MAJOR >= 14 /* how about stable interfaces? */
#include "llvm/Passes/OptimizationLevel.h"
#endif
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/CFG.h"
#if LLVM_VERSION_MAJOR >= 4 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/CFG.h"
#else
#include "llvm/DebugInfo.h"
#include "llvm/Support/CFG.h"
#endif
#include "llvm/IR/IRBuilder.h"
@ -59,16 +72,30 @@ using namespace llvm;
namespace {
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
class AFLCoverage : public PassInfoMixin<AFLCoverage> {
public:
AFLCoverage() {
#else
class AFLCoverage : public ModulePass {
public:
static char ID;
AFLCoverage() : ModulePass(ID) {
#endif
initInstrumentList();
}
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
#else
bool runOnModule(Module &M) override;
#endif
protected:
uint32_t ngram_size = 0;
@ -82,37 +109,97 @@ class AFLCoverage : public PassInfoMixin<AFLCoverage> {
} // namespace
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
extern "C" LLVM_ATTRIBUTE_WEAK PassPluginLibraryInfo llvmGetPassPluginInfo() {
return {LLVM_PLUGIN_API_VERSION, "AFLCoverage", "v0.1",
/* lambda to insert our pass into the pass pipeline. */
[](PassBuilder &PB) {
#if LLVM_VERSION_MAJOR >= 16
#if 1
#if LLVM_VERSION_MAJOR <= 13
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
#endif
#if LLVM_VERSION_MAJOR >= 16
PB.registerOptimizerEarlyEPCallback(
#else
#else
PB.registerOptimizerLastEPCallback(
#endif
#endif
[](ModulePassManager &MPM, OptimizationLevel OL
#if LLVM_VERSION_MAJOR >= 20
#if LLVM_VERSION_MAJOR >= 20
,
ThinOrFullLTOPhase Phase
#endif
#endif
) {
MPM.addPass(AFLCoverage());
});
/* TODO LTO registration */
#else
using PipelineElement = typename PassBuilder::PipelineElement;
PB.registerPipelineParsingCallback([](StringRef Name,
ModulePassManager &MPM,
ArrayRef<PipelineElement>) {
if (Name == "AFLCoverage") {
MPM.addPass(AFLCoverage());
return true;
} else {
return false;
}
});
#endif
}};
}
/* #if LLVM_VERSION_STRING >= "4.0.1" */
#define AFL_HAVE_VECTOR_INTRINSICS 1
#else
char AFLCoverage::ID = 0;
#endif
/* needed up to 3.9.0 */
#if LLVM_VERSION_MAJOR == 3 && \
(LLVM_VERSION_MINOR < 9 || \
(LLVM_VERSION_MINOR == 9 && LLVM_VERSION_PATCH < 1))
uint64_t PowerOf2Ceil(unsigned in) {
uint64_t in64 = in - 1;
in64 |= (in64 >> 1);
in64 |= (in64 >> 2);
in64 |= (in64 >> 4);
in64 |= (in64 >> 8);
in64 |= (in64 >> 16);
in64 |= (in64 >> 32);
return in64 + 1;
}
#endif
/* #if LLVM_VERSION_STRING >= "4.0.1" */
#if LLVM_VERSION_MAJOR >= 5 || \
(LLVM_VERSION_MAJOR == 4 && LLVM_VERSION_PATCH >= 1)
#define AFL_HAVE_VECTOR_INTRINSICS 1
#endif
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
#else
bool AFLCoverage::runOnModule(Module &M) {
#endif
LLVMContext &C = M.getContext();
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
@ -137,13 +224,24 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
if (getenv("AFL_DEBUG")) debug = 1;
if (getenv("AFL_LLVM_ONLY_FSRV")) {
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
if (getenv("AFL_SAN_NO_INST")) {
if (debug) { fprintf(stderr, "Instrumentation disabled\n"); }
if (debug) { fprintf(stderr, "Instrument disabled\n"); }
return PreservedAnalyses::all();
}
#else
if (getenv("AFL_SAN_NO_INST")) {
if (debug) { fprintf(stderr, "Instrument disabled\n"); }
return true;
}
#endif
if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
SAYF(cCYA "afl-llvm-pass" VERSION cRST
@ -179,6 +277,9 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
}
#if LLVM_VERSION_MAJOR < 9
char *neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO");
#endif
skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST");
@ -296,12 +397,24 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
#ifdef AFL_HAVE_VECTOR_INTRINSICS
int PrevLocVecSize = PowerOf2Ceil(PrevLocSize);
if (ngram_size) PrevLocTy = VectorType::get(IntLocTy, PrevLocVecSize, false);
if (ngram_size)
PrevLocTy = VectorType::get(IntLocTy, PrevLocVecSize
#if LLVM_VERSION_MAJOR >= 12
,
false
#endif
);
#endif
#ifdef AFL_HAVE_VECTOR_INTRINSICS
int PrevCallerVecSize = PowerOf2Ceil(PrevCallerSize);
if (ctx_k) PrevCallerTy = VectorType::get(IntLocTy, PrevCallerVecSize, false);
if (ctx_k)
PrevCallerTy = VectorType::get(IntLocTy, PrevCallerVecSize
#if LLVM_VERSION_MAJOR >= 12
,
false
#endif
);
#endif
/* Get globals for the SHM region and the previous location. Note that
@ -439,7 +552,11 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
#ifdef AFL_HAVE_VECTOR_INTRINSICS
if (ctx_k) {
PrevCaller = IRB.CreateLoad(PrevCallerTy, AFLPrevCaller);
PrevCaller = IRB.CreateLoad(
#if LLVM_VERSION_MAJOR >= 14
PrevCallerTy,
#endif
AFLPrevCaller);
PrevCaller->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
PrevCtx =
@ -452,7 +569,11 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
// load the context ID of the previous function and write to a
// local variable on the stack
LoadInst *PrevCtxLoad = IRB.CreateLoad(IRB.getInt32Ty(), AFLContext);
LoadInst *PrevCtxLoad = IRB.CreateLoad(
#if LLVM_VERSION_MAJOR >= 14
IRB.getInt32Ty(),
#endif
AFLContext);
PrevCtxLoad->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
PrevCtx = PrevCtxLoad;
@ -526,11 +647,11 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
// cur_loc++;
cur_loc = AFL_R(map_size);
/* There is a problem with Ubuntu 18.04 and llvm 6.0 (see issue #63).
The inline function successors() is not inlined and also not found at
runtime
:-( As I am unable to detect Ubuntu18.04 here, the next best thing is
to disable this optional optimization for LLVM 6.0.0 and Linux */
/* There is a problem with Ubuntu 18.04 and llvm 6.0 (see issue #63).
The inline function successors() is not inlined and also not found at runtime
:-( As I am unable to detect Ubuntu18.04 here, the next best thing is to
disable this optional optimization for LLVM 6.0.0 and Linux */
#if !(LLVM_VERSION_MAJOR == 6 && LLVM_VERSION_MINOR == 0) || !defined __linux__
// only instrument if this basic block is the destination of a previous
// basic block that has multiple successors
// this gets rid of ~5-10% of instrumentations that are unnecessary
@ -575,11 +696,11 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
IRBuilder<> Post_IRB(Inst);
StoreInst *RestoreCtx;
#ifdef AFL_HAVE_VECTOR_INTRINSICS
#ifdef AFL_HAVE_VECTOR_INTRINSICS
if (ctx_k)
RestoreCtx = IRB.CreateStore(PrevCaller, AFLPrevCaller);
else
#endif
#endif
RestoreCtx = Post_IRB.CreateStore(PrevCtx, AFLContext);
RestoreCtx->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
@ -592,6 +713,8 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
}
#endif
ConstantInt *CurLoc;
#ifdef AFL_HAVE_VECTOR_INTRINSICS
@ -607,11 +730,19 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
if (ngram_size) {
PrevLoc = IRB.CreateLoad(PrevLocTy, AFLPrevLoc);
PrevLoc = IRB.CreateLoad(
#if LLVM_VERSION_MAJOR >= 14
PrevLocTy,
#endif
AFLPrevLoc);
} else {
PrevLoc = IRB.CreateLoad(IRB.getInt32Ty(), AFLPrevLoc);
PrevLoc = IRB.CreateLoad(
#if LLVM_VERSION_MAJOR >= 14
IRB.getInt32Ty(),
#endif
AFLPrevLoc);
}
@ -638,7 +769,11 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
/* Load SHM pointer */
LoadInst *MapPtr = IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr);
LoadInst *MapPtr = IRB.CreateLoad(
#if LLVM_VERSION_MAJOR >= 14
PointerType::get(Int8Ty, 0),
#endif
AFLMapPtr);
MapPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
Value *MapPtrIdx;
@ -651,15 +786,20 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
Int32Ty));
else
#endif
MapPtrIdx =
IRB.CreateGEP(Int8Ty, MapPtr, IRB.CreateXor(PrevLocTrans, CurLoc));
MapPtrIdx = IRB.CreateGEP(
#if LLVM_VERSION_MAJOR >= 14
Int8Ty,
#endif
MapPtr, IRB.CreateXor(PrevLocTrans, CurLoc));
/* Update bitmap */
if (use_threadsafe_counters) { /* Atomic */
IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One,
#if LLVM_VERSION_MAJOR >= 13
llvm::MaybeAlign(1),
#endif
llvm::AtomicOrdering::Monotonic);
/*
@ -669,13 +809,22 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
} else {
LoadInst *Counter = IRB.CreateLoad(IRB.getInt8Ty(), MapPtrIdx);
LoadInst *Counter = IRB.CreateLoad(
#if LLVM_VERSION_MAJOR >= 14
IRB.getInt8Ty(),
#endif
MapPtrIdx);
Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
Value *Incr = IRB.CreateAdd(Counter, One);
#if LLVM_VERSION_MAJOR >= 9
if (!skip_nozero) {
#else
if (neverZero_counters_str != NULL) {
#endif
/* hexcoder: Realize a counter that skips zero during overflow.
* Once this counter reaches its maximum value, it next increments to
* 1
@ -754,6 +903,124 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
}
#if 0
if (use_threadsafe_counters) { /*Atomic NeverZero */
// handle the list of registered blocks to instrument
for (auto val : todo) {
/* hexcoder: Realize a thread-safe counter that skips zero during
* overflow. Once this counter reaches its maximum value, it next
* increments to 1
*
* Instead of
* Counter + 1 -> Counter
* we inject now this
* Counter + 1 -> {Counter, OverflowFlag}
* Counter + OverflowFlag -> Counter
*/
/* equivalent c code looks like this
* Thanks to
https://preshing.com/20150402/you-can-do-any-kind-of-atomic-read-modify-write-operation/
int old = atomic_load_explicit(&Counter, memory_order_relaxed);
int new;
do {
if (old == 255) {
new = 1;
} else {
new = old + 1;
}
} while (!atomic_compare_exchange_weak_explicit(&Counter, &old, new,
memory_order_relaxed, memory_order_relaxed));
*/
Value * MapPtrIdx = val;
Instruction * MapPtrIdxInst = cast<Instruction>(val);
BasicBlock::iterator it0(&(*MapPtrIdxInst));
++it0;
IRBuilder<> IRB(&(*it0));
// load the old counter value atomically
LoadInst *Counter = IRB.CreateLoad(
#if LLVM_VERSION_MAJOR >= 14
IRB.getInt8Ty(),
#endif
MapPtrIdx);
Counter->setAlignment(llvm::Align());
Counter->setAtomic(llvm::AtomicOrdering::Monotonic);
Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
BasicBlock *BB = IRB.GetInsertBlock();
// insert a basic block with the corpus of a do while loop
// the calculation may need to repeat, if atomic compare_exchange is not
// successful
BasicBlock::iterator it(*Counter);
it++; // split after load counter
BasicBlock *end_bb = BB->splitBasicBlock(it);
end_bb->setName("injected");
// insert the block before the second half of the split
BasicBlock *do_while_bb =
BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb);
// set terminator of BB from target end_bb to target do_while_bb
auto term = BB->getTerminator();
BranchInst::Create(do_while_bb, BB);
term->eraseFromParent();
// continue to fill instructions into the do_while loop
IRB.SetInsertPoint(do_while_bb, do_while_bb->getFirstInsertionPt());
PHINode *PN = IRB.CreatePHI(Int8Ty, 2);
// compare with maximum value 0xff
auto *Cmp = IRB.CreateICmpEQ(Counter, ConstantInt::get(Int8Ty, -1));
// increment the counter
Value *Incr = IRB.CreateAdd(Counter, One);
// select the counter value or 1
auto *Select = IRB.CreateSelect(Cmp, One, Incr);
// try to save back the new counter value
auto *CmpXchg = IRB.CreateAtomicCmpXchg(
MapPtrIdx, PN, Select, llvm::AtomicOrdering::Monotonic,
llvm::AtomicOrdering::Monotonic);
CmpXchg->setAlignment(llvm::Align());
CmpXchg->setWeak(true);
CmpXchg->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
// get the result of trying to update the Counter
Value *Success =
IRB.CreateExtractValue(CmpXchg, ArrayRef<unsigned>({1}));
// get the (possibly updated) value of Counter
Value *OldVal =
IRB.CreateExtractValue(CmpXchg, ArrayRef<unsigned>({0}));
// initially we use Counter
PN->addIncoming(Counter, BB);
// on retry, we use the updated value
PN->addIncoming(OldVal, do_while_bb);
// if the cmpXchg was not successful, retry
IRB.CreateCondBr(Success, end_bb, do_while_bb);
}
}
#endif
}
/*
@ -828,6 +1095,26 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
}
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
return PreservedAnalyses();
#else
return true;
#endif
}
#if LLVM_VERSION_MAJOR < 11 /* use old pass manager */
static void registerAFLPass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) {
PM.add(new AFLCoverage());
}
static RegisterStandardPasses RegisterAFLPass(
PassManagerBuilder::EP_OptimizerLast, registerAFLPass);
static RegisterStandardPasses RegisterAFLPass0(
PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLPass);
#endif

View File

@ -31,17 +31,31 @@
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/IR/PassManager.h"
#if LLVM_MAJOR >= 11
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/IR/PassManager.h"
#else
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#endif
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Pass.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Passes/OptimizationLevel.h"
#if LLVM_VERSION_MAJOR >= 14 /* how about stable interfaces? */
#include "llvm/Passes/OptimizationLevel.h"
#endif
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/Support/raw_ostream.h"
#if LLVM_VERSION_MAJOR >= 4 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/Support/raw_ostream.h"
#else
#include "llvm/Analysis/Verifier.h"
#include "llvm/DebugInfo.h"
#define nullptr 0
#endif
#include <set>
#include "afl-llvm-common.h"
@ -50,8 +64,7 @@ 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> {
public:
@ -61,15 +74,45 @@ class CmpLogInstructions : public PassInfoMixin<CmpLogInstructions> {
}
#else
class CmpLogInstructions : public ModulePass {
public:
static char ID;
CmpLogInstructions() : ModulePass(ID) {
initInstrumentList();
}
#endif
#if LLVM_MAJOR >= 11 /* use new pass manager */
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
#else
bool runOnModule(Module &M) override;
#if LLVM_VERSION_MAJOR >= 4
StringRef getPassName() const override {
#else
const char *getPassName() const override {
#endif
return "cmplog instructions";
}
#endif
private:
bool hookInstrs(Module &M, DomTreeCallback DTCallback);
bool hookInstrs(Module &M);
};
} // namespace
#if LLVM_MAJOR >= 11
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
llvmGetPassPluginInfo() {
@ -77,15 +120,15 @@ llvmGetPassPluginInfo() {
/* lambda to insert our pass into the pass pipeline. */
[](PassBuilder &PB) {
#if LLVM_VERSION_MAJOR <= 13
#if LLVM_VERSION_MAJOR <= 13
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
#endif
#endif
PB.registerOptimizerLastEPCallback([](ModulePassManager &MPM,
OptimizationLevel OL
#if LLVM_VERSION_MAJOR >= 20
#if LLVM_VERSION_MAJOR >= 20
,
ThinOrFullLTOPhase Phase
#endif
#endif
) {
MPM.addPass(CmpLogInstructions());
@ -96,6 +139,10 @@ llvmGetPassPluginInfo() {
}
#else
char CmpLogInstructions::ID = 0;
#endif
template <class Iterator>
Iterator Unique(Iterator first, Iterator last) {
@ -111,16 +158,7 @@ Iterator Unique(Iterator first, Iterator last) {
}
bool IsBackEdge(BasicBlock *From, BasicBlock *To, const DominatorTree *DT) {
if (DT->dominates(To, From)) return true;
if (auto Next = To->getUniqueSuccessor())
if (DT->dominates(Next, From)) return true;
return false;
}
bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
bool CmpLogInstructions::hookInstrs(Module &M) {
std::vector<Instruction *> icomps;
LLVMContext &C = M.getContext();
@ -152,25 +190,95 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
#endif
*/
FunctionCallee c2 = M.getOrInsertFunction("__cmplog_ins_hook2", VoidTy,
Int16Ty, Int16Ty, Int8Ty);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c2 = M.getOrInsertFunction("__cmplog_ins_hook2", VoidTy, Int16Ty, Int16Ty,
Int8Ty
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee cmplogHookIns2 = c2;
#else
Function *cmplogHookIns2 = cast<Function>(c2);
#endif
FunctionCallee c4 = M.getOrInsertFunction("__cmplog_ins_hook4", VoidTy,
Int32Ty, Int32Ty, Int8Ty);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c4 = M.getOrInsertFunction("__cmplog_ins_hook4", VoidTy, Int32Ty, Int32Ty,
Int8Ty
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee cmplogHookIns4 = c4;
#else
Function *cmplogHookIns4 = cast<Function>(c4);
#endif
FunctionCallee c8 = M.getOrInsertFunction("__cmplog_ins_hook8", VoidTy,
Int64Ty, Int64Ty, Int8Ty);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c8 = M.getOrInsertFunction("__cmplog_ins_hook8", VoidTy, Int64Ty, Int64Ty,
Int8Ty
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee cmplogHookIns8 = c8;
#else
Function *cmplogHookIns8 = cast<Function>(c8);
#endif
FunctionCallee c16 = M.getOrInsertFunction("__cmplog_ins_hook16", VoidTy,
Int128Ty, Int128Ty, Int8Ty);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c16 = M.getOrInsertFunction("__cmplog_ins_hook16", VoidTy, Int128Ty,
Int128Ty, Int8Ty
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR < 9
Function *cmplogHookIns16 = cast<Function>(c16);
#else
FunctionCallee cmplogHookIns16 = c16;
#endif
FunctionCallee cN = M.getOrInsertFunction("__cmplog_ins_hookN", VoidTy,
Int128Ty, Int128Ty, Int8Ty, Int8Ty);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
cN = M.getOrInsertFunction("__cmplog_ins_hookN", VoidTy, Int128Ty,
Int128Ty, Int8Ty, Int8Ty
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee cmplogHookInsN = cN;
#else
Function *cmplogHookInsN = cast<Function>(cN);
#endif
GlobalVariable *AFLCmplogPtr = M.getNamedGlobal("__afl_cmp_map");
@ -188,7 +296,6 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
for (auto &F : M) {
if (!isInInstrumentList(&F, MNAME)) continue;
const DominatorTree *DT = DTCallback(F);
for (auto &BB : F) {
@ -197,12 +304,6 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
CmpInst *selectcmpInst = nullptr;
if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) {
// skip loop comparisons
if (selectcmpInst->hasOneUse())
if (auto BR = dyn_cast<BranchInst>(selectcmpInst->user_back()))
for (BasicBlock *B : BR->successors())
if (IsBackEdge(BR->getParent(), B, DT)) continue;
icomps.push_back(selectcmpInst);
}
@ -222,8 +323,11 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
IRBuilder<> IRB2(selectcmpInst->getParent());
IRB2.SetInsertPoint(selectcmpInst);
LoadInst *CmpPtr =
IRB2.CreateLoad(PointerType::get(Int8Ty, 0), AFLCmplogPtr);
LoadInst *CmpPtr = IRB2.CreateLoad(
#if LLVM_VERSION_MAJOR >= 14
PointerType::get(Int8Ty, 0),
#endif
AFLCmplogPtr);
CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
auto ThenTerm =
@ -297,12 +401,18 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
}
#if (LLVM_VERSION_MAJOR >= 12)
vector_cnt = tt->getElementCount().getKnownMinValue();
ty0 = tt->getElementType();
#endif
}
if (ty0->isHalfTy() || ty0->isBFloatTy())
if (ty0->isHalfTy()
#if LLVM_VERSION_MAJOR >= 11
|| ty0->isBFloatTy()
#endif
)
max_size = 16;
else if (ty0->isFloatTy())
max_size = 32;
@ -312,9 +422,11 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
max_size = 80;
else if (ty0->isFP128Ty() || ty0->isPPC_FP128Ty())
max_size = 128;
#if (LLVM_VERSION_MAJOR >= 12)
else if (ty0->getTypeID() != llvm::Type::PointerTyID && !be_quiet)
fprintf(stderr, "Warning: unsupported cmp type for cmplog: %u!\n",
ty0->getTypeID());
#endif
attr += 8;
is_fp = 1;
@ -324,6 +436,7 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
if (ty0->isVectorTy()) {
#if (LLVM_VERSION_MAJOR >= 12)
VectorType *tt = dyn_cast<VectorType>(ty0);
if (!tt) {
@ -334,6 +447,7 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
vector_cnt = tt->getElementCount().getKnownMinValue();
ty1 = ty0 = tt->getElementType();
#endif
}
@ -348,6 +462,7 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
} else {
#if (LLVM_VERSION_MAJOR >= 12)
if (ty0->getTypeID() != llvm::Type::PointerTyID && !be_quiet) {
fprintf(stderr, "Warning: unsupported cmp type for cmplog: %u\n",
@ -355,6 +470,8 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
}
#endif
}
}
@ -555,27 +672,52 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
}
#if LLVM_MAJOR >= 11 /* use new pass manager */
PreservedAnalyses CmpLogInstructions::run(Module &M,
ModuleAnalysisManager &MAM) {
auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
auto DTCallback = [&FAM](Function &F) -> const DominatorTree *{
#else
bool CmpLogInstructions::runOnModule(Module &M) {
return &FAM.getResult<DominatorTreeAnalysis>(F);
};
#endif
if (getenv("AFL_QUIET") == NULL)
printf("Running cmplog-instructions-pass by andreafioraldi@gmail.com\n");
else
be_quiet = 1;
bool ret = hookInstrs(M, DTCallback);
bool ret = hookInstrs(M);
verifyModule(M);
#if LLVM_MAJOR >= 11 /* use new pass manager */
if (ret == false)
return PreservedAnalyses::all();
else
return PreservedAnalyses();
#else
return ret;
#endif
}
#if LLVM_MAJOR < 11 /* use old pass manager */
static void registerCmpLogInstructionsPass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) {
auto p = new CmpLogInstructions();
PM.add(p);
}
static RegisterStandardPasses RegisterCmpLogInstructionsPass(
PassManagerBuilder::EP_OptimizerLast, registerCmpLogInstructionsPass);
static RegisterStandardPasses RegisterCmpLogInstructionsPass0(
PassManagerBuilder::EP_EnabledOnOptLevel0, registerCmpLogInstructionsPass);
#if LLVM_VERSION_MAJOR >= 11
static RegisterStandardPasses RegisterCmpLogInstructionsPassLTO(
PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
registerCmpLogInstructionsPass);
#endif
#endif

View File

@ -27,9 +27,14 @@
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/IR/PassManager.h"
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/IR/PassManager.h"
#else
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#endif
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@ -41,8 +46,15 @@
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#if LLVM_VERSION_MAJOR >= 4 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#else
#include "llvm/Analysis/Verifier.h"
#include "llvm/DebugInfo.h"
#define nullptr 0
#endif
#include <set>
#include "afl-llvm-common.h"
@ -51,16 +63,42 @@ using namespace llvm;
namespace {
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
class CmpLogRoutines : public PassInfoMixin<CmpLogRoutines> {
public:
CmpLogRoutines() {
#else
class CmpLogRoutines : public ModulePass {
public:
static char ID;
CmpLogRoutines() : ModulePass(ID) {
#endif
initInstrumentList();
}
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
#else
bool runOnModule(Module &M) override;
#if LLVM_VERSION_MAJOR >= 4
StringRef getPassName() const override {
#else
const char *getPassName() const override {
#endif
return "cmplog routines";
}
#endif
private:
bool hookRtns(Module &M);
@ -69,6 +107,7 @@ class CmpLogRoutines : public PassInfoMixin<CmpLogRoutines> {
} // namespace
#if LLVM_MAJOR >= 11
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
llvmGetPassPluginInfo() {
@ -76,15 +115,15 @@ llvmGetPassPluginInfo() {
/* lambda to insert our pass into the pass pipeline. */
[](PassBuilder &PB) {
#if LLVM_VERSION_MAJOR <= 13
#if LLVM_VERSION_MAJOR <= 13
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
#endif
#endif
PB.registerOptimizerLastEPCallback([](ModulePassManager &MPM,
OptimizationLevel OL
#if LLVM_VERSION_MAJOR >= 20
#if LLVM_VERSION_MAJOR >= 20
,
ThinOrFullLTOPhase Phase
#endif
#endif
) {
MPM.addPass(CmpLogRoutines());
@ -95,6 +134,10 @@ llvmGetPassPluginInfo() {
}
#else
char CmpLogRoutines::ID = 0;
#endif
bool CmpLogRoutines::hookRtns(Module &M) {
std::vector<CallInst *> calls, llvmStdStd, llvmStdC, gccStdStd, gccStdC,
@ -107,37 +150,148 @@ bool CmpLogRoutines::hookRtns(Module &M) {
IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
PointerType *i8PtrTy = PointerType::get(Int8Ty, 0);
FunctionCallee c =
M.getOrInsertFunction("__cmplog_rtn_hook", VoidTy, i8PtrTy, i8PtrTy);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c = M.getOrInsertFunction("__cmplog_rtn_hook", VoidTy, i8PtrTy, i8PtrTy
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee cmplogHookFn = c;
#else
Function *cmplogHookFn = cast<Function>(c);
#endif
FunctionCallee c1 = M.getOrInsertFunction(
"__cmplog_rtn_llvm_stdstring_stdstring", VoidTy, i8PtrTy, i8PtrTy);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c1 = M.getOrInsertFunction("__cmplog_rtn_llvm_stdstring_stdstring",
VoidTy, i8PtrTy, i8PtrTy
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee cmplogLlvmStdStd = c1;
#else
Function *cmplogLlvmStdStd = cast<Function>(c1);
#endif
FunctionCallee c2 = M.getOrInsertFunction(
"__cmplog_rtn_llvm_stdstring_cstring", VoidTy, i8PtrTy, i8PtrTy);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c2 = M.getOrInsertFunction("__cmplog_rtn_llvm_stdstring_cstring", VoidTy,
i8PtrTy, i8PtrTy
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee cmplogLlvmStdC = c2;
#else
Function *cmplogLlvmStdC = cast<Function>(c2);
#endif
FunctionCallee c3 = M.getOrInsertFunction(
"__cmplog_rtn_gcc_stdstring_stdstring", VoidTy, i8PtrTy, i8PtrTy);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c3 = M.getOrInsertFunction("__cmplog_rtn_gcc_stdstring_stdstring", VoidTy,
i8PtrTy, i8PtrTy
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee cmplogGccStdStd = c3;
#else
Function *cmplogGccStdStd = cast<Function>(c3);
#endif
FunctionCallee c4 = M.getOrInsertFunction(
"__cmplog_rtn_gcc_stdstring_cstring", VoidTy, i8PtrTy, i8PtrTy);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c4 = M.getOrInsertFunction("__cmplog_rtn_gcc_stdstring_cstring", VoidTy,
i8PtrTy, i8PtrTy
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee cmplogGccStdC = c4;
#else
Function *cmplogGccStdC = cast<Function>(c4);
#endif
FunctionCallee c5 = M.getOrInsertFunction("__cmplog_rtn_hook_n", VoidTy,
i8PtrTy, i8PtrTy, Int64Ty);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c5 = M.getOrInsertFunction("__cmplog_rtn_hook_n", VoidTy, i8PtrTy,
i8PtrTy, Int64Ty
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee cmplogHookFnN = c5;
#else
Function *cmplogHookFnN = cast<Function>(c5);
#endif
FunctionCallee c6 = M.getOrInsertFunction("__cmplog_rtn_hook_strn", VoidTy,
i8PtrTy, i8PtrTy, Int64Ty);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c6 = M.getOrInsertFunction("__cmplog_rtn_hook_strn", VoidTy, i8PtrTy,
i8PtrTy, Int64Ty
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee cmplogHookFnStrN = c6;
#else
Function *cmplogHookFnStrN = cast<Function>(c6);
#endif
FunctionCallee c7 =
M.getOrInsertFunction("__cmplog_rtn_hook_str", VoidTy, i8PtrTy, i8PtrTy);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c7 = M.getOrInsertFunction("__cmplog_rtn_hook_str", VoidTy, i8PtrTy,
i8PtrTy
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee cmplogHookFnStr = c7;
#else
Function *cmplogHookFnStr = cast<Function>(c7);
#endif
GlobalVariable *AFLCmplogPtr = M.getNamedGlobal("__afl_cmp_map");
@ -332,7 +486,7 @@ bool CmpLogRoutines::hookRtns(Module &M) {
if (!calls.size() && !gccStdStd.size() && !gccStdC.size() &&
!llvmStdStd.size() && !llvmStdC.size() && !Memcmp.size() &&
!Strcmp.size() && !Strncmp.size())
Strcmp.size() && Strncmp.size())
return false;
/*
@ -348,8 +502,11 @@ bool CmpLogRoutines::hookRtns(Module &M) {
IRBuilder<> IRB2(callInst->getParent());
IRB2.SetInsertPoint(callInst);
LoadInst *CmpPtr =
IRB2.CreateLoad(PointerType::get(Int8Ty, 0), AFLCmplogPtr);
LoadInst *CmpPtr = IRB2.CreateLoad(
#if LLVM_VERSION_MAJOR >= 14
PointerType::get(Int8Ty, 0),
#endif
AFLCmplogPtr);
CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
@ -376,8 +533,11 @@ bool CmpLogRoutines::hookRtns(Module &M) {
IRBuilder<> IRB2(callInst->getParent());
IRB2.SetInsertPoint(callInst);
LoadInst *CmpPtr =
IRB2.CreateLoad(PointerType::get(Int8Ty, 0), AFLCmplogPtr);
LoadInst *CmpPtr = IRB2.CreateLoad(
#if LLVM_VERSION_MAJOR >= 14
PointerType::get(Int8Ty, 0),
#endif
AFLCmplogPtr);
CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
@ -408,8 +568,11 @@ bool CmpLogRoutines::hookRtns(Module &M) {
IRBuilder<> IRB2(callInst->getParent());
IRB2.SetInsertPoint(callInst);
LoadInst *CmpPtr =
IRB2.CreateLoad(PointerType::get(Int8Ty, 0), AFLCmplogPtr);
LoadInst *CmpPtr = IRB2.CreateLoad(
#if LLVM_VERSION_MAJOR >= 14
PointerType::get(Int8Ty, 0),
#endif
AFLCmplogPtr);
CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
@ -436,8 +599,11 @@ bool CmpLogRoutines::hookRtns(Module &M) {
IRBuilder<> IRB2(callInst->getParent());
IRB2.SetInsertPoint(callInst);
LoadInst *CmpPtr =
IRB2.CreateLoad(PointerType::get(Int8Ty, 0), AFLCmplogPtr);
LoadInst *CmpPtr = IRB2.CreateLoad(
#if LLVM_VERSION_MAJOR >= 14
PointerType::get(Int8Ty, 0),
#endif
AFLCmplogPtr);
CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
@ -468,8 +634,11 @@ bool CmpLogRoutines::hookRtns(Module &M) {
IRBuilder<> IRB2(callInst->getParent());
IRB2.SetInsertPoint(callInst);
LoadInst *CmpPtr =
IRB2.CreateLoad(PointerType::get(Int8Ty, 0), AFLCmplogPtr);
LoadInst *CmpPtr = IRB2.CreateLoad(
#if LLVM_VERSION_MAJOR >= 14
PointerType::get(Int8Ty, 0),
#endif
AFLCmplogPtr);
CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
@ -495,8 +664,11 @@ bool CmpLogRoutines::hookRtns(Module &M) {
IRBuilder<> IRB2(callInst->getParent());
IRB2.SetInsertPoint(callInst);
LoadInst *CmpPtr =
IRB2.CreateLoad(PointerType::get(Int8Ty, 0), AFLCmplogPtr);
LoadInst *CmpPtr = IRB2.CreateLoad(
#if LLVM_VERSION_MAJOR >= 14
PointerType::get(Int8Ty, 0),
#endif
AFLCmplogPtr);
CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
@ -522,8 +694,11 @@ bool CmpLogRoutines::hookRtns(Module &M) {
IRBuilder<> IRB2(callInst->getParent());
IRB2.SetInsertPoint(callInst);
LoadInst *CmpPtr =
IRB2.CreateLoad(PointerType::get(Int8Ty, 0), AFLCmplogPtr);
LoadInst *CmpPtr = IRB2.CreateLoad(
#if LLVM_VERSION_MAJOR >= 14
PointerType::get(Int8Ty, 0),
#endif
AFLCmplogPtr);
CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
@ -549,8 +724,11 @@ bool CmpLogRoutines::hookRtns(Module &M) {
IRBuilder<> IRB2(callInst->getParent());
IRB2.SetInsertPoint(callInst);
LoadInst *CmpPtr =
IRB2.CreateLoad(PointerType::get(Int8Ty, 0), AFLCmplogPtr);
LoadInst *CmpPtr = IRB2.CreateLoad(
#if LLVM_VERSION_MAJOR >= 14
PointerType::get(Int8Ty, 0),
#endif
AFLCmplogPtr);
CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
@ -573,8 +751,14 @@ bool CmpLogRoutines::hookRtns(Module &M) {
}
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
PreservedAnalyses CmpLogRoutines::run(Module &M, ModuleAnalysisManager &MAM) {
#else
bool CmpLogRoutines::runOnModule(Module &M) {
#endif
if (getenv("AFL_QUIET") == NULL)
printf("Running cmplog-routines-pass by andreafioraldi@gmail.com\n");
else
@ -582,10 +766,36 @@ PreservedAnalyses CmpLogRoutines::run(Module &M, ModuleAnalysisManager &MAM) {
bool ret = hookRtns(M);
verifyModule(M);
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
if (ret == false)
return PreservedAnalyses::all();
else
return PreservedAnalyses();
#else
return ret;
#endif
}
#if LLVM_VERSION_MAJOR < 11 /* use old pass manager */
static void registerCmpLogRoutinesPass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) {
auto p = new CmpLogRoutines();
PM.add(p);
}
static RegisterStandardPasses RegisterCmpLogRoutinesPass(
PassManagerBuilder::EP_OptimizerLast, registerCmpLogRoutinesPass);
static RegisterStandardPasses RegisterCmpLogRoutinesPass0(
PassManagerBuilder::EP_EnabledOnOptLevel0, registerCmpLogRoutinesPass);
#if LLVM_VERSION_MAJOR >= 11
static RegisterStandardPasses RegisterCmpLogRoutinesPassLTO(
PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
registerCmpLogRoutinesPass);
#endif
#endif

View File

@ -28,9 +28,14 @@
#include "llvm/Config/llvm-config.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/IR/PassManager.h"
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/IR/PassManager.h"
#else
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#endif
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@ -42,8 +47,15 @@
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#if LLVM_VERSION_MAJOR >= 4 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#else
#include "llvm/Analysis/Verifier.h"
#include "llvm/DebugInfo.h"
#define nullptr 0
#endif
#include <set>
#include "afl-llvm-common.h"
@ -52,16 +64,41 @@ using namespace llvm;
namespace {
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
class CmplogSwitches : public PassInfoMixin<CmplogSwitches> {
public:
CmplogSwitches() {
#else
class CmplogSwitches : public ModulePass {
public:
static char ID;
CmplogSwitches() : ModulePass(ID) {
#endif
initInstrumentList();
}
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
#else
bool runOnModule(Module &M) override;
#if LLVM_VERSION_MAJOR < 4
const char *getPassName() const override {
#else
StringRef getPassName() const override {
#endif
return "cmplog switch split";
}
#endif
private:
bool hookInstrs(Module &M);
@ -70,6 +107,7 @@ class CmplogSwitches : public PassInfoMixin<CmplogSwitches> {
} // namespace
#if LLVM_MAJOR >= 11
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
llvmGetPassPluginInfo() {
@ -77,15 +115,15 @@ llvmGetPassPluginInfo() {
/* lambda to insert our pass into the pass pipeline. */
[](PassBuilder &PB) {
#if LLVM_VERSION_MAJOR <= 13
#if LLVM_VERSION_MAJOR <= 13
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
#endif
#endif
PB.registerOptimizerLastEPCallback([](ModulePassManager &MPM,
OptimizationLevel OL
#if LLVM_VERSION_MAJOR >= 20
#if LLVM_VERSION_MAJOR >= 20
,
ThinOrFullLTOPhase Phase
#endif
#endif
) {
MPM.addPass(CmplogSwitches());
@ -96,6 +134,10 @@ llvmGetPassPluginInfo() {
}
#else
char CmplogSwitches::ID = 0;
#endif
template <class Iterator>
Iterator Unique(Iterator first, Iterator last) {
@ -122,21 +164,77 @@ bool CmplogSwitches::hookInstrs(Module &M) {
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
FunctionCallee c1 = M.getOrInsertFunction("__cmplog_ins_hook1", VoidTy,
Int8Ty, Int8Ty, Int8Ty);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c1 = M.getOrInsertFunction("__cmplog_ins_hook1", VoidTy, Int8Ty, Int8Ty,
Int8Ty
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee cmplogHookIns1 = c1;
#else
Function *cmplogHookIns1 = cast<Function>(c1);
#endif
FunctionCallee c2 = M.getOrInsertFunction("__cmplog_ins_hook2", VoidTy,
Int16Ty, Int16Ty, Int8Ty);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c2 = M.getOrInsertFunction("__cmplog_ins_hook2", VoidTy, Int16Ty, Int16Ty,
Int8Ty
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee cmplogHookIns2 = c2;
#else
Function *cmplogHookIns2 = cast<Function>(c2);
#endif
FunctionCallee c4 = M.getOrInsertFunction("__cmplog_ins_hook4", VoidTy,
Int32Ty, Int32Ty, Int8Ty);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c4 = M.getOrInsertFunction("__cmplog_ins_hook4", VoidTy, Int32Ty, Int32Ty,
Int8Ty
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee cmplogHookIns4 = c4;
#else
Function *cmplogHookIns4 = cast<Function>(c4);
#endif
FunctionCallee c8 = M.getOrInsertFunction("__cmplog_ins_hook8", VoidTy,
Int64Ty, Int64Ty, Int8Ty);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c8 = M.getOrInsertFunction("__cmplog_ins_hook8", VoidTy, Int64Ty, Int64Ty,
Int8Ty
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee cmplogHookIns8 = c8;
#else
Function *cmplogHookIns8 = cast<Function>(c8);
#endif
GlobalVariable *AFLCmplogPtr = M.getNamedGlobal("__afl_cmp_map");
@ -200,8 +298,11 @@ bool CmplogSwitches::hookInstrs(Module &M) {
IRBuilder<> IRB2(SI->getParent());
IRB2.SetInsertPoint(SI);
LoadInst *CmpPtr =
IRB2.CreateLoad(PointerType::get(Int8Ty, 0), AFLCmplogPtr);
LoadInst *CmpPtr = IRB2.CreateLoad(
#if LLVM_VERSION_MAJOR >= 14
PointerType::get(Int8Ty, 0),
#endif
AFLCmplogPtr);
CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, SI, false);
@ -251,7 +352,11 @@ bool CmplogSwitches::hookInstrs(Module &M) {
for (SwitchInst::CaseIt i = SI->case_begin(), e = SI->case_end(); i != e;
++i) {
#if LLVM_VERSION_MAJOR < 5
ConstantInt *cint = i.getCaseValue();
#else
ConstantInt *cint = i->getCaseValue();
#endif
if (cint) {
@ -330,8 +435,14 @@ bool CmplogSwitches::hookInstrs(Module &M) {
}
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
PreservedAnalyses CmplogSwitches::run(Module &M, ModuleAnalysisManager &MAM) {
#else
bool CmplogSwitches::runOnModule(Module &M) {
#endif
if (getenv("AFL_QUIET") == NULL)
printf("Running cmplog-switches-pass by andreafioraldi@gmail.com\n");
else
@ -339,10 +450,36 @@ PreservedAnalyses CmplogSwitches::run(Module &M, ModuleAnalysisManager &MAM) {
bool ret = hookInstrs(M);
verifyModule(M);
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
if (ret == false)
return PreservedAnalyses::all();
else
return PreservedAnalyses();
#else
return ret;
#endif
}
#if LLVM_VERSION_MAJOR < 11 /* use old pass manager */
static void registerCmplogSwitchesPass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) {
auto p = new CmplogSwitches();
PM.add(p);
}
static RegisterStandardPasses RegisterCmplogSwitchesPass(
PassManagerBuilder::EP_OptimizerLast, registerCmplogSwitchesPass);
static RegisterStandardPasses RegisterCmplogSwitchesPass0(
PassManagerBuilder::EP_EnabledOnOptLevel0, registerCmplogSwitchesPass);
#if LLVM_VERSION_MAJOR >= 11
static RegisterStandardPasses RegisterCmplogSwitchesPassLTO(
PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
registerCmplogSwitchesPass);
#endif
#endif

View File

@ -27,9 +27,14 @@
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/IR/PassManager.h"
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/IR/PassManager.h"
#else
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#endif
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@ -41,8 +46,15 @@
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#if LLVM_VERSION_MAJOR >= 4 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#else
#include "llvm/Analysis/Verifier.h"
#include "llvm/DebugInfo.h"
#define nullptr 0
#endif
#include <set>
#include "afl-llvm-common.h"
@ -51,16 +63,42 @@ using namespace llvm;
namespace {
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
class InjectionRoutines : public PassInfoMixin<InjectionRoutines> {
public:
InjectionRoutines() {
#else
class InjectionRoutines : public ModulePass {
public:
static char ID;
InjectionRoutines() : ModulePass(ID) {
#endif
initInstrumentList();
}
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
#else
bool runOnModule(Module &M) override;
#if LLVM_VERSION_MAJOR >= 4
StringRef getPassName() const override {
#else
const char *getPassName() const override {
#endif
return "Injection routines";
}
#endif
private:
bool hookRtns(Module &M);
@ -73,6 +111,7 @@ class InjectionRoutines : public PassInfoMixin<InjectionRoutines> {
} // namespace
#if LLVM_MAJOR >= 11
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
llvmGetPassPluginInfo() {
@ -80,12 +119,15 @@ llvmGetPassPluginInfo() {
/* lambda to insert our pass into the pass pipeline. */
[](PassBuilder &PB) {
#if LLVM_VERSION_MAJOR <= 13
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
#endif
PB.registerOptimizerLastEPCallback([](ModulePassManager &MPM,
OptimizationLevel OL
#if LLVM_VERSION_MAJOR >= 20
#if LLVM_VERSION_MAJOR >= 20
,
ThinOrFullLTOPhase Phase
#endif
#endif
) {
MPM.addPass(InjectionRoutines());
@ -96,6 +138,10 @@ llvmGetPassPluginInfo() {
}
#else
char InjectionRoutines::ID = 0;
#endif
bool InjectionRoutines::hookRtns(Module &M) {
std::vector<CallInst *> calls, llvmStdStd, llvmStdC, gccStdStd, gccStdC,
@ -106,19 +152,62 @@ bool InjectionRoutines::hookRtns(Module &M) {
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
PointerType *i8PtrTy = PointerType::get(Int8Ty, 0);
FunctionCallee c1 =
M.getOrInsertFunction("__afl_injection_sql", VoidTy, i8PtrTy);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c1 = M.getOrInsertFunction("__afl_injection_sql", VoidTy, i8PtrTy
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee sqlfunc = c1;
#else
Function *sqlfunc = cast<Function>(c1);
#endif
FunctionCallee c2 =
M.getOrInsertFunction("__afl_injection_ldap", VoidTy, i8PtrTy);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c2 = M.getOrInsertFunction("__afl_injection_ldap", VoidTy, i8PtrTy
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee ldapfunc = c2;
#else
Function *ldapfunc = cast<Function>(c2);
#endif
FunctionCallee c3 =
M.getOrInsertFunction("__afl_injection_xss", VoidTy, i8PtrTy);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c3 = M.getOrInsertFunction("__afl_injection_xss", VoidTy, i8PtrTy
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee xssfunc = c3;
#else
Function *xssfunc = cast<Function>(c3);
#endif
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee FuncPtr;
#else
Function *FuncPtr;
#endif
bool ret = false;
@ -222,9 +311,15 @@ bool InjectionRoutines::hookRtns(Module &M) {
}
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
PreservedAnalyses InjectionRoutines::run(Module &M,
ModuleAnalysisManager &MAM) {
#else
bool InjectionRoutines::runOnModule(Module &M) {
#endif
if (getenv("AFL_QUIET") == NULL)
printf("Running injection-pass by Marc Heuse (mh@mh-sec.de)\n");
else
@ -244,9 +339,36 @@ PreservedAnalyses InjectionRoutines::run(Module &M,
bool ret = hookRtns(M);
verifyModule(M);
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
if (ret == false)
return PreservedAnalyses::all();
else
return PreservedAnalyses();
#else
return ret;
#endif
}
#if LLVM_VERSION_MAJOR < 11 /* use old pass manager */
static void registerInjectionRoutinesPass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) {
auto p = new InjectionRoutines();
PM.add(p);
}
static RegisterStandardPasses RegisterInjectionRoutinesPass(
PassManagerBuilder::EP_OptimizerLast, registerInjectionRoutinesPass);
static RegisterStandardPasses RegisterInjectionRoutinesPass0(
PassManagerBuilder::EP_EnabledOnOptLevel0, registerInjectionRoutinesPass);
#if LLVM_VERSION_MAJOR >= 11
static RegisterStandardPasses RegisterInjectionRoutinesPassLTO(
PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
registerInjectionRoutinesPass);
#endif
#endif

View File

@ -30,16 +30,30 @@
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/IR/PassManager.h"
#if LLVM_MAJOR >= 11
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/IR/PassManager.h"
#else
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#endif
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/IR/Module.h"
#include "llvm/Passes/OptimizationLevel.h"
#if LLVM_VERSION_MAJOR >= 14 /* how about stable interfaces? */
#include "llvm/Passes/OptimizationLevel.h"
#endif
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#if LLVM_VERSION_MAJOR >= 4 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#else
#include "llvm/Analysis/Verifier.h"
#include "llvm/DebugInfo.h"
#define nullptr 0
#endif
using namespace llvm;
#include "afl-llvm-common.h"
@ -50,17 +64,31 @@ using namespace llvm;
namespace {
#if LLVM_MAJOR >= 11
class SplitComparesTransform : public PassInfoMixin<SplitComparesTransform> {
public:
// static char ID;
SplitComparesTransform() : enableFPSplit(0) {
#else
class SplitComparesTransform : public ModulePass {
public:
static char ID;
SplitComparesTransform() : ModulePass(ID), enableFPSplit(0) {
#endif
initInstrumentList();
}
#if LLVM_MAJOR >= 11
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
#else
bool runOnModule(Module &M) override;
#endif
private:
int enableFPSplit;
@ -149,6 +177,7 @@ class SplitComparesTransform : public PassInfoMixin<SplitComparesTransform> {
} // namespace
#if LLVM_MAJOR >= 11
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
llvmGetPassPluginInfo() {
@ -156,26 +185,56 @@ llvmGetPassPluginInfo() {
/* lambda to insert our pass into the pass pipeline. */
[](PassBuilder &PB) {
#if LLVM_VERSION_MAJOR >= 16
#if 1
#if LLVM_VERSION_MAJOR <= 13
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
#endif
#if LLVM_VERSION_MAJOR >= 16
PB.registerOptimizerEarlyEPCallback(
#else
#else
PB.registerOptimizerLastEPCallback(
#endif
#endif
[](ModulePassManager &MPM, OptimizationLevel OL
#if LLVM_VERSION_MAJOR >= 20
#if LLVM_VERSION_MAJOR >= 20
,
ThinOrFullLTOPhase Phase
#endif
#endif
) {
MPM.addPass(SplitComparesTransform());
});
/* TODO LTO registration */
#else
using PipelineElement = typename PassBuilder::PipelineElement;
PB.registerPipelineParsingCallback([](StringRef Name,
ModulePassManager &MPM,
ArrayRef<PipelineElement>) {
if (Name == "splitcompares") {
MPM.addPass(SplitComparesTransform());
return true;
} else {
return false;
}
});
#endif
}};
}
#else
char SplitComparesTransform::ID = 0;
#endif
/// This function splits FCMP instructions with xGE or xLE predicates into two
/// FCMP instructions with predicate xGT or xLT and EQ
bool SplitComparesTransform::simplifyFPCompares(Module &M) {
@ -892,6 +951,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
LLVMContext &C = M.getContext();
#if LLVM_VERSION_MAJOR >= 4 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 7)
const DataLayout &dl = M.getDataLayout();
/* define unions with floating point and (sign, exponent, mantissa) triples
@ -906,6 +967,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
}
#endif
std::vector<CmpInst *> fcomps;
/* get all EQ, NE, GT, and LT fcmps. if the other two
@ -1647,9 +1710,15 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
}
#if LLVM_MAJOR >= 11
PreservedAnalyses SplitComparesTransform::run(Module &M,
ModuleAnalysisManager &MAM) {
#else
bool SplitComparesTransform::runOnModule(Module &M) {
#endif
if ((isatty(2) && getenv("AFL_QUIET") == NULL) ||
getenv("AFL_DEBUG") != NULL) {
@ -1754,8 +1823,12 @@ PreservedAnalyses SplitComparesTransform::run(Module &M,
bool ret = count == 0 ? false : true;
bool brokenDebug = false;
if (verifyModule(M, &errs(),
if (verifyModule(M, &errs()
#if LLVM_VERSION_MAJOR >= 4 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 9)
,
&brokenDebug // 9th May 2016
#endif
)) {
reportError(
@ -1780,6 +1853,7 @@ PreservedAnalyses SplitComparesTransform::run(Module &M,
}
#if LLVM_MAJOR >= 11
/* if (modified) {
PA.abandon<XX_Manager>();
@ -1790,5 +1864,36 @@ PreservedAnalyses SplitComparesTransform::run(Module &M,
return PreservedAnalyses::all();
else
return PreservedAnalyses();
#else
return ret;
#endif
}
#if LLVM_MAJOR < 11 /* use old pass manager */
static void registerSplitComparesPass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) {
PM.add(new SplitComparesTransform());
}
static RegisterStandardPasses RegisterSplitComparesPass(
PassManagerBuilder::EP_OptimizerLast, registerSplitComparesPass);
static RegisterStandardPasses RegisterSplitComparesTransPass0(
PassManagerBuilder::EP_EnabledOnOptLevel0, registerSplitComparesPass);
#if LLVM_VERSION_MAJOR >= 11
static RegisterStandardPasses RegisterSplitComparesTransPassLTO(
PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
registerSplitComparesPass);
#endif
static RegisterPass<SplitComparesTransform> X("splitcompares",
"AFL++ split compares",
true /* Only looks at CFG */,
true /* Analysis Pass */);
#endif

View File

@ -27,20 +27,34 @@
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/IR/PassManager.h"
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/IR/PassManager.h"
#else
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#endif
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Pass.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Passes/OptimizationLevel.h"
#if LLVM_VERSION_MAJOR >= 14 /* how about stable interfaces? */
#include "llvm/Passes/OptimizationLevel.h"
#endif
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#if LLVM_VERSION_MAJOR >= 4 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#else
#include "llvm/Analysis/Verifier.h"
#include "llvm/DebugInfo.h"
#define nullptr 0
#endif
#include <set>
#include "afl-llvm-common.h"
@ -49,16 +63,42 @@ using namespace llvm;
namespace {
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
class SplitSwitchesTransform : public PassInfoMixin<SplitSwitchesTransform> {
public:
SplitSwitchesTransform() {
#else
class SplitSwitchesTransform : public ModulePass {
public:
static char ID;
SplitSwitchesTransform() : ModulePass(ID) {
#endif
initInstrumentList();
}
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
#else
bool runOnModule(Module &M) override;
#if LLVM_VERSION_MAJOR >= 4
StringRef getPassName() const override {
#else
const char *getPassName() const override {
#endif
return "splits switch constructs";
}
#endif
struct CaseExpr {
ConstantInt *Val;
@ -85,6 +125,7 @@ class SplitSwitchesTransform : public PassInfoMixin<SplitSwitchesTransform> {
} // namespace
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
llvmGetPassPluginInfo() {
@ -92,16 +133,20 @@ llvmGetPassPluginInfo() {
/* lambda to insert our pass into the pass pipeline. */
[](PassBuilder &PB) {
#if LLVM_VERSION_MAJOR >= 16
#if 1
#if LLVM_VERSION_MAJOR <= 13
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
#endif
#if LLVM_VERSION_MAJOR >= 16
PB.registerOptimizerEarlyEPCallback(
#else
#else
PB.registerOptimizerLastEPCallback(
#endif
#endif
[](ModulePassManager &MPM, OptimizationLevel OL
#if LLVM_VERSION_MAJOR >= 20
#if LLVM_VERSION_MAJOR >= 20
,
ThinOrFullLTOPhase Phase
#endif
#endif
) {
@ -109,10 +154,36 @@ llvmGetPassPluginInfo() {
});
/* TODO LTO registration */
#else
using PipelineElement = typename PassBuilder::PipelineElement;
PB.registerPipelineParsingCallback([](StringRef Name,
ModulePassManager &MPM,
ArrayRef<PipelineElement>) {
if (Name == "splitswitches") {
MPM.addPass(SplitSwitchesTransform());
return true;
} else {
return false;
}
});
#endif
}};
}
#else
char SplitSwitchesTransform::ID = 0;
#endif
/* switchConvert - Transform simple list of Cases into list of CaseRange's */
BasicBlock *SplitSwitchesTransform::switchConvert(
CaseVector Cases, std::vector<bool> bytesChecked, BasicBlock *OrigBlock,
@ -321,7 +392,10 @@ BasicBlock *SplitSwitchesTransform::switchConvert(
bool SplitSwitchesTransform::splitSwitches(Module &M) {
LLVMContext &C = M.getContext();
#if (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7)
LLVMContext &C = M.getContext();
#endif
std::vector<SwitchInst *> switches;
/* iterate over all functions, bbs and instruction and add
@ -388,7 +462,11 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) {
CaseVector Cases;
for (SwitchInst::CaseIt i = SI->case_begin(), e = SI->case_end(); i != e;
++i)
#if LLVM_VERSION_MAJOR >= 5
Cases.push_back(CaseExpr(i->getCaseValue(), i->getCaseSuccessor()));
#else
Cases.push_back(CaseExpr(i.getCaseValue(), i.getCaseSuccessor()));
#endif
/* bugfix thanks to pbst
* round up bytesChecked (in case getBitWidth() % 8 != 0) */
std::vector<bool> bytesChecked((7 + Cases[0].Val->getBitWidth()) / 8,
@ -434,9 +512,15 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) {
}
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
PreservedAnalyses SplitSwitchesTransform::run(Module &M,
ModuleAnalysisManager &MAM) {
#else
bool SplitSwitchesTransform::runOnModule(Module &M) {
#endif
if ((isatty(2) && getenv("AFL_QUIET") == NULL) || getenv("AFL_DEBUG") != NULL)
printf("Running split-switches-pass by laf.intel@gmail.com\n");
else
@ -445,16 +529,42 @@ PreservedAnalyses SplitSwitchesTransform::run(Module &M,
bool ret = splitSwitches(M);
verifyModule(M);
/* if (modified) {
PA.abandon<XX_Manager>();
}*/
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
/* if (modified) {
PA.abandon<XX_Manager>();
}*/
if (ret == false)
return PreservedAnalyses::all();
else
return PreservedAnalyses();
#else
return ret;
#endif
}
#if LLVM_VERSION_MAJOR < 11 /* use old pass manager */
static void registerSplitSwitchesTransPass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) {
auto p = new SplitSwitchesTransform();
PM.add(p);
}
static RegisterStandardPasses RegisterSplitSwitchesTransPass(
PassManagerBuilder::EP_OptimizerLast, registerSplitSwitchesTransPass);
static RegisterStandardPasses RegisterSplitSwitchesTransPass0(
PassManagerBuilder::EP_EnabledOnOptLevel0, registerSplitSwitchesTransPass);
#if LLVM_VERSION_MAJOR >= 11
static RegisterStandardPasses RegisterSplitSwitchesTransPassLTO(
PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
registerSplitSwitchesTransPass);
#endif
#endif

View File

@ -1 +1 @@
8c7f180c5a
ef1cd9a8cb

View File

@ -68,11 +68,6 @@ which can be a huge speed improvement.
For an example, see [README.deferred_initialization_example.md](README.deferred_initialization_example.md).
Note that there is also `AFL_EXITPOINT` which you can set to an address that
will trigger a termination of the qemu forked instance when the block that
contains this address is reached. Read again: when the block where the address
is is reached!
## 4) Persistent mode
AFL++'s QEMU mode now supports also persistent mode for x86, x86_64, arm, and

View File

@ -75,6 +75,7 @@ static bool edges_only, /* Ignore hit counts? */
static volatile u8 stop_soon; /* Ctrl-C pressed? */
static u8 *target_path;
static u8 frida_mode;
static u8 qemu_mode;
static u8 cs_mode;
static u32 map_size = MAP_SIZE;
@ -627,7 +628,9 @@ static void handle_stop_sig(int sig) {
static void set_up_environment(char **argv) {
u8 *x;
u8 *x;
char *afl_preload;
char *frida_afl_preload = NULL;
fsrv.dev_null_fd = open("/dev/null", O_RDWR);
if (fsrv.dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
@ -669,7 +672,57 @@ static void set_up_environment(char **argv) {
}
set_sanitizer_defaults();
afl_fsrv_setup_preload(&fsrv, argv[0]);
if (get_afl_env("AFL_PRELOAD")) {
if (qemu_mode) {
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
} else if (frida_mode) {
afl_preload = getenv("AFL_PRELOAD");
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
if (afl_preload) {
frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
} else {
frida_afl_preload = alloc_printf("%s", frida_binary);
}
ck_free(frida_binary);
setenv("LD_PRELOAD", frida_afl_preload, 1);
#ifdef __APPLE__
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
#endif
} else {
/* CoreSight mode uses the default behavior. */
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
#ifdef __APPLE__
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
#endif
}
} else if (frida_mode) {
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
setenv("LD_PRELOAD", frida_binary, 1);
#ifdef __APPLE__
setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
#endif
ck_free(frida_binary);
}
if (frida_afl_preload) { ck_free(frida_afl_preload); }
}
@ -883,9 +936,10 @@ int main(int argc, char **argv_orig, char **envp) {
case 'O': /* FRIDA mode */
if (fsrv.frida_mode) { FATAL("Multiple -O options not supported"); }
if (frida_mode) { FATAL("Multiple -O options not supported"); }
fsrv.frida_mode = true;
frida_mode = 1;
fsrv.frida_mode = frida_mode;
setenv("AFL_FRIDA_INST_SEED", "1", 1);
break;
@ -984,7 +1038,7 @@ int main(int argc, char **argv_orig, char **envp) {
fsrv.target_path = find_binary(argv[optind]);
#endif
fsrv.trace_bits = afl_shm_init(&shm, map_size, 0, DEFAULT_PERMISSION, -1);
fsrv.trace_bits = afl_shm_init(&shm, map_size, 0);
detect_file_args(argv + optind, fsrv.out_file, &use_stdin);
signal(SIGALRM, kill_child);

View File

@ -244,7 +244,7 @@ static inline void insert_object(aflcc_state_t *aflcc, u8 *obj, u8 *fmt,
/* Insert params into the new argv, make clang load the pass. */
static inline void load_llvm_pass(aflcc_state_t *aflcc, u8 *pass) {
if (getenv("AFL_LLVM_ONLY_FSRV")) {
if (getenv("AFL_SAN_NO_INST")) {
if (!be_quiet) { DEBUGF("SAND: Coverage instrumentation disabled\n"); }
return;
@ -2097,7 +2097,7 @@ void add_native_pcguard(aflcc_state_t *aflcc) {
* anyway.
*/
if (aflcc->have_rust_asanrt) { return; }
if (getenv("AFL_LLVM_ONLY_FSRV")) {
if (getenv("AFL_SAN_NO_INST")) {
if (!be_quiet) { DEBUGF("SAND: Coverage instrumentation disabled\n"); }
return;
@ -2138,7 +2138,7 @@ void add_native_pcguard(aflcc_state_t *aflcc) {
*/
void add_optimized_pcguard(aflcc_state_t *aflcc) {
if (getenv("AFL_LLVM_ONLY_FSRV")) {
if (getenv("AFL_SAN_NO_INST")) {
if (!be_quiet) { DEBUGF("SAND: Coverage instrumentation disabled\n"); }
return;
@ -2600,13 +2600,6 @@ void add_assembler(aflcc_state_t *aflcc) {
/* Add params to launch the gcc plugins for instrumentation. */
void add_gcc_plugin(aflcc_state_t *aflcc) {
if (getenv("AFL_GCC_ONLY_FSRV")) {
if (!be_quiet) { DEBUGF("SAND: Coverage instrumentation disabled\n"); }
return;
}
if (aflcc->cmplog_mode) {
insert_object(aflcc, "afl-gcc-cmplog-pass.so", "-fplugin=%s", 0);

View File

@ -179,7 +179,7 @@ u32 check_binary_signatures(u8 *fn) {
if (f_data == MAP_FAILED) { PFATAL("Unable to mmap file '%s'", fn); }
close(fd);
if (afl_memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG))) {
if (afl_memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG) + 1)) {
if (!be_quiet) { OKF(cPIN "Persistent mode binary detected."); }
setenv(PERSIST_ENV_VAR, "1", 1);
@ -204,7 +204,7 @@ u32 check_binary_signatures(u8 *fn) {
}
if (afl_memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG))) {
if (afl_memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
if (!be_quiet) { OKF(cPIN "Deferred forkserver binary detected."); }
setenv(DEFER_ENV_VAR, "1", 1);
@ -819,21 +819,7 @@ void check_environment_vars(char **envp) {
WARNF("AFL environment variable %s is deprecated!",
afl_environment_deprecated[i]);
if (strncmp(afl_environment_deprecated[i], "AFL_SAN_NO_INST",
strlen(afl_environment_deprecated[i])) == 0) {
WARNF(
"AFL_LLVM_ONLY_FSRV/AFL_GCC_ONLY_FSRV is induced and set "
"instead.");
setenv("AFL_GCC_ONLY_FSRV", "1", 0);
setenv("AFL_LLVM_ONLY_FSRV", "1", 0);
} else {
issue_detected = 1;
}
issue_detected = 1;
} else {
@ -1397,12 +1383,12 @@ u32 get_map_size(void) {
/* Create a stream file */
FILE *create_ffile(u8 *fn, mode_t mode) {
FILE *create_ffile(u8 *fn) {
s32 fd;
FILE *f;
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, mode);
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
@ -1416,11 +1402,11 @@ FILE *create_ffile(u8 *fn, mode_t mode) {
/* Create a file */
s32 create_file(u8 *fn, mode_t mode) {
s32 create_file(u8 *fn) {
s32 fd;
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, mode);
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }

View File

@ -51,7 +51,6 @@
#include <sys/resource.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <grp.h>
#ifdef __linux__
#include <dlfcn.h>
@ -141,7 +140,7 @@ nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) {
if (plugin->nyx_get_target_hash64 == NULL) { goto fail; }
plugin->nyx_config_free = dlsym(handle, "nyx_config_free");
if (plugin->nyx_config_free == NULL) { goto fail; }
if (plugin->nyx_get_target_hash64 == NULL) { goto fail; }
OKF("libnyx plugin is ready!");
return plugin;
@ -209,53 +208,9 @@ static void fsrv_exec_child(afl_forkserver_t *fsrv, char **argv) {
}
if (fsrv->gid_set) {
if (setregid(fsrv->gid, fsrv->gid) == -1) {
FATAL("setgid failed: %s\n", strerror(errno));
}
if (setgroups(fsrv->nb_supl_gids, fsrv->supl_gids) == -1) {
FATAL("setgroups failed: %s\n", strerror(errno));
}
}
if (fsrv->uid_set) {
if (setreuid(fsrv->uid, fsrv->uid) == -1) {
FATAL("setuid failed: %s\n", strerror(errno));
}
}
if (fsrv->chown_needed && fsrv->out_file != NULL) {
if (access(fsrv->out_file, R_OK) == -1) {
if (errno == EACCES) {
FATAL(
"Access to the file to fuzz denied. Most likely the requested\n"
" UID and/or GID is denied search permission ('x') for one of "
"the directories\n in the path prefix of \"%s\".",
fsrv->out_file);
}
}
}
execv(fsrv->target_path, argv);
WARNF("Execv failed in forkserver: %s.", strerror(errno));
WARNF("Execv failed in forkserver.");
}
@ -295,16 +250,6 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
fsrv->child_kill_signal = SIGKILL;
fsrv->max_length = MAX_FILE;
if (getenv("AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT") != NULL) {
fsrv->setenv = 1;
} else {
fsrv->setenv = 0;
}
/* exec related stuff */
fsrv->child_pid = -1;
fsrv->map_size = get_map_size();
@ -319,9 +264,6 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
fsrv->persistent_trace_bits = NULL;
#endif
fsrv->uid_set = 0;
fsrv->gid_set = 0;
fsrv->init_child_func = fsrv_exec_child;
list_append(&fsrv_list, fsrv);
@ -368,38 +310,6 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
}
void afl_fsrv_setup_preload(afl_forkserver_t *fsrv, char *argv0) {
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
if (fsrv->qemu_mode) return;
u8 *afl_preload = getenv("AFL_PRELOAD");
u8 *preload_path = NULL;
u8 *frida_binary = NULL;
if (fsrv->frida_mode)
frida_binary = find_afl_binary(argv0, "afl-frida-trace.so");
if (afl_preload && frida_binary)
preload_path = alloc_printf("%s:%s", afl_preload, frida_binary);
else if (afl_preload)
preload_path = ck_strdup(afl_preload);
else if (frida_binary)
preload_path = ck_strdup(frida_binary);
ck_free(frida_binary);
if (preload_path) {
setenv("LD_PRELOAD", preload_path, 1);
#ifdef __APPLE__
setenv("DYLD_INSERT_LIBRARIES", preload_path, 1);
#endif
ck_free(preload_path);
}
}
/* Wrapper for select() and read(), reading a 32 bit var.
Returns the time passed to read.
If the wait times out, returns timeout_ms + 1;
@ -541,26 +451,6 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) {
close(FORKSRV_FD);
close(FORKSRV_FD + 1);
if (fsrv->gid_set) {
if (setgid(fsrv->gid) == -1) {
FATAL("setgid failed: %s\n", strerror(errno));
}
}
if (fsrv->uid_set) {
if (setuid(fsrv->uid) == -1) {
FATAL("setuid failed: %s\n", strerror(errno));
}
}
// finally: exec...
execv(fsrv->target_path, argv);
@ -988,8 +878,6 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
/* CHILD PROCESS */
if (unlikely(fsrv->setenv)) { setenv("AFL_FORKSERVER_PARENT", "1", 0); }
// enable terminating on sigpipe in the children
struct sigaction sa;
memset((char *)&sa, 0, sizeof(sa));
@ -1907,18 +1795,14 @@ void __attribute__((hot)) afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv,
if (unlikely(fsrv->no_unlink)) {
fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_TRUNC, fsrv->perm);
fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_TRUNC,
DEFAULT_PERMISSION);
} else {
unlink(fsrv->out_file); /* Ignore errors. */
fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_EXCL, fsrv->perm);
}
if (fsrv->chown_needed) {
if (fchown(fd, -1, fsrv->gid) == -1) { PFATAL("fchown() failed"); }
fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_EXCL,
DEFAULT_PERMISSION);
}

View File

@ -84,16 +84,10 @@ void write_bitmap(afl_state_t *afl) {
afl->bitmap_changed = 0;
snprintf(fname, PATH_MAX, "%s/fuzz_bitmap", afl->out_dir);
fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, afl->perm);
fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to open '%s'", fname); }
if (afl->chown_needed) {
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
}
ck_write(fd, afl->virgin_bits, afl->fsrv.map_size, fname);
close(fd);
@ -261,8 +255,7 @@ inline u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) {
* on rare cases it fall backs to the slow path: classify_counts() first, then
* return has_new_bits(). */
static inline u8 has_new_bits_unclassified(afl_state_t *afl, u8 *virgin_map,
bool *classified) {
inline u8 has_new_bits_unclassified(afl_state_t *afl, u8 *virgin_map) {
/* Handle the hot path first: no new coverage */
u8 *end = afl->fsrv.trace_bits + afl->fsrv.map_size;
@ -279,7 +272,6 @@ static inline u8 has_new_bits_unclassified(afl_state_t *afl, u8 *virgin_map,
#endif /* ^WORD_SIZE_64 */
classify_counts(&afl->fsrv);
*classified = true;
return has_new_bits(afl, virgin_map);
}
@ -325,15 +317,7 @@ u8 *describe_op(afl_state_t *afl, u8 new_bits, size_t max_description_len) {
if (unlikely(afl->syncing_party)) {
if (unlikely(afl->foreign_file)) {
sprintf(ret, "sync:%s,src:%.20s", afl->syncing_party, afl->foreign_file);
} else {
sprintf(ret, "sync:%s,src:%06u", afl->syncing_party, afl->syncing_case);
}
sprintf(ret, "sync:%s,src:%06u", afl->syncing_party, afl->syncing_case);
} else {
@ -435,18 +419,12 @@ void write_crash_readme(afl_state_t *afl) {
sprintf(fn, "%s/crashes/README.txt", afl->out_dir);
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, afl->perm);
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
/* Do not die on errors here - that would be impolite. */
if (unlikely(fd < 0)) { return; }
if (afl->chown_needed) {
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
}
f = fdopen(fd, "w");
if (unlikely(!f)) {
@ -484,46 +462,6 @@ void write_crash_readme(afl_state_t *afl) {
}
static inline void classify_if_necessary(afl_state_t *afl, bool *classified) {
if (*classified) return;
classify_counts(&afl->fsrv);
*classified = true;
}
static inline void calculate_cksum_if_necessary(afl_state_t *afl, u64 *cksum,
bool *cksumed,
bool *classified) {
if (*cksumed) return;
classify_if_necessary(afl, classified);
*cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
*cksumed = true;
}
static inline void calculate_new_bits_if_necessary(afl_state_t *afl,
u8 *new_bits,
bool *bits_counted,
bool *classified) {
if (*bits_counted) return;
if (*classified) {
*new_bits = has_new_bits(afl, afl->virgin_bits);
} else {
*new_bits = has_new_bits_unclassified(afl, afl->virgin_bits, classified);
}
*bits_counted = true;
}
/* Check if the result of an execve() during routine fuzzing is interesting,
save or queue the input test case for further analysis if so. Returns 1 if
entry is saved, 0 otherwise. */
@ -531,6 +469,8 @@ static inline void calculate_new_bits_if_necessary(afl_state_t *afl,
u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
u32 len, u8 fault) {
u8 classified = 0;
if (unlikely(len == 0)) { return 0; }
if (unlikely(fault == FSRV_RUN_TMOUT && afl->afl_env.afl_ignore_timeouts)) {
@ -539,6 +479,7 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
classify_counts(&afl->fsrv);
u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
classified = 1;
// Saturated increment
if (likely(afl->n_fuzz[cksum % N_FUZZ_SIZE] < 0xFFFFFFFF))
@ -552,14 +493,13 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
u8 fn[PATH_MAX];
u8 *queue_fn = "";
u8 keeping = 0, res, is_timeout = 0;
u8 san_fault = 0, san_idx = 0, feed_san = 0;
u8 new_bits = 0, keeping = 0, res, is_timeout = 0, need_hash = 1;
s32 fd;
u64 cksum = 0;
u32 cksum_simplified = 0, cksum_unique = 0;
bool classified = false, bits_counted = false, cksumed = false;
u8 new_bits = 0; /* valid if bits_counted is true */
u64 cksum = 0; /* valid if cksumed is true */
u8 san_fault = 0;
u8 san_idx = 0;
u8 feed_san = 0;
afl->san_case_status = 0;
@ -569,7 +509,10 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
only be used for special schedules */
if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
calculate_cksum_if_necessary(afl, &cksum, &cksumed, &classified);
classify_counts(&afl->fsrv);
need_hash = 0;
cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
/* Saturated increment */
if (likely(afl->n_fuzz[cksum % N_FUZZ_SIZE] < 0xFFFFFFFF))
@ -604,8 +547,7 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
unlikely(afl->san_abstraction == COVERAGE_INCREASE)) {
/* Check if the input increase the coverage */
calculate_new_bits_if_necessary(afl, &new_bits, &bits_counted,
&classified);
new_bits = has_new_bits_unclassified(afl, afl->virgin_bits);
if (unlikely(new_bits)) { feed_san = 1; }
@ -614,9 +556,15 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
if (unlikely(afl->san_binary_length) &&
likely(afl->san_abstraction == UNIQUE_TRACE)) {
// If schedule is not FAST..RARE, we need to classify counts here
// Note: SAND was evaluated under FAST schedule but should also work
// with other scedules.
classify_if_necessary(afl, &classified);
if (!classified) {
classify_counts(&afl->fsrv);
classified = 1;
}
cksum_unique =
hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
@ -676,7 +624,22 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
/* Keep only if there are new bits in the map, add to queue for
future fuzzing, etc. */
calculate_new_bits_if_necessary(afl, &new_bits, &bits_counted, &classified);
if (!unlikely(afl->san_abstraction == COVERAGE_INCREASE && feed_san)) {
/* If we are in coverage increasing abstraction and have fed input to
sanitizers, we are sure it has new bits.*/
if (classified) {
/* We could have classified the bits in SAND with UNIQUE_TRACE */
new_bits = has_new_bits(afl, afl->virgin_bits);
} else {
new_bits = has_new_bits_unclassified(afl, afl->virgin_bits);
}
}
if (likely(!new_bits)) {
@ -699,11 +662,6 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
save_to_queue:
/* these calculations are necessary because some code flow may jump here via
goto */
calculate_cksum_if_necessary(afl, &cksum, &cksumed, &classified);
calculate_new_bits_if_necessary(afl, &new_bits, &bits_counted, &classified);
#ifndef SIMPLE_FILES
if (!afl->afl_env.afl_sha1_filenames) {
@ -785,8 +743,6 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
#endif
afl->queue_top->exec_cksum = cksum;
if (new_bits == 2) {
afl->queue_top->has_new_cov = 1;
@ -794,8 +750,17 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
}
if (unlikely(need_hash && new_bits)) {
/* due to classify counts we have to recalculate the checksum */
afl->queue_top->exec_cksum =
hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
need_hash = 0;
}
/* For AFLFast schedules we update the new queue entry */
if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
if (likely(cksum)) {
afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE;
afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1;
@ -894,9 +859,7 @@ may_save_fault:
}
new_fault = fuzz_run_target(afl, &afl->fsrv, afl->hang_tmout);
classified = false;
bits_counted = false;
cksumed = false;
classify_counts(&afl->fsrv);
/* A corner case that one user reported bumping into: increasing the
timeout actually uncovers a crash. Make sure we don't discard it if
@ -1088,15 +1051,9 @@ may_save_fault:
u8 fn_log[PATH_MAX];
(void)(snprintf(fn_log, PATH_MAX, "%s.log", fn) + 1);
fd = open(fn_log, O_WRONLY | O_CREAT | O_EXCL, afl->perm);
fd = open(fn_log, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", fn_log); }
if (afl->chown_needed) {
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
}
u32 nyx_aux_string_len = afl->fsrv.nyx_handlers->nyx_get_aux_string(
afl->fsrv.nyx_runner, afl->fsrv.nyx_aux_string,
afl->fsrv.nyx_aux_string_len);

View File

@ -748,16 +748,10 @@ void save_auto(afl_state_t *afl) {
s32 fd;
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, afl->perm);
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
if (afl->chown_needed) {
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
}
ck_write(fd, afl->a_extras[i].data, afl->a_extras[i].len, fn);
close(fd);

View File

@ -589,6 +589,8 @@ void read_foreign_testcases(afl_state_t *afl, int first) {
u8 *fn2 =
alloc_printf("%s/%s", afl->foreign_syncs[iter].dir, nl[i]->d_name);
free(nl[i]); /* not tracked */
if (unlikely(lstat(fn2, &st) || access(fn2, R_OK))) {
if (first) PFATAL("Unable to access '%s'", fn2);
@ -651,14 +653,17 @@ void read_foreign_testcases(afl_state_t *afl, int first) {
u32 len = write_to_testcase(afl, (void **)&mem, st.st_size, 1);
fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
afl->syncing_party = foreign_name;
afl->foreign_file = nl[i]->d_name;
afl->queued_imported += save_if_interesting(afl, mem, len, fault);
afl->syncing_party = 0;
munmap(mem, st.st_size);
close(fd);
if (st.st_mtime > mtime_max) { mtime_max = st.st_mtime; }
show_stats(afl);
if (st.st_mtime > mtime_max) {
mtime_max = st.st_mtime;
show_stats(afl);
}
}
@ -668,21 +673,12 @@ void read_foreign_testcases(afl_state_t *afl, int first) {
}
for (i = 0; i < (u32)nl_cnt; ++i) {
free(nl[i]); /* not tracked */
}
free(nl); /* not tracked */
}
}
afl->foreign_file = NULL;
afl->syncing_party = 0;
if (first) {
afl->last_find_time = 0;
@ -760,10 +756,21 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
if (nl_cnt) {
u32 done = 0;
i = 0;
if (unlikely(afl->in_place_resume)) {
i = nl_cnt;
} else {
i = 0;
}
do {
if (unlikely(afl->in_place_resume)) { --i; }
struct stat st;
u8 dfn[PATH_MAX];
snprintf(dfn, PATH_MAX, "%s/.state/deterministic_done/%s", afl->in_dir,
@ -843,12 +850,22 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
}
next_entry:
if (unlikely(++i >= (u32)nl_cnt)) { done = 1; }
if (unlikely(afl->in_place_resume)) {
if (unlikely(i == 0)) { done = 1; }
} else {
if (unlikely(++i >= (u32)nl_cnt)) { done = 1; }
}
} while (!done);
}
// if (getenv("MYTEST")) afl->in_place_resume = 0;
free(nl); /* not tracked */
if (!afl->queued_items && directory == NULL) {
@ -892,21 +909,9 @@ void perform_dry_run(afl_state_t *afl) {
struct queue_entry *q;
u32 cal_failures = 0, idx;
u8 *use_mem, done = 0;
u8 *use_mem;
if (afl->in_place_resume) {
idx = afl->queued_items;
} else {
idx = 0;
}
do {
if (afl->in_place_resume) { --idx; }
for (idx = 0; idx < afl->queued_items; idx++) {
q = afl->queue_buf[idx];
if (unlikely(!q || q->disabled)) { continue; }
@ -1268,20 +1273,9 @@ void perform_dry_run(afl_state_t *afl) {
++afl->saved_crashes;
fd = open(crash_fn, O_WRONLY | O_CREAT | O_EXCL, afl->perm);
fd = open(crash_fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", crash_fn); }
ck_write(fd, use_mem, read_len, crash_fn);
if (afl->chown_needed) {
if (fchown(fd, -1, afl->fsrv.gid) == -1) {
PFATAL("fchown() failed");
}
}
close(fd);
#ifdef __linux__
@ -1290,7 +1284,8 @@ void perform_dry_run(afl_state_t *afl) {
u8 crash_log_fn[PATH_MAX];
snprintf(crash_log_fn, PATH_MAX, "%s.log", crash_fn);
fd = open(crash_log_fn, O_WRONLY | O_CREAT | O_EXCL, afl->perm);
fd = open(crash_log_fn, O_WRONLY | O_CREAT | O_EXCL,
DEFAULT_PERMISSION);
if (unlikely(fd < 0)) {
PFATAL("Unable to create '%s'", crash_log_fn);
@ -1303,17 +1298,6 @@ void perform_dry_run(afl_state_t *afl) {
ck_write(fd, afl->fsrv.nyx_aux_string, nyx_aux_string_len,
crash_log_fn);
if (afl->chown_needed) {
if (fchown(fd, -1, afl->fsrv.gid) == -1) {
PFATAL("fchown() failed");
}
}
close(fd);
}
@ -1394,17 +1378,7 @@ void perform_dry_run(afl_state_t *afl) {
}
if (!afl->in_place_resume) {
if (++idx >= afl->queued_items) { done = 1; }
} else {
if (idx == 0) { done = 1; }
}
} while (!done);
}
if (cal_failures) {
@ -1433,51 +1407,67 @@ void perform_dry_run(afl_state_t *afl) {
q = afl->queue_buf[idx];
if (!q || q->disabled || q->cal_failed || !q->exec_cksum) { continue; }
u32 done = 0;
for (i = idx + 1; likely(i < afl->queued_items && afl->queue_buf[i]); ++i) {
for (i = idx + 1;
likely(i < afl->queued_items && afl->queue_buf[i] && !done); ++i) {
struct queue_entry *p = afl->queue_buf[i];
if (p->disabled || p->cal_failed || !p->exec_cksum) { continue; }
if (p->exec_cksum != q->exec_cksum) continue;
duplicates = 1;
if (p->exec_cksum == q->exec_cksum) {
// we keep the shorter file
struct queue_entry *to_disable, *to_keep;
if (p->len >= q->len) {
duplicates = 1;
to_disable = p;
to_keep = q;
// we keep the shorter file
if (p->len >= q->len) {
} else {
if (!p->was_fuzzed) {
to_disable = q;
to_keep = p;
p->was_fuzzed = 1;
afl->reinit_table = 1;
--afl->pending_not_fuzzed;
--afl->active_items;
}
p->disabled = 1;
p->perf_score = 0;
if (afl->debug) {
WARNF("Same coverage - %s is kept active, %s is disabled.",
q->fname, p->fname);
}
} else {
if (!q->was_fuzzed) {
q->was_fuzzed = 1;
afl->reinit_table = 1;
--afl->pending_not_fuzzed;
--afl->active_items;
}
q->disabled = 1;
q->perf_score = 0;
if (afl->debug) {
WARNF("Same coverage - %s is kept active, %s is disabled.",
p->fname, q->fname);
}
done = 1; // end inner loop because outer loop entry is disabled now
}
}
if (!to_disable->was_fuzzed) {
to_disable->was_fuzzed = 1;
afl->reinit_table = 1;
--afl->pending_not_fuzzed;
--afl->active_items;
}
to_disable->disabled = 1;
to_disable->perf_score = 0;
if (afl->debug) {
WARNF("Same coverage - %s is kept active, %s is disabled.",
to_keep->fname, to_disable->fname);
}
// end inner loop because outer loop entry is disabled now
if (to_disable == q) break;
}
}
@ -1504,7 +1494,7 @@ void perform_dry_run(afl_state_t *afl) {
/* Helper function: link() if possible, copy otherwise. */
static void link_or_copy(u8 *old_path, u8 *new_path, mode_t perm) {
static void link_or_copy(u8 *old_path, u8 *new_path) {
s32 i = link(old_path, new_path);
if (!i) { return; }
@ -1515,7 +1505,7 @@ static void link_or_copy(u8 *old_path, u8 *new_path, mode_t perm) {
sfd = open(old_path, O_RDONLY);
if (sfd < 0) { PFATAL("Unable to open '%s'", old_path); }
dfd = open(new_path, O_WRONLY | O_CREAT | O_EXCL, perm);
dfd = open(new_path, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (dfd < 0) { PFATAL("Unable to create '%s'", new_path); }
tmp = ck_alloc(64 * 1024);
@ -1567,9 +1557,8 @@ void pivot_inputs(afl_state_t *afl) {
ID matches the one we'd assign, just use the original file name.
This is valuable for resuming fuzzing runs. */
if (afl->in_place_resume ||
(!strncmp(rsl, CASE_PREFIX, 3) &&
sscanf(rsl + 3, "%06u", &orig_id) == 1 && orig_id == id)) {
if (!strncmp(rsl, CASE_PREFIX, 3) &&
sscanf(rsl + 3, "%06u", &orig_id) == 1 && orig_id == id) {
u8 *src_str;
u32 src_id;
@ -1651,16 +1640,10 @@ void pivot_inputs(afl_state_t *afl) {
/* Pivot to the new queue entry. */
link_or_copy(q->fname, nfn, afl->perm);
link_or_copy(q->fname, nfn);
ck_free(q->fname);
q->fname = nfn;
if (afl->chown_needed) {
if (chown(nfn, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
}
/* Make sure that the passed_det value carries over, too. */
if (q->passed_det) { mark_as_det_done(afl, q); }
@ -2267,13 +2250,13 @@ void setup_dirs_fds(afl_state_t *afl) {
ACTF("Setting up output directories...");
if (afl->sync_id && mkdir(afl->sync_dir, afl->dir_perm) && errno != EEXIST) {
if (afl->sync_id && mkdir(afl->sync_dir, 0700) && errno != EEXIST) {
PFATAL("Unable to create '%s'", afl->sync_dir);
}
if (mkdir(afl->out_dir, afl->dir_perm)) {
if (mkdir(afl->out_dir, 0700)) {
if (errno != EEXIST) { PFATAL("Unable to create '%s'", afl->out_dir); }
@ -2281,16 +2264,6 @@ void setup_dirs_fds(afl_state_t *afl) {
} else {
if (afl->chown_needed) {
if (chown(afl->out_dir, -1, afl->fsrv.gid) == -1) {
PFATAL("fchown() failed");
}
}
if (afl->in_place_resume) {
FATAL("Resume attempted but old output directory not found");
@ -2325,27 +2298,27 @@ void setup_dirs_fds(afl_state_t *afl) {
/* Queue directory for any starting & discovered paths. */
tmp = alloc_printf("%s/queue", afl->out_dir);
if (mkdir(tmp, afl->dir_perm)) { PFATAL("Unable to create '%s'", tmp); }
if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
ck_free(tmp);
/* Top-level directory for queue metadata used for session
resume and related tasks. */
tmp = alloc_printf("%s/queue/.state/", afl->out_dir);
if (mkdir(tmp, afl->dir_perm)) { PFATAL("Unable to create '%s'", tmp); }
if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
ck_free(tmp);
/* Directory for flagging queue entries that went through
deterministic fuzzing in the past. */
tmp = alloc_printf("%s/queue/.state/deterministic_done/", afl->out_dir);
if (mkdir(tmp, afl->dir_perm)) { PFATAL("Unable to create '%s'", tmp); }
if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
ck_free(tmp);
/* Directory with the auto-selected dictionary entries. */
tmp = alloc_printf("%s/queue/.state/auto_extras/", afl->out_dir);
if (mkdir(tmp, afl->dir_perm)) { PFATAL("Unable to create '%s'", tmp); }
if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
ck_free(tmp);
/* Sync directory for keeping track of cooperating fuzzers. */
@ -2354,8 +2327,7 @@ void setup_dirs_fds(afl_state_t *afl) {
tmp = alloc_printf("%s/.synced/", afl->out_dir);
if (mkdir(tmp, afl->dir_perm) &&
(!afl->in_place_resume || errno != EEXIST)) {
if (mkdir(tmp, 0700) && (!afl->in_place_resume || errno != EEXIST)) {
PFATAL("Unable to create '%s'", tmp);
@ -2368,13 +2340,13 @@ void setup_dirs_fds(afl_state_t *afl) {
/* All recorded crashes. */
tmp = alloc_printf("%s/crashes", afl->out_dir);
if (mkdir(tmp, afl->dir_perm)) { PFATAL("Unable to create '%s'", tmp); }
if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
ck_free(tmp);
/* All recorded hangs. */
tmp = alloc_printf("%s/hangs", afl->out_dir);
if (mkdir(tmp, afl->dir_perm)) { PFATAL("Unable to create '%s'", tmp); }
if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
ck_free(tmp);
/* Generally useful file descriptors. */
@ -2391,14 +2363,8 @@ void setup_dirs_fds(afl_state_t *afl) {
if (!afl->in_place_resume) {
int fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, afl->perm);
int fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", tmp); }
if (afl->chown_needed) {
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
}
ck_free(tmp);
afl->fsrv.plot_file = fdopen(fd, "w");
@ -2424,14 +2390,8 @@ void setup_dirs_fds(afl_state_t *afl) {
} else {
int fd = open(tmp, O_WRONLY | O_CREAT, afl->perm);
int fd = open(tmp, O_WRONLY | O_CREAT, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", tmp); }
if (afl->chown_needed) {
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
}
ck_free(tmp);
afl->fsrv.plot_file = fdopen(fd, "w");
@ -2447,14 +2407,8 @@ void setup_dirs_fds(afl_state_t *afl) {
tmp = alloc_printf("%s/plot_det_data", afl->out_dir);
int fd = open(tmp, O_WRONLY | O_CREAT, afl->perm);
int fd = open(tmp, O_WRONLY | O_CREAT, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", tmp); }
if (afl->chown_needed) {
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
}
ck_free(tmp);
afl->fsrv.det_plot_file = fdopen(fd, "w");
@ -2478,14 +2432,8 @@ void setup_cmdline_file(afl_state_t *afl, char **argv) {
/* Store the command line to reproduce our findings */
tmp = alloc_printf("%s/cmdline", afl->out_dir);
fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, afl->perm);
fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", tmp); }
if (afl->chown_needed) {
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
}
ck_free(tmp);
cmdline_file = fdopen(fd, "w");
@ -2520,7 +2468,7 @@ void setup_stdio_file(afl_state_t *afl) {
unlink(afl->fsrv.out_file); /* Ignore errors */
afl->fsrv.out_fd =
open(afl->fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, afl->perm);
open(afl->fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (afl->fsrv.out_fd < 0) {
@ -2528,16 +2476,6 @@ void setup_stdio_file(afl_state_t *afl) {
}
if (afl->chown_needed) {
if (fchown(afl->fsrv.out_fd, -1, afl->fsrv.gid) == -1) {
PFATAL("fchown() failed");
}
}
}
/* Make sure that core dumps don't go to a program. */
@ -2863,9 +2801,9 @@ void fix_up_sync(afl_state_t *afl) {
}
if (strlen(afl->sync_id) > SYNC_ID_MAX_LEN) {
if (strlen(afl->sync_id) > 50) {
FATAL("sync_id max length is %d characters", SYNC_ID_MAX_LEN);
FATAL("sync_id max length is 50 characters");
}
@ -2973,17 +2911,11 @@ void setup_testcase_shmem(afl_state_t *afl) {
afl->shm_fuzz = ck_alloc(sizeof(sharedmem_t));
// we need to set the non-instrumented mode to not overwrite the SHM_ENV_VAR
size_t shm_fuzz_map_size = SHM_FUZZ_MAP_SIZE_DEFAULT;
u8 *map = afl_shm_init(afl->shm_fuzz, shm_fuzz_map_size, 1, afl->perm,
afl->chown_needed ? afl->fsrv.gid : -1);
u8 *map = afl_shm_init(afl->shm_fuzz, MAX_FILE + sizeof(u32), 1);
afl->shm_fuzz->shmemfuzz_mode = 1;
if (!map) { FATAL("BUG: Zero return from afl_shm_init."); }
u8 *shm_fuzz_map_size_str = alloc_printf("%zu", shm_fuzz_map_size);
setenv(SHM_FUZZ_MAP_SIZE_ENV_VAR, shm_fuzz_map_size_str, 1);
ck_free(shm_fuzz_map_size_str);
#ifdef USEMMAP
setenv(SHM_FUZZ_ENV_VAR, afl->shm_fuzz->g_shm_file_path, 1);
#else
@ -3184,7 +3116,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
!afl->fsrv.nyx_mode &&
#endif
!afl->fsrv.cs_mode && !afl->non_instrumented_mode &&
!afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR))) {
!afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
SAYF("\n" cLRD "[-] " cRST
"Looks like the target binary is not instrumented! The fuzzer depends "
@ -3215,7 +3147,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
}
if ((afl->fsrv.cs_mode || afl->fsrv.qemu_mode || afl->fsrv.frida_mode) &&
afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR))) {
afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
SAYF("\n" cLRD "[-] " cRST
"This program appears to be instrumented with AFL++ compilers, but is "
@ -3250,7 +3182,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
/* Detect persistent & deferred init signatures in the binary. */
if (afl_memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG))) {
if (afl_memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG) + 1)) {
OKF(cPIN "Persistent mode binary detected.");
setenv(PERSIST_ENV_VAR, "1", 1);
@ -3277,7 +3209,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
}
if (afl->fsrv.frida_mode ||
afl_memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG))) {
afl_memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
OKF(cPIN "Deferred forkserver binary detected.");
setenv(DEFER_ENV_VAR, "1", 1);

View File

@ -623,16 +623,10 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
unlink(q->fname); /* ignore errors */
fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, afl->perm);
fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); }
if (afl->chown_needed) {
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
}
ck_write(fd, out_buf, out_len, q->fname);
close(fd);

View File

@ -411,12 +411,11 @@ u8 fuzz_one_original(afl_state_t *afl) {
u_simplestring_time_diff(time_tmp, afl->prev_run_time + get_cur_time(),
afl->start_time);
ACTF(
"Fuzzing test case #%u (%u total, %s%llu crashes saved%s, state: %s, "
"Fuzzing test case #%u (%u total, %llu crashes saved, state: %s, "
"mode=%s, "
"perf_score=%0.0f, weight=%0.0f, favorite=%u, was_fuzzed=%u, "
"exec_us=%llu, hits=%u, map=%u, ascii=%u, run_time=%s)...",
afl->current_entry, afl->queued_items,
afl->saved_crashes != 0 ? cRED : "", afl->saved_crashes, cRST,
afl->current_entry, afl->queued_items, afl->saved_crashes,
get_fuzzing_state(afl), afl->fuzz_mode ? "exploit" : "explore",
afl->queue_cur->perf_score, afl->queue_cur->weight,
afl->queue_cur->favored, afl->queue_cur->was_fuzzed,
@ -6178,8 +6177,7 @@ u8 fuzz_one(afl_state_t *afl) {
if (afl->do_document == 0) {
snprintf(path_buf, PATH_MAX, "%s/mutations", afl->out_dir);
afl->do_document =
mkdir(path_buf, afl->dir_perm); // if it exists we do not care
afl->do_document = mkdir(path_buf, 0700); // if it exists we do not care
afl->do_document = 1;
} else {

View File

@ -432,15 +432,8 @@ void mark_as_det_done(afl_state_t *afl, struct queue_entry *q) {
snprintf(fn, PATH_MAX, "%s/queue/.state/deterministic_done/%s", afl->out_dir,
strrchr((char *)q->fname, '/') + 1);
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, afl->perm);
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
if (afl->chown_needed) {
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
}
close(fd);
q->passed_det = 1;

View File

@ -26,10 +26,8 @@
#include "afl-fuzz.h"
#include <sys/time.h>
#include <sys/stat.h>
#include <signal.h>
#include <limits.h>
#include <glob.h>
#if !defined NAME_MAX
#define NAME_MAX _XOPEN_NAME_MAX
#endif
@ -258,21 +256,11 @@ u32 __attribute__((hot)) write_to_testcase(afl_state_t *afl, void **mem,
afl->document_counter++,
describe_op(afl, 0, NAME_MAX - strlen("000000000:")));
if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, afl->perm)) >= 0) {
if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION)) >=
0) {
if (write(doc_fd, *mem, len) != len)
PFATAL("write to mutation file failed: %s", fn);
if (afl->chown_needed) {
if (fchown(doc_fd, -1, afl->fsrv.gid) == -1) {
PFATAL("fchown() failed");
}
}
close(doc_fd);
}
@ -396,23 +384,19 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at,
if (unlikely(afl->no_unlink)) {
fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_TRUNC, afl->perm);
fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_TRUNC,
DEFAULT_PERMISSION);
} else {
unlink(afl->fsrv.out_file); /* Ignore errors. */
fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_EXCL, afl->perm);
fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_EXCL,
DEFAULT_PERMISSION);
}
if (fd < 0) { PFATAL("Unable to create '%s'", afl->fsrv.out_file); }
if (afl->chown_needed) {
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
}
} else {
lseek(fd, 0, SEEK_SET);
@ -509,41 +493,36 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
afl->afl_env.afl_post_process_keep_original = 1;
/* we need a dummy run if this is LTO + cmplog */
/*
if (unlikely(afl->shm.cmplog_mode)) {
if (unlikely(afl->shm.cmplog_mode)) {
(void)write_to_testcase(afl, (void **)&use_mem, q->len, 1);
(void)write_to_testcase(afl, (void **)&use_mem, q->len, 1);
fault = fuzz_run_target(afl, &afl->fsrv, use_tmout);
fault = fuzz_run_target(afl, &afl->fsrv, use_tmout);
// afl->stop_soon is set by the handler for Ctrl+C. When it's pressed,
// we want to bail out quickly.
/* afl->stop_soon is set by the handler for Ctrl+C. When it's pressed,
we want to bail out quickly. */
if (afl->stop_soon || fault != afl->crash_mode) { goto abort_calibration;
if (afl->stop_soon || fault != afl->crash_mode) { goto abort_calibration; }
}
if (!afl->non_instrumented_mode && !afl->stage_cur &&
!count_bytes(afl, afl->fsrv.trace_bits)) {
if (!afl->non_instrumented_mode &&
!count_bytes(afl, afl->fsrv.trace_bits)) {
fault = FSRV_RUN_NOINST;
goto abort_calibration;
}
#ifdef INTROSPECTION
if (unlikely(!q->bitsmap_size)) { q->bitsmap_size = afl->bitsmap_size; }
#endif
fault = FSRV_RUN_NOINST;
goto abort_calibration;
}
*/
#ifdef INTROSPECTION
if (unlikely(!q->bitsmap_size)) q->bitsmap_size = afl->bitsmap_size;
#endif
}
if (q->exec_cksum) {
memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size);
hnb = has_new_bits(afl, afl->virgin_bits);
if (unlikely(hnb > new_bits)) { new_bits = hnb; }
if (hnb > new_bits) { new_bits = hnb; }
}
@ -572,7 +551,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
if (afl->stop_soon || fault != afl->crash_mode) { goto abort_calibration; }
if (!afl->non_instrumented_mode &&
if (!afl->non_instrumented_mode && !afl->stage_cur &&
!count_bytes(afl, afl->fsrv.trace_bits)) {
fault = FSRV_RUN_NOINST;
@ -581,19 +560,17 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
}
#ifdef INTROSPECTION
if (unlikely(!q->bitsmap_size)) { q->bitsmap_size = afl->bitsmap_size; }
if (unlikely(!q->bitsmap_size)) q->bitsmap_size = afl->bitsmap_size;
#endif
classify_counts(&afl->fsrv);
cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
if (unlikely(q->exec_cksum != cksum)) {
if (q->exec_cksum != cksum) {
hnb = has_new_bits(afl, afl->virgin_bits);
if (hnb > new_bits) { new_bits = hnb; }
if (unlikely(hnb > new_bits)) { new_bits = hnb; }
if (likely(q->exec_cksum)) {
if (q->exec_cksum) {
u32 i;
@ -720,110 +697,6 @@ abort_calibration:
}
/* Do not sync items that were synced from us */
static bool is_known_case(afl_state_t *afl, u8 *name) {
static char coming_from_me_str[SYNC_ID_MAX_LEN + 2];
static u32 coming_from_me_len = 0;
static u32 min_len = 15 + 4 + 6;
if (!coming_from_me_len) {
snprintf(coming_from_me_str, sizeof(coming_from_me_str), "%s,",
afl->sync_id);
min_len += coming_from_me_len = strlen(coming_from_me_str);
}
// file name length long enough so it can be ours
if (unlikely(strlen(name) < min_len)) { return false; }
// is it based on a sync? allow optimizer to make an integer comparison
if (likely(memcmp(name + 10, "sync", 4) != 0)) { return false; }
// we jump over the ':' after 'sync' and compare to our sync name
if (unlikely(memcmp(name + 15, coming_from_me_str, coming_from_me_len) !=
0)) {
return false;
}
/* We do not need this as we now look on startup how many files are in sync
targets.
int src_id = atoi(name + 15 + coming_from_me_len + 4);
if (unlikely(src_id >= afl->queued_items)) return false;
*/
// yes it is highly likely a current testcase we already know
return true;
}
/* Write into .sync/INSTANCE.max how many queue files were there on startup */
void check_sync_fuzzers(afl_state_t *afl) {
if (unlikely(afl->afl_env.afl_no_sync)) { return; }
DIR *sd, *dir;
struct dirent *sd_ent, *entry;
u8 qd_path[PATH_MAX], qd_synced_maxid[PATH_MAX];
sd = opendir(afl->sync_dir);
if (!sd) { PFATAL("Unable to open '%s'", afl->sync_dir); }
u64 sync_start_us = get_cur_time_us();
// Look at the entries created for every other fuzzer in the sync directory.
while ((sd_ent = readdir(sd))) {
if (sd_ent->d_name[0] == '.' || !strcmp(afl->sync_id, sd_ent->d_name)) {
continue;
}
sprintf(qd_path, "%s/%s/queue", afl->sync_dir, sd_ent->d_name);
dir = opendir(qd_path);
if (dir) {
u32 max_start_id = 0;
while ((entry = readdir(dir)) != NULL) {
max_start_id++;
}
if (max_start_id > 4) {
sprintf(qd_synced_maxid, "%s/.synced/%s.max", afl->out_dir,
sd_ent->d_name);
s32 max_fd = open(qd_synced_maxid, O_WRONLY | O_CREAT | O_TRUNC,
DEFAULT_PERMISSION);
if (max_fd >= 0) {
max_start_id -= 4; // without ".", "..", ".state" and counting from 0
write(max_fd, &max_start_id, sizeof(u32));
close(max_fd);
}
}
}
closedir(dir);
}
closedir(sd);
update_sync_time(afl, &sync_start_us);
}
/* Grab interesting test cases from other fuzzers. */
void sync_fuzzers(afl_state_t *afl) {
@ -842,7 +715,8 @@ void sync_fuzzers(afl_state_t *afl) {
afl->cur_depth = 0;
u64 sync_start_us = get_cur_time_us();
// Look at the entries created for every other fuzzer in the sync directory.
/* Look at the entries created for every other fuzzer in the sync directory.
*/
while ((sd_ent = readdir(sd))) {
@ -850,11 +724,12 @@ void sync_fuzzers(afl_state_t *afl) {
// iteration
update_sync_time(afl, &sync_start_us);
u8 qd_synced_path[PATH_MAX], qd_path[PATH_MAX], qd_synced_maxid[PATH_MAX];
u32 min_accept = 0, next_min_accept = 0, max_start_id = 0;
u8 qd_synced_path[PATH_MAX], qd_path[PATH_MAX];
u32 min_accept = 0, next_min_accept = 0;
s32 id_fd;
// Skip dot files and our own output directory.
/* Skip dot files and our own output directory. */
if (sd_ent->d_name[0] == '.' || !strcmp(afl->sync_id, sd_ent->d_name)) {
@ -889,7 +764,14 @@ void sync_fuzzers(afl_state_t *afl) {
synced++;
// Skip anything that doesn't have a queue/ subdirectory.
/* document the attempt to sync to this instance */
sprintf(qd_synced_path, "%s/.synced/%s.last", afl->out_dir, sd_ent->d_name);
id_fd =
open(qd_synced_path, O_RDWR | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
if (id_fd >= 0) close(id_fd);
/* Skip anything that doesn't have a queue/ subdirectory. */
sprintf(qd_path, "%s/%s/queue", afl->sync_dir, sd_ent->d_name);
@ -905,20 +787,14 @@ 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);
id_fd = open(qd_synced_path, O_RDWR | O_CREAT, afl->perm);
id_fd = open(qd_synced_path, O_RDWR | O_CREAT, DEFAULT_PERMISSION);
if (id_fd < 0) { PFATAL("Unable to create '%s'", qd_synced_path); }
if (afl->chown_needed) {
if (fchown(id_fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
}
if (read(id_fd, &min_accept, sizeof(u32)) == sizeof(u32)) {
next_min_accept = min_accept;
@ -926,55 +802,6 @@ void sync_fuzzers(afl_state_t *afl) {
}
// now document the attempt to sync to this instance
sprintf(qd_synced_path, "%s/.synced/%s.last", afl->out_dir, sd_ent->d_name);
int id_fd2 =
open(qd_synced_path, O_RDWR | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
if (id_fd2 >= 0) close(id_fd2);
// It could be that the target syncing instance was restarted, check!
time_t last_mtime = 0;
char id0[PATH_MAX];
struct stat st;
if (stat(qd_synced_path, &st) == 0) { last_mtime = st.st_mtime; }
snprintf(id0, sizeof(id0), "%s/%s/cmdline", afl->sync_dir, sd_ent->d_name);
if (likely(stat(id0, &st) == 0)) {
if (unlikely(last_mtime && last_mtime <= st.st_mtime)) {
// the first entry is newer than when we synced last - instance was
// restarted - we have to reset our counter and will skip this instance
// this time. It could also be this was trimmed later, or restated with
// resume-in-place though but better be safe.
min_accept = 0;
ck_write(id_fd, &min_accept, sizeof(u32), qd_synced_path);
goto close_sync;
}
} else {
// something went wrong - this cannot be right, mabye the instance is
// restarting, skip
goto close_sync;
}
// check if there is a file documented the maximum id seen on startup
sprintf(qd_synced_maxid, "%s/.synced/%s.max", afl->out_dir, sd_ent->d_name);
s32 max_fd = open(qd_synced_maxid, O_RDONLY, DEFAULT_PERMISSION);
if (max_fd >= 0) {
read(max_fd, &max_start_id, sizeof(u32));
close(max_fd);
if (max_start_id < next_min_accept) { unlink(qd_synced_maxid); }
}
/* Show stats */
snprintf(afl->stage_name_buf, STAGE_BUF_SIZE, "sync %u", ++sync_cnt);
@ -1028,37 +855,34 @@ void sync_fuzzers(afl_state_t *afl) {
if (st.st_size && st.st_size <= MAX_FILE) {
if (likely(next_min_accept < max_start_id ||
!is_known_case(afl, namelist[o]->d_name))) {
u8 fault;
u8 *mem = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
/* See what happens. We rely on save_if_interesting() to catch major
errors and save the test case. */
if (mem == MAP_FAILED) { PFATAL("Unable to mmap '%s'", path); }
u8 *mem = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
/* See what happens. We rely on save_if_interesting() to catch major
errors and save the test case. */
if (mem == MAP_FAILED) { PFATAL("Unable to mmap '%s'", path); }
u32 new_len = write_to_testcase(afl, (void **)&mem, st.st_size, 1);
u32 new_len = write_to_testcase(afl, (void **)&mem, st.st_size, 1);
fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
u8 fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
if (afl->stop_soon) {
if (afl->stop_soon) {
munmap(mem, st.st_size);
close(fd);
goto close_sync;
}
afl->syncing_party = sd_ent->d_name;
afl->queued_imported += save_if_interesting(afl, mem, new_len, fault);
show_stats(afl);
afl->syncing_party = 0;
munmap(mem, st.st_size);
close(fd);
goto close_sync;
}
afl->syncing_party = sd_ent->d_name;
afl->queued_imported += save_if_interesting(afl, mem, new_len, fault);
show_stats(afl);
afl->syncing_party = 0;
munmap(mem, st.st_size);
}
close(fd);
@ -1316,7 +1140,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
if (unlikely(afl->no_unlink)) {
fd = open(q->fname, O_WRONLY | O_CREAT | O_TRUNC, afl->perm);
fd = open(q->fname, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); }
@ -1331,7 +1155,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
} else {
unlink(q->fname); /* ignore errors */
fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, afl->perm);
fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); }
@ -1339,12 +1163,6 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
}
if (afl->chown_needed) {
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
}
close(fd);
queue_testcase_retake_mem(afl, q, in_buf, q->len, orig_len);

View File

@ -39,9 +39,6 @@ void sanfuzz_exec_child(afl_forkserver_t *fsrv, char **argv) {
}
// In case users provide the normally instrumented binaries, this servers as
// the last resort to avoid collecting incorrect coverage.
setenv("AFL_LLVM_ONLY_FSRV", "1", 0);
execv(fsrv->target_path, argv);
}

View File

@ -148,34 +148,6 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) {
}
void afl_resize_map_buffers(afl_state_t *afl, u32 old_size, u32 new_size) {
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_size);
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_size);
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_size);
afl->var_bytes = ck_realloc(afl->var_bytes, new_size);
afl->top_rated = ck_realloc(afl->top_rated, new_size * sizeof(void *));
afl->clean_trace = ck_realloc(afl->clean_trace, new_size);
afl->clean_trace_custom = ck_realloc(afl->clean_trace_custom, new_size);
afl->first_trace = ck_realloc(afl->first_trace, new_size);
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_size);
if (old_size < new_size) {
u32 size_diff = new_size - old_size;
memset(afl->var_bytes + old_size, 0, size_diff);
memset(afl->top_rated + old_size * sizeof(void *), 0,
size_diff * sizeof(void *));
memset(afl->clean_trace + old_size, 0, size_diff);
memset(afl->clean_trace_custom + old_size, 0, size_diff);
memset(afl->first_trace + old_size, 0, size_diff);
memset(afl->map_tmp_buf + old_size, 0, size_diff);
}
}
/*This sets up the environment variables for afl-fuzz into the afl_state
* struct*/
@ -683,89 +655,6 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
afl->afl_env.afl_sha1_filenames =
get_afl_env(afl_environment_variables[i]) ? 1 : 0;
} else if (!strncmp(env, "AFL_FORKSRV_UID",
afl_environment_variable_len)) {
u8 *uid_str = (u8 *)get_afl_env(afl_environment_variables[i]);
char *ret;
int uid = strtol(uid_str, &ret, 10);
if (*ret != '\0') {
WARNF("Incorrect value given to AFL_FORKSRV_UID\n");
} else {
afl->afl_env.afl_forksrv_uid_set = 1;
afl->afl_env.afl_forksrv_uid = uid;
}
} else if (!strncmp(env, "AFL_FORKSRV_GID",
afl_environment_variable_len)) {
u8 *gid_str = (u8 *)get_afl_env(afl_environment_variables[i]);
// Count the number of supplementary GIDs
// and prepare the string for the next loop
afl->afl_env.afl_forksrv_nb_supl_gids = 0;
for (u32 i = 0; gid_str[i] != '\0'; i++) {
if (gid_str[i] == ',') {
afl->afl_env.afl_forksrv_nb_supl_gids++;
gid_str[i] = '\0';
}
}
if (afl->afl_env.afl_forksrv_nb_supl_gids > 0) {
afl->afl_env.afl_forksrv_supl_gids = ck_alloc(
sizeof(gid_t) * afl->afl_env.afl_forksrv_nb_supl_gids);
}
for (u16 i = 0; i < afl->afl_env.afl_forksrv_nb_supl_gids + 1;
i++) {
char *ret;
int gid = strtol(gid_str, &ret, 10);
if (*ret != '\0') {
WARNF("Incorrect value given to AFL_FORKSRV_GID\n");
afl->afl_env.afl_forksrv_gid_set = 0;
afl->afl_env.afl_forksrv_gid = 0;
free(afl->afl_env.afl_forksrv_supl_gids);
break;
} else {
// First GID is the effective one, others are supplementary
// ones.
if (i == 0) {
afl->afl_env.afl_forksrv_gid_set = 1;
afl->afl_env.afl_forksrv_gid = gid;
} else {
afl->afl_env.afl_forksrv_supl_gids[i - 1] = gid;
}
// Jump to next GID
gid_str = ret + 1;
}
}
}
} else {
@ -891,8 +780,6 @@ void afl_state_deinit(afl_state_t *afl) {
ck_free(afl->skipdet_g);
ck_free(afl->havoc_prof);
ck_free(afl->afl_env.afl_forksrv_supl_gids);
list_remove(&afl_states, afl);
}

View File

@ -28,13 +28,8 @@
#include "envs.h"
#include <limits.h>
// 7 is the number of characters in a color control code
// 11 is the number of characters in the fuzzing state itself
// 5 is the number of characters in `cRST`
// 1 is for the null character
static char fuzzing_state[4][7 + 11 + 5 + 1] = {
"started :-)", "in progress", "final phase", cRED "finished..." cRST};
static char fuzzing_state[4][12] = {"started :-)", "in progress", "final phase",
"finished..."};
char *get_fuzzing_state(afl_state_t *afl) {
@ -59,13 +54,13 @@ char *get_fuzzing_state(afl_state_t *afl) {
u64 percent_cur = last_find_100 / cur_run_time;
u64 percent_total = last_find_100 / cur_total_run_time;
if (unlikely(percent_cur >= 75 && percent_total >= 75)) {
if (unlikely(percent_cur >= 80 && percent_total >= 80)) {
if (unlikely(afl->afl_env.afl_exit_when_done)) { afl->stop_soon = 2; }
return fuzzing_state[3];
} else if (unlikely(percent_cur >= 50 && percent_total >= 50)) {
} else if (unlikely(percent_cur >= 55 && percent_total >= 55)) {
return fuzzing_state[2];
@ -86,13 +81,7 @@ void write_setup_file(afl_state_t *afl, u32 argc, char **argv) {
u8 fn[PATH_MAX], fn2[PATH_MAX];
snprintf(fn2, PATH_MAX, "%s/target_hash", afl->out_dir);
FILE *f2 = create_ffile(fn2, afl->perm);
if (afl->chown_needed) {
if (chown(fn2, -1, afl->fsrv.gid) == -1) { PFATAL("chown() failed"); }
}
FILE *f2 = create_ffile(fn2);
#ifdef __linux__
if (afl->fsrv.nyx_mode) {
@ -112,15 +101,9 @@ void write_setup_file(afl_state_t *afl, u32 argc, char **argv) {
fclose(f2);
snprintf(fn, PATH_MAX, "%s/fuzzer_setup", afl->out_dir);
FILE *f = create_ffile(fn, afl->perm);
FILE *f = create_ffile(fn);
u32 i;
if (afl->chown_needed) {
if (chown(fn, -1, afl->fsrv.gid) == -1) { PFATAL("chown() failed"); }
}
fprintf(f, "# environment variables:\n");
u32 s_afl_env = (u32)sizeof(afl_environment_variables) /
sizeof(afl_environment_variables[0]) -
@ -335,13 +318,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
snprintf(fn_tmp, PATH_MAX, "%s/.fuzzer_stats_tmp", afl->out_dir);
snprintf(fn_final, PATH_MAX, "%s/fuzzer_stats", afl->out_dir);
f = create_ffile(fn_tmp, afl->perm);
if (afl->chown_needed) {
if (chown(fn_tmp, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
}
f = create_ffile(fn_tmp);
/* Keep last values in case we're called from another context
where exec/sec stats and such are not readily available. */

View File

@ -602,49 +602,6 @@ int main(int argc, char **argv_orig, char **envp) {
if (debug) { afl->fsrv.debug = true; }
read_afl_environment(afl, envp);
if (afl->shm.map_size) { afl->fsrv.map_size = afl->shm.map_size; }
if (afl->afl_env.afl_forksrv_uid_set) {
afl->fsrv.uid_set = 1;
afl->fsrv.uid = afl->afl_env.afl_forksrv_uid;
}
if (afl->afl_env.afl_forksrv_gid_set) {
afl->fsrv.gid_set = 1;
afl->fsrv.gid = afl->afl_env.afl_forksrv_gid;
afl->fsrv.nb_supl_gids = afl->afl_env.afl_forksrv_nb_supl_gids;
afl->fsrv.supl_gids = afl->afl_env.afl_forksrv_supl_gids;
}
if (afl->fsrv.uid_set) {
/* If the UID is modified, allow group to open files and dirs */
afl->perm = DEFAULT_PERMISSION | 0060;
afl->fsrv.perm = afl->perm;
afl->dir_perm = DEFAULT_DIRS_PERMISSION | 0070;
/* Ensure permissions will be really set*/
umask(~(afl->perm | afl->dir_perm));
/* If the GID is also modified, then change the group of files and dirs */
if (afl->fsrv.gid_set) {
afl->chown_needed = 1;
afl->fsrv.chown_needed = 1;
}
} else {
afl->perm = DEFAULT_PERMISSION;
afl->fsrv.perm = afl->perm;
afl->dir_perm = DEFAULT_DIRS_PERMISSION;
}
exit_1 = !!afl->afl_env.afl_bench_just_one;
SAYF(cCYA "afl-fuzz" VERSION cRST
@ -1545,9 +1502,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->is_main_node == 1 && afl->schedule != FAST &&
afl->schedule != EXPLORE) {
WARNF(
"When using -M, it is recommended to use only fast or explore -p power "
"schedules");
FATAL("-M is compatible only with fast and explore -p power schedules");
}
@ -1790,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));
}
@ -2352,7 +2307,11 @@ int main(int argc, char **argv_orig, char **envp) {
u64 target_hash = get_binary_hash(afl->fsrv.target_path);
#endif
if (!target_hash || prev_target_hash != target_hash) {
if ((!target_hash || prev_target_hash != target_hash)
#ifdef __linux__
|| (afl->fsrv.nyx_mode && target_hash == 0)
#endif
) {
ACTF("Target binary is different, cannot perform FAST RESUME!");
@ -2543,15 +2502,35 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->non_instrumented_mode || afl->fsrv.qemu_mode ||
afl->fsrv.frida_mode || afl->fsrv.cs_mode || afl->unicorn_mode) {
u32 old_map_size = map_size;
map_size = afl->fsrv.real_map_size = afl->fsrv.map_size = MAP_SIZE;
afl_resize_map_buffers(afl, map_size, MAP_SIZE);
afl->virgin_bits = ck_realloc(afl->virgin_bits, map_size);
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, map_size);
afl->virgin_crash = ck_realloc(afl->virgin_crash, map_size);
afl->var_bytes = ck_realloc(afl->var_bytes, map_size);
afl->top_rated = ck_realloc(afl->top_rated, map_size * sizeof(void *));
afl->clean_trace = ck_realloc(afl->clean_trace, map_size);
afl->clean_trace_custom = ck_realloc(afl->clean_trace_custom, map_size);
afl->first_trace = ck_realloc(afl->first_trace, map_size);
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, map_size);
if (old_map_size < map_size) {
memset(afl->var_bytes + old_map_size, 0, map_size - old_map_size);
memset(afl->top_rated + old_map_size, 0, map_size - old_map_size);
memset(afl->clean_trace + old_map_size, 0, map_size - old_map_size);
memset(afl->clean_trace_custom + old_map_size, 0,
map_size - old_map_size);
memset(afl->first_trace + old_map_size, 0, map_size - old_map_size);
memset(afl->map_tmp_buf + old_map_size, 0, map_size - old_map_size);
}
}
afl->argv = use_argv;
afl->fsrv.trace_bits =
afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->non_instrumented_mode,
afl->perm, afl->chown_needed ? afl->fsrv.gid : -1);
afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->non_instrumented_mode);
if (!afl->non_instrumented_mode && !afl->fsrv.qemu_mode &&
!afl->unicorn_mode && !afl->fsrv.frida_mode && !afl->fsrv.cs_mode &&
@ -2573,14 +2552,37 @@ int main(int argc, char **argv_orig, char **envp) {
if (map_size < new_map_size) {
OKF("Re-initializing maps to %u bytes", new_map_size);
afl_resize_map_buffers(afl, map_size, new_map_size);
u32 old_map_size = map_size;
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
afl->var_bytes = ck_realloc(afl->var_bytes, new_map_size);
afl->top_rated =
ck_realloc(afl->top_rated, new_map_size * sizeof(void *));
afl->clean_trace = ck_realloc(afl->clean_trace, new_map_size);
afl->clean_trace_custom =
ck_realloc(afl->clean_trace_custom, new_map_size);
afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
if (old_map_size < new_map_size) {
memset(afl->var_bytes + old_map_size, 0, new_map_size - old_map_size);
memset(afl->top_rated + old_map_size, 0, new_map_size - old_map_size);
memset(afl->clean_trace + old_map_size, 0, new_map_size - old_map_size);
memset(afl->clean_trace_custom + old_map_size, 0,
new_map_size - old_map_size);
memset(afl->first_trace + old_map_size, 0, new_map_size - old_map_size);
memset(afl->map_tmp_buf + old_map_size, 0, new_map_size - old_map_size);
}
afl_fsrv_kill(&afl->fsrv);
afl_shm_deinit(&afl->shm);
afl->fsrv.map_size = new_map_size;
afl->fsrv.trace_bits =
afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode,
afl->perm, afl->chown_needed ? afl->fsrv.gid : -1);
afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode);
setenv("AFL_NO_AUTODICT", "1", 1); // loaded already
afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
afl->afl_env.afl_debug_child);
@ -2635,6 +2637,7 @@ int main(int argc, char **argv_orig, char **envp) {
*/
afl->san_fsrvs[i].trace_bits = ck_alloc(
afl->fsrv.map_size + 8); /* One more u64 according to afl_shm_init*/
afl->san_fsrvs[i].map_size = afl->fsrv.map_size;
afl->san_fsrvs[i].san_but_not_instrumented = 1;
afl->san_fsrvs[i].cs_mode = afl->fsrv.cs_mode;
@ -2644,6 +2647,10 @@ int main(int argc, char **argv_orig, char **envp) {
afl->san_fsrvs[i].target_path = afl->san_binary[i];
afl->san_fsrvs[i].init_child_func = sanfuzz_exec_child;
afl->san_fsrvs[i].child_kill_signal =
afl->fsrv.child_kill_signal; // I believe cmplog also needs this.
afl->san_fsrvs[i].fsrv_kill_signal = afl->fsrv.fsrv_kill_signal;
if ((map_size <= DEFAULT_SHMEM_SIZE ||
afl->san_fsrvs[i].map_size < map_size) &&
!afl->non_instrumented_mode && !afl->fsrv.qemu_mode &&
@ -2666,7 +2673,18 @@ int main(int argc, char **argv_orig, char **envp) {
OKF("Re-initializing maps to %u bytes due to SAN instrumented binary",
new_map_size);
afl_resize_map_buffers(afl, map_size, new_map_size);
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
afl->var_bytes = ck_realloc(afl->var_bytes, new_map_size);
afl->top_rated =
ck_realloc(afl->top_rated, new_map_size * sizeof(void *));
afl->clean_trace = ck_realloc(afl->clean_trace, new_map_size);
afl->clean_trace_custom =
ck_realloc(afl->clean_trace_custom, new_map_size);
afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
afl_fsrv_kill(&afl->fsrv);
afl_fsrv_kill(&afl->san_fsrvs[i]);
@ -2677,8 +2695,7 @@ int main(int argc, char **argv_orig, char **envp) {
setenv("AFL_NO_AUTODICT", "1", 1); // loaded already
afl->fsrv.trace_bits =
afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode,
afl->perm, afl->chown_needed ? afl->fsrv.gid : -1);
afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode);
ck_free(afl->san_fsrvs[i].trace_bits);
afl->san_fsrvs[i].trace_bits = ck_alloc(afl->fsrv.map_size + 8);
afl->san_fsrvs[i].map_size = afl->fsrv.map_size;
@ -2733,7 +2750,31 @@ int main(int argc, char **argv_orig, char **envp) {
if (map_size < new_map_size) {
OKF("Re-initializing maps to %u bytes due cmplog", new_map_size);
afl_resize_map_buffers(afl, map_size, new_map_size);
u32 old_map_size = map_size;
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
afl->var_bytes = ck_realloc(afl->var_bytes, new_map_size);
afl->top_rated =
ck_realloc(afl->top_rated, new_map_size * sizeof(void *));
afl->clean_trace = ck_realloc(afl->clean_trace, new_map_size);
afl->clean_trace_custom =
ck_realloc(afl->clean_trace_custom, new_map_size);
afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
if (old_map_size < new_map_size) {
memset(afl->var_bytes + old_map_size, 0, new_map_size - old_map_size);
memset(afl->top_rated + old_map_size, 0, new_map_size - old_map_size);
memset(afl->clean_trace + old_map_size, 0, new_map_size - old_map_size);
memset(afl->clean_trace_custom + old_map_size, 0,
new_map_size - old_map_size);
memset(afl->first_trace + old_map_size, 0, new_map_size - old_map_size);
memset(afl->map_tmp_buf + old_map_size, 0, new_map_size - old_map_size);
}
afl_fsrv_kill(&afl->fsrv);
afl_fsrv_kill(&afl->cmplog_fsrv);
@ -2744,8 +2785,7 @@ int main(int argc, char **argv_orig, char **envp) {
setenv("AFL_NO_AUTODICT", "1", 1); // loaded already
afl->fsrv.trace_bits =
afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode,
afl->perm, afl->chown_needed ? afl->fsrv.gid : -1);
afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode);
afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits;
afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
afl->afl_env.afl_debug_child);
@ -2962,8 +3002,6 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->stop_soon) { goto stop_fuzzing; }
if (!afl->in_place_resume) { check_sync_fuzzers(afl); }
/* Woop woop woop */
if (!afl->not_on_tty) {
@ -3495,17 +3533,8 @@ stop_fuzzing:
if ((fr_fd = ZLIBOPEN(fr, "wb9")) != NULL) {
#else
if ((fr_fd = open(fr, O_WRONLY | O_TRUNC | O_CREAT, afl->perm)) >= 0) {
if (afl->chown_needed) {
if (fchown(fr_fd, -1, afl->fsrv.gid) == -1) {
PFATAL("fchown() failed");
}
}
if ((fr_fd = open(fr, O_WRONLY | O_TRUNC | O_CREAT, DEFAULT_PERMISSION)) >=
0) {
#endif

View File

@ -71,7 +71,6 @@ void afl_shm_deinit(sharedmem_t *shm) {
if (shm->shmemfuzz_mode) {
unsetenv(SHM_FUZZ_ENV_VAR);
unsetenv(SHM_FUZZ_MAP_SIZE_ENV_VAR);
} else {
@ -142,8 +141,7 @@ void afl_shm_deinit(sharedmem_t *shm) {
*/
u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
unsigned char non_instrumented_mode, mode_t permission,
int gid) {
unsigned char non_instrumented_mode) {
shm->map_size = 0;
@ -182,13 +180,7 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
shm->g_shm_fd =
shm_create_largepage(shm->g_shm_file_path, shmflags, i,
SHM_LARGEPAGE_ALLOC_DEFAULT, permission);
if (gid != -1 && shm->g_shm_fd != -1) {
if (fchown(shm->g_shm_fd, -1, gid) == -1) { PFATAL("fchown() failed"); }
}
SHM_LARGEPAGE_ALLOC_DEFAULT, DEFAULT_PERMISSION);
}
@ -200,13 +192,7 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
if (shm->g_shm_fd == -1) {
shm->g_shm_fd =
shm_open(shm->g_shm_file_path, shmflags | O_CREAT, permission);
if (gid != -1 && shm->g_shm_fd != -1) {
if (fchown(shm->g_shm_fd, -1, gid) == -1) { PFATAL("fchown() failed"); }
}
shm_open(shm->g_shm_file_path, shmflags | O_CREAT, DEFAULT_PERMISSION);
}
@ -247,14 +233,10 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
getpid(), random());
/* create the shared memory segment as if it was a file */
shm->cmplog_g_shm_fd = shm_open(shm->cmplog_g_shm_file_path,
O_CREAT | O_RDWR | O_EXCL, permission);
shm->cmplog_g_shm_fd =
shm_open(shm->cmplog_g_shm_file_path, O_CREAT | O_RDWR | O_EXCL,
DEFAULT_PERMISSION);
if (shm->cmplog_g_shm_fd == -1) { PFATAL("shm_open() failed"); }
if (gid != -1) {
if (fchown(shm->g_shm_fd, -1, gid) == -1) { PFATAL("fchown() failed"); }
}
/* configure the size of the shared memory segment */
if (ftruncate(shm->cmplog_g_shm_fd, sizeof(struct cmp_map))) {
@ -290,41 +272,23 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
}
#else
u8 *shm_str;
struct shmid_ds shmid_ds;
u8 *shm_str;
// for qemu+unicorn we have to increase by 8 to account for potential
// compcov map overwrite
shm->shm_id =
shmget(IPC_PRIVATE, map_size == MAP_SIZE ? map_size + 8 : map_size,
IPC_CREAT | IPC_EXCL | permission);
IPC_CREAT | IPC_EXCL | DEFAULT_PERMISSION);
if (shm->shm_id < 0) {
PFATAL("shmget() failed, try running afl-system-config");
}
if (gid != -1) {
if (shmctl(shm->shm_id, IPC_STAT, &shmid_ds) == -1) {
PFATAL("shmctl(IPC_STAT) failed");
}
shmid_ds.shm_perm.gid = (gid_t)gid;
if (shmctl(shm->shm_id, IPC_SET, &shmid_ds) == -1) {
PFATAL("shmctl(IPC_SET) failed");
}
}
if (shm->cmplog_mode) {
shm->cmplog_shm_id = shmget(IPC_PRIVATE, sizeof(struct cmp_map),
IPC_CREAT | IPC_EXCL | permission);
IPC_CREAT | IPC_EXCL | DEFAULT_PERMISSION);
if (shm->cmplog_shm_id < 0) {
@ -333,23 +297,6 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
}
if (gid != -1) {
if (shmctl(shm->cmplog_shm_id, IPC_STAT, &shmid_ds) == -1) {
PFATAL("shmctl(IPC_STAT) failed");
}
shmid_ds.shm_perm.gid = (gid_t)gid;
if (shmctl(shm->cmplog_shm_id, IPC_SET, &shmid_ds) == -1) {
PFATAL("shmctl(IPC_SET) failed");
}
}
}
if (!non_instrumented_mode) {

View File

@ -714,8 +714,61 @@ static void handle_stop_sig(int sig) {
static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
char *afl_preload;
char *frida_afl_preload = NULL;
set_sanitizer_defaults();
afl_fsrv_setup_preload(fsrv, argv[0]);
if (get_afl_env("AFL_PRELOAD")) {
if (fsrv->qemu_mode) {
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
} else if (fsrv->frida_mode) {
afl_preload = getenv("AFL_PRELOAD");
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
if (afl_preload) {
frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
} else {
frida_afl_preload = alloc_printf("%s", frida_binary);
}
ck_free(frida_binary);
setenv("LD_PRELOAD", frida_afl_preload, 1);
#ifdef __APPLE__
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
#endif
} else {
/* CoreSight mode uses the default behavior. */
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
#ifdef __APPLE__
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
#endif
}
} else if (fsrv->frida_mode) {
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
setenv("LD_PRELOAD", frida_binary, 1);
#ifdef __APPLE__
setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
#endif
ck_free(frida_binary);
}
if (frida_afl_preload) { ck_free(frida_afl_preload); }
}
@ -1348,7 +1401,7 @@ int main(int argc, char **argv_orig, char **envp) {
fsrv->target_path = find_binary(argv[optind]);
#endif
fsrv->trace_bits = afl_shm_init(&shm, map_size, 0, DEFAULT_PERMISSION, -1);
fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
if (!quiet_mode) {
@ -1487,16 +1540,9 @@ int main(int argc, char **argv_orig, char **envp) {
shm_fuzz->cmplog_mode = 0;
atexit(at_exit_handler);
size_t shm_fuzz_map_size = SHM_FUZZ_MAP_SIZE_DEFAULT;
u8 *map = afl_shm_init(shm_fuzz, SHM_FUZZ_MAP_SIZE_DEFAULT, 1,
DEFAULT_PERMISSION, -1);
u8 *map = afl_shm_init(shm_fuzz, MAX_FILE + sizeof(u32), 1);
shm_fuzz->shmemfuzz_mode = true;
if (!map) { FATAL("BUG: Zero return from afl_shm_init."); }
u8 *shm_fuzz_map_size_str = alloc_printf("%zu", shm_fuzz_map_size);
setenv(SHM_FUZZ_MAP_SIZE_ENV_VAR, shm_fuzz_map_size_str, 1);
ck_free(shm_fuzz_map_size_str);
#ifdef USEMMAP
setenv(SHM_FUZZ_ENV_VAR, shm_fuzz->g_shm_file_path, 1);
#else
@ -1543,7 +1589,7 @@ int main(int argc, char **argv_orig, char **envp) {
// only reinitialize when it makes sense
if (map_size < new_map_size ||
(new_map_size < map_size && map_size - new_map_size > MAP_SIZE)) {
(new_map_size > map_size && new_map_size - map_size > MAP_SIZE)) {
if (!be_quiet)
ACTF("Acquired new map size for target: %u bytes\n", new_map_size);
@ -1551,8 +1597,7 @@ int main(int argc, char **argv_orig, char **envp) {
afl_shm_deinit(&shm);
afl_fsrv_kill(fsrv);
fsrv->map_size = new_map_size;
fsrv->trace_bits =
afl_shm_init(&shm, new_map_size, 0, DEFAULT_PERMISSION, -1);
fsrv->trace_bits = afl_shm_init(&shm, new_map_size, 0);
}

View File

@ -899,7 +899,9 @@ static void handle_stop_sig(int sig) {
static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
u8 *x;
u8 *x;
char *afl_preload;
char *frida_afl_preload = NULL;
fsrv->dev_null_fd = open("/dev/null", O_RDWR);
if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
@ -943,7 +945,57 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
}
set_sanitizer_defaults();
afl_fsrv_setup_preload(fsrv, argv[0]);
if (get_afl_env("AFL_PRELOAD")) {
if (fsrv->qemu_mode) {
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
} else if (fsrv->frida_mode) {
afl_preload = getenv("AFL_PRELOAD");
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
if (afl_preload) {
frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
} else {
frida_afl_preload = alloc_printf("%s", frida_binary);
}
ck_free(frida_binary);
setenv("LD_PRELOAD", frida_afl_preload, 1);
#ifdef __APPLE__
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
#endif
} else {
/* CoreSight mode uses the default behavior. */
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
#ifdef __APPLE__
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
#endif
}
} else if (fsrv->frida_mode) {
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
setenv("LD_PRELOAD", frida_binary, 1);
#ifdef __APPLE__
setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
#endif
ck_free(frida_binary);
}
if (frida_afl_preload) { ck_free(frida_afl_preload); }
}
@ -1332,7 +1384,7 @@ int main(int argc, char **argv_orig, char **envp) {
fsrv->target_path = find_binary(argv[optind]);
#endif
fsrv->trace_bits = afl_shm_init(&shm, map_size, 0, DEFAULT_PERMISSION, -1);
fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
detect_file_args(argv + optind, out_file, &fsrv->use_stdin);
signal(SIGALRM, kill_child);
@ -1429,17 +1481,9 @@ int main(int argc, char **argv_orig, char **envp) {
/* initialize cmplog_mode */
shm_fuzz->cmplog_mode = 0;
size_t shm_fuzz_map_size = SHM_FUZZ_MAP_SIZE_DEFAULT;
u8 *map = afl_shm_init(shm_fuzz, SHM_FUZZ_MAP_SIZE_DEFAULT, 1,
DEFAULT_PERMISSION, -1);
u8 *map = afl_shm_init(shm_fuzz, MAX_FILE + sizeof(u32), 1);
shm_fuzz->shmemfuzz_mode = 1;
if (!map) { FATAL("BUG: Zero return from afl_shm_init."); }
u8 *shm_fuzz_map_size_str = alloc_printf("%zu", shm_fuzz_map_size);
setenv(SHM_FUZZ_MAP_SIZE_ENV_VAR, shm_fuzz_map_size_str, 1);
ck_free(shm_fuzz_map_size_str);
#ifdef USEMMAP
setenv(SHM_FUZZ_ENV_VAR, shm_fuzz->g_shm_file_path, 1);
#else
@ -1503,8 +1547,7 @@ int main(int argc, char **argv_orig, char **envp) {
afl_shm_deinit(&shm);
afl_fsrv_kill(fsrv);
fsrv->map_size = new_map_size;
fsrv->trace_bits =
afl_shm_init(&shm, new_map_size, 0, DEFAULT_PERMISSION, -1);
fsrv->trace_bits = afl_shm_init(&shm, new_map_size, 0);
afl_fsrv_start(fsrv, use_argv, &stop_soon,
(get_afl_env("AFL_DEBUG_CHILD") ||
get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))

View File

@ -49,11 +49,7 @@ int main(int argc, char **argv) {
if ((cnt = read(fd, buf, sizeof(buf) - 1)) < 1) {
printf("Hum?\n");
#ifdef EXIT_AT_END
exit(1);
#else
return 1;
#endif
}
@ -81,10 +77,6 @@ int main(int argc, char **argv) {
}
#ifdef EXIT_AT_END
exit(0);
#endif
return 0;
}

View File

@ -17,9 +17,9 @@ test -z "" 2>/dev/null || { echo Error: test command not found ; exit 1 ; }
GREP=`type grep > /dev/null 2>&1 && echo OK`
test "$GREP" = OK || { echo Error: grep command not found ; exit 1 ; }
echo foobar | grep -qE 'asd|oob' 2>/dev/null || { echo Error: grep command does not support -q and/or -E option ; exit 1 ; }
test -e ./test-all.sh || cd $(dirname "$0") || exit 1
test -e ./test-all.sh || cd $(dirname $0) || exit 1
test -e ./test-all.sh || { echo Error: you must be in the test/ directory ; exit 1 ; }
export AFL_PATH="$(pwd)/.."
export AFL_PATH=`pwd`/..
export AFL_TRY_AFFINITY=1 # workaround for travis that fails for no avail cores
echo 1 > test.1
@ -59,7 +59,7 @@ $ECHO \\101 2>&1 | grep -qE '^A' || {
$ECHO "\\101" 2>&1 | grep -qE '^A' || ECHO=
}
}
test -z "$ECHO" && { echo Error: printf command does not support octal character codes ; exit 1 ; }
test -z "$ECHO" && { printf Error: printf command does not support octal character codes ; exit 1 ; }
export AFL_EXIT_WHEN_DONE=1
export AFL_EXIT_ON_TIME=60
@ -109,10 +109,12 @@ test -n "$TRAVIS_OS_NAME" && {
# on OpenBSD we need to work with llvm from /usr/local/bin
test -e /usr/local/bin/opt && {
test "$(uname -s)" = 'Darwin' || export PATH="/usr/local/bin:${PATH}"
test `uname -s` = 'Darwin' || export PATH="/usr/local/bin:${PATH}"
}
AFL_COMPILER=afl-clang-fast
SYS=`uname -m`
GREY="\\033[1;90m"
BLUE="\\033[1;94m"
GREEN="\\033[0;32m"
@ -120,13 +122,6 @@ RED="\\033[0;31m"
YELLOW="\\033[1;93m"
RESET="\\033[0m"
if test -n "$CPU_TARGET"; then
$ECHO "${RESET}${GREY}[*] Using environment variable CPU_TARGET=$CPU_TARGET for SYS"
SYS="$CPU_TARGET"
else
SYS=$(uname -m)
fi
MEM_LIMIT=none
export PATH="${PATH}:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin"

View File

@ -13,17 +13,10 @@ test -z "$AFL_CC" && {
fi
}
if test -n "$CPU_TARGET_CC"; then
$ECHO "$GREY[*] Using $CPU_TARGET_CC as compiler for target"
else
CPU_TARGET_CC=cc
fi
test -e ../afl-qemu-trace && {
${CPU_TARGET_CC} -pie -fPIE -o test-instr ../test-instr.c
${CPU_TARGET_CC} -o test-compcov test-compcov.c
${CPU_TARGET_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 && {
cc -pie -fPIE -o test-instr ../test-instr.c
cc -o test-compcov test-compcov.c
test -e test-instr -a -e test-compcov && {
{
mkdir -p in
echo 00000 > in/in
@ -111,7 +104,7 @@ test -e ../afl-qemu-trace && {
$ECHO "$YELLOW[-] not an intel or arm platform, cannot test qemu_mode cmplog"
}
test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" -o "$SYS" = "mipsel" && {
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, this will take approx 10 seconds"
{
IS_STATIC=""
@ -120,16 +113,11 @@ test -e ../afl-qemu-trace && {
if file test-instr | grep -q "32-bit"; then
# for 32-bit reduce 8 nibbles to the lower 7 nibbles
ADDR_LOWER_PART=`nm test-instr | grep "T main" | awk '{print $1}' | sed 's/^.//'`
export AFL_QEMU_PERSISTENT_ADDR=`expr 0x4${ADDR_LOWER_PART}`
elif [ "$SYS" = "aarch64" ]; then
# for aarch64 reduce 16 nibbles to the lower 8 nibbles
ADDR_LOWER_PART=`nm test-instr | grep "T main" | awk '{print $1}' | sed 's/^........//'`
export AFL_QEMU_PERSISTENT_ADDR=`expr 0x55${ADDR_LOWER_PART}`
else
# for x64 reduce 16 nibbles to the lower 9 nibbles
# for 64-bit reduce 16 nibbles to the lower 9 nibbles
ADDR_LOWER_PART=`nm test-instr | grep "T main" | awk '{print $1}' | sed 's/^.......//'`
export AFL_QEMU_PERSISTENT_ADDR=`expr 0x4${ADDR_LOWER_PART}`
fi
export AFL_QEMU_PERSISTENT_ADDR=`expr 0x4${ADDR_LOWER_PART}`
}
test -n "$IS_STATIC" && {
export AFL_QEMU_PERSISTENT_ADDR=0x`nm test-instr | grep "T main" | awk '{print $1}'`
@ -161,66 +149,9 @@ test -e ../afl-qemu-trace && {
$ECHO "$RED[!] afl-fuzz is not working correctly with persistent qemu_mode"
CODE=1
}
rm -rf out errors
} || {
$ECHO "$YELLOW[-] not an intel or arm platform, cannot test persistent qemu_mode"
}
test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" -o "$SYS" = "mipsel" && {
$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/^.//'`
export AFL_QEMU_PERSISTENT_ADDR=`expr 0x4${ADDR_LOWER_PART}`
elif [ "$SYS" = "aarch64" ]; then
# for aarch64 reduce 16 nibbles to the lower 8 nibbles
ADDR_LOWER_PART=`nm test-instr-exit-at-end | grep "T main" | awk '{print $1}' | sed 's/^........//'`
export AFL_QEMU_PERSISTENT_ADDR=`expr 0x55${ADDR_LOWER_PART}`
else
# for x64 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/^.......//'`
export AFL_QEMU_PERSISTENT_ADDR=`expr 0x4${ADDR_LOWER_PART}`
fi
}
test -n "$IS_STATIC" && {
export AFL_QEMU_PERSISTENT_ADDR=0x`nm test-instr-exit-at-end | grep "T main" | awk '{print $1}'`
}
export AFL_QEMU_PERSISTENT_GPR=1
$ECHO "Info: AFL_QEMU_PERSISTENT_ADDR=$AFL_QEMU_PERSISTENT_ADDR <= $(nm test-instr-exit-at-end | grep "T main" | awk '{print $1}')"
export AFL_QEMU_PERSISTENT_EXITS=1
../afl-fuzz -m ${MEM_LIMIT} -V07 -Q -i in -o out -- ./test-instr-exit-at-end
echo status "$?"
unset AFL_QEMU_PERSISTENT_ADDR
unset AFL_QEMU_PERSISTENT_GPR
unset AFL_QEMU_PERSISTENT_EXITS
} >>errors 2>&1
test -n "$( ls out/default/queue/id:000000* 2>/dev/null )" && {
$ECHO "$GREEN[+] afl-fuzz is working correctly with persistent qemu_mode and AFL_QEMU_PERSISTENT_EXITS"
RUNTIMEP_EXIT=`grep execs_done out/default/fuzzer_stats | awk '{print$3}'`
test -n "$RUNTIME" -a -n "$RUNTIMEP_EXIT" && {
DIFF=`expr $RUNTIMEP_EXIT / $RUNTIME`
test "$DIFF" -gt 1 && { # must be at least twice as fast
$ECHO "$GREEN[+] persistent qemu_mode with AFL_QEMU_PERSISTENT_EXITS was noticeable faster than standard qemu_mode"
} || {
$ECHO "$YELLOW[-] persistent qemu_mode with AFL_QEMU_PERSISTENT_EXITS was not noticeable faster than standard qemu_mode"
}
} || {
$ECHO "$YELLOW[-] we got no data on executions performed? weird!"
}
} || {
echo CUT------------------------------------------------------------------CUT
cat errors
echo CUT------------------------------------------------------------------CUT
$ECHO "$RED[!] afl-fuzz is not working correctly with persistent qemu_mode and AFL_QEMU_PERSISTENT_EXITS"
CODE=1
}
rm -rf in out errors
} || {
$ECHO "$YELLOW[-] not an intel or arm platform, cannot test persistent qemu_mode with AFL_QEMU_PERSISTENT_EXITS"
$ECHO "$YELLOW[-] not an intel or arm platform, cannot test persistent qemu_mode"
}
test -e ../qemu_mode/unsigaction/unsigaction32.so && {
@ -281,7 +212,7 @@ test -e ../afl-qemu-trace && {
CODE=1
}
rm -f test-instr test-compcov test-instr-exit-at-end
rm -f test-instr test-compcov
} || {
$ECHO "$YELLOW[-] qemu_mode is not compiled, cannot test"
INCOMPLETE=1

View File

@ -10,7 +10,7 @@ test -s ../unicorn_mode/unicornafl/build/libunicornafl.a && {
export AFL_DEBUG_CHILD=1
# some python version should be available now
PYTHONS="`command -v python3` `command -v python`"
PYTHONS="`command -v python3` `command -v python` `command -v python2`"
EASY_INSTALL_FOUND=0
for PYTHON in $PYTHONS ; do

View File

@ -65,7 +65,7 @@ if [ ! -f "../afl-showmap" ]; then
fi
PYTHONBIN=`command -v python3 || command -v python || echo python3`
PYTHONBIN=`command -v python3 || command -v python || command -v python2 || echo python3`
MAKECMD=make
TARCMD=tar
@ -116,7 +116,7 @@ for i in $PYTHONBIN automake autoconf git $MAKECMD $TARCMD; do
done
# some python version should be available now
PYTHONS="`command -v python3` `command -v python`"
PYTHONS="`command -v python3` `command -v python` `command -v python2`"
PIP_FOUND=0
for PYTHON in $PYTHONS ; do

View File

@ -179,17 +179,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
unlink(out_file);
fsrv->out_fd = open(out_file, O_RDWR | O_CREAT | O_EXCL, fsrv->perm);
if (fsrv->chown_needed) {
if (fchown(fsrv->out_fd, -1, fsrv->gid) == -1) {
PFATAL("fchown() failed");
}
}
fsrv->out_fd = open(out_file, O_RDWR | O_CREAT | O_EXCL, 0600);
if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); }
@ -536,8 +526,7 @@ int main(int argc, char **argv_orig, char **envp) {
check_environment_vars(envp);
sharedmem_t shm = {0};
fsrv->trace_bits = afl_shm_init(&shm, map_size, 0, fsrv->perm,
fsrv->chown_needed ? fsrv->gid : -1);
fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
in_data = afl_realloc((void **)&in_data, 65536);
if (unlikely(!in_data)) { PFATAL("Alloc"); }

View File

@ -199,9 +199,9 @@ static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
}
static void __afl_end_testcase(int status) {
static void __afl_end_testcase(void) {
if (!status) { status = -1; }
int status = 0xffffff;
if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1);
@ -241,8 +241,7 @@ int main(int argc, char *argv[]) {
}
/* report the test case is done and wait for the next */
// set the value to XXX (need to check) to report a crash
__afl_end_testcase(0);
__afl_end_testcase();
}

View File

@ -18,8 +18,7 @@ ifneq "" "$(LLVM_BINDIR)"
endif
endif
CFLAGS := -O3 -funroll-loops -g -fPIC -fno-lto
AR ?= ar
CFLAGS := -O3 -funroll-loops -g -fPIC
ifdef IOS_SDK_PATH
CFLAGS += -isysroot $(IOS_SDK_PATH)
@ -31,7 +30,7 @@ aflpp_driver.o: aflpp_driver.c
-$(CC) -I. -I../../include $(CFLAGS) -c aflpp_driver.c
libAFLDriver.a: aflpp_driver.o
@$(AR) rc libAFLDriver.a aflpp_driver.o
@ar rc libAFLDriver.a aflpp_driver.o
@cp -vf libAFLDriver.a ../../
debug:
@ -39,13 +38,13 @@ debug:
$(CC) -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c
#$(CC) -S -emit-llvm -Wno-deprecated -I../../include $(CFLAGS) -D_DEBUG=\"1\" -c -o afl-performance.ll ../../src/afl-performance.c
#$(CC) -S -emit-llvm -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c
$(AR) rc libAFLDriver.a afl-performance.o aflpp_driver.o
ar rc libAFLDriver.a afl-performance.o aflpp_driver.o
aflpp_qemu_driver.o: aflpp_qemu_driver.c
-$(CC) $(CFLAGS) -O0 -funroll-loops -c aflpp_qemu_driver.c
libAFLQemuDriver.a: aflpp_qemu_driver.o
@-$(AR) rc libAFLQemuDriver.a aflpp_qemu_driver.o
@-ar rc libAFLQemuDriver.a aflpp_qemu_driver.o
@-cp -vf libAFLQemuDriver.a ../../
aflpp_qemu_driver_hook.so: aflpp_qemu_driver_hook.o

View File

@ -64,15 +64,6 @@ extern "C" {
#include "hash.h"
#endif
#if defined(__APPLE__) && defined(__MACH__)
#define SECTION_RODATA \
__attribute__((used, retain)) __attribute__((section("__RODATA,__" \
"rodata")))
#else
#define SECTION_RODATA \
__attribute__((used, retain)) __attribute__((section(".rodata")))
#endif
// AFL++ shared memory fuzz cases
int __afl_sharedmem_fuzzing = 1;
extern unsigned int *__afl_fuzz_len;
@ -115,11 +106,14 @@ __attribute__((weak)) void __asan_unpoison_memory_region(
__attribute__((weak)) void *__asan_region_is_poisoned(void *beg, size_t size);
// Notify AFL about persistent mode.
SECTION_RODATA static const char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
int __afl_persistent_loop(unsigned int);
__attribute__((section(".rodata"), used,
retain)) static const char AFL_PERSISTENT[] =
"##SIG_AFL_PERSISTENT##";
int __afl_persistent_loop(unsigned int);
// Notify AFL about deferred forkserver.
SECTION_RODATA static const char AFL_DEFER_FORKSVR[] =
__attribute__((section(".rodata"), used,
retain)) static const char AFL_DEFER_FORKSVR[] =
"##SIG_AFL_DEFER_FORKSRV##";
void __afl_manual_init();

View File

@ -33,7 +33,7 @@ def ensure_dir(dir):
def parse_args():
parser = argparse.ArgumentParser(
description=(
"Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python3 thisfile.py outdir str.txt"
"Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt"
)
)

View File

@ -17,7 +17,7 @@ from binascii import unhexlify
def parse_args():
parser = argparse.ArgumentParser(
description=(
"Helper - Specify input file to analysis and output folder to save corpdirus for constants in the overall project ------- Example usage : python3 thisfile.py outdir o.txt"
"Helper - Specify input file to analysis and output folder to save corpdirus for constants in the overall project ------- Example usage : python2 thisfile.py outdir o.txt"
)
)
parser.add_argument(
@ -25,7 +25,7 @@ def parse_args():
)
parser.add_argument(
"infile",
help="Specify file output of codeql analysis - ex. ooo-hex.txt, analysis take place on this file, example : python3 thisfile.py outdir out.txt",
help="Specify file output of codeql analysis - ex. ooo-hex.txt, analysis take place on this file, example : python2 thisfile.py outdir out.txt",
)
return parser.parse_args()

View File

@ -25,7 +25,7 @@ def ensure_dir(dir):
def parse_args():
parser = argparse.ArgumentParser(
description=(
"Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python3 thisfile.py outdir str.txt"
"Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt"
)
)
parser.add_argument(
@ -33,7 +33,7 @@ def parse_args():
)
parser.add_argument(
"infile",
help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python3 thisfile.py outdir strings.txt",
help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt",
)
return parser.parse_args()

View File

@ -25,7 +25,7 @@ def ensure_dir(dir):
def parse_args():
parser = argparse.ArgumentParser(
description=(
"Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python3 thisfile.py outdir str.txt"
"Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt"
)
)
parser.add_argument(
@ -33,7 +33,7 @@ def parse_args():
)
parser.add_argument(
"infile",
help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python3 thisfile.py outdir strings.txt",
help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt",
)
return parser.parse_args()

View File

@ -25,7 +25,7 @@ def ensure_dir(dir):
def parse_args():
parser = argparse.ArgumentParser(
description=(
"Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python3 thisfile.py outdir str.txt"
"Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt"
)
)
parser.add_argument(
@ -33,7 +33,7 @@ def parse_args():
)
parser.add_argument(
"infile",
help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python3 thisfile.py outdir strings.txt",
help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt",
)
return parser.parse_args()

View File

@ -25,7 +25,7 @@ def ensure_dir(dir):
def parse_args():
parser = argparse.ArgumentParser(
description=(
"Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python3 thisfile.py outdir str.txt"
"Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt"
)
)
parser.add_argument(
@ -33,7 +33,7 @@ def parse_args():
)
parser.add_argument(
"infile",
help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python3 thisfile.py outdir strings.txt",
help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt",
)
return parser.parse_args()

View File

@ -1,12 +0,0 @@
# For cross compilation modify this as needed
#GLIBC_PATH := /path/to/glibc-2.xx/build/local_install
#CROSS_CFLAGS := -mfloat-abi=soft -nostdlib -I$(GLIBC_PATH)/include -L$(GLIBC_PATH)/lib -Wl,-rpath=/lib -Wl,--dynamic-linker=/lib/ld-linux.so.3
all: libaflppdesock.so
libaflppdesock.so: libaflppdesock.c
$(CC) $(CROSS_CFLAGS) -shared -fPIC -o libaflppdesock.so libaflppdesock.c
clean:
rm -f libaflppdesock.so *~ core

View File

@ -1,46 +0,0 @@
# AFL++ TCP desocket library
Other desocketing solutions:
* https://github.com/zardus/preeny (desock and desock2)
* https://github.com/fkie-cad/libdesock
* https://github.com/zyingp/desockmulti
* https://github.com/vanhauser-thc/network-emulator
If these desocket solutions fail, then this one will likely easily work
for you - alass with slightly lower performance.
And it is easy to extend :-)
## Why might this solution work when others do not?
What makes this desocket library special is that only **only** intercepts
`accept()` calls bound to a specified port. Hence any other network stuff
the application does is still working as expected.
## How to use
`AFL_PRELOAD` this library and use the following environment variables:
* `DESOCK_PORT=8080` - required for intercepting incoming connections for fuzzing - sets the TCP port
* `DESOCK_FORK=1` - intercept and prevent forking
* `DESOCK_CLOSE_EXIT=1` - call _exit() when the desocketed file descriptor is `close`d or `shutdown`ed
* `DESOCK_DEBUG=1` - print debug information to `stderr`
** Internals
Currently the library intercepts the following calls:
```
shutdown
close
fork
accept
accept4
listen
bind
setsockopt
getsockopt
getpeername
getsockname
```
`

View File

@ -1,352 +0,0 @@
/* desocket library by Marc "vanHauser" Heuse <vh@thc.org>
*
* Use this library for fuzzing if preeny's desock and desock2 solutions
* do not work for you - these would provide faster performance.
*
*/
// default: file descriptor 0 for stdin
#define FUZZ_INPUT_FD 0
#include <dlfcn.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static void *handle;
static bool do_fork, do_close, debug, running;
static int port = -1;
static int listen_fd = -1;
struct myin_addr {
unsigned int s_addr; // IPv4 address in network byte order
};
struct mysockaddr {
unsigned short int sin_family; // Address family: AF_INET
unsigned short int sin_port; // Port number (network byte order)
struct myin_addr sin_addr; // Internet address
char sin_zero[8]; // Padding (unused)
};
#define RTLD_LAZY 0x00001
unsigned short int htons(unsigned short int hostshort) {
return (hostshort << 8) | (hostshort >> 8);
}
static void __get_handle() {
if (!(handle = dlopen("libc.so", RTLD_NOW))) {
if (!(handle = dlopen("libc.so.6", RTLD_NOW))) {
if (!(handle = dlopen("libc-orig.so", RTLD_LAZY))) {
if (!(handle = dlopen("cygwin1.dll", RTLD_LAZY))) {
if (!(handle = dlopen("libc.so", RTLD_NOW))) {
fprintf(stderr, "DESOCK: can not find libc!\n");
exit(-1);
}
}
}
}
}
if (getenv("DESOCK_DEBUG")) { debug = true; }
if (getenv("DESOCK_PORT")) { port = atoi(getenv("DESOCK_PORT")); }
if (getenv("DESOCK_FORK")) { do_fork = true; }
if (getenv("DESOCK_CLOSE_EXIT")) { do_close = true; }
if (debug) fprintf(stderr, "DESOCK: initialized!\n");
}
int (*o_shutdown)(int socket, int how);
int shutdown(int socket, int how) {
if (port != -1 && socket == FUZZ_INPUT_FD && running) {
running = false;
if (do_close) {
if (debug) fprintf(stderr, "DESOCK: exiting\n");
_exit(0);
}
}
if (port == -1 && do_close) {
if (debug) fprintf(stderr, "DESOCK: exiting\n");
_exit(0);
}
if (!handle) { __get_handle(); }
if (!o_shutdown) { o_shutdown = dlsym(handle, "shutdown"); }
return o_shutdown(socket, how);
}
int (*o_close)(int socket);
int close(int socket) {
if (port != -1 && socket == FUZZ_INPUT_FD && running) {
running = false;
if (do_close) {
if (debug) fprintf(stderr, "DESOCK: exiting\n");
_exit(0);
}
}
if (listen_fd != -1 && socket == listen_fd) {
if (debug) fprintf(stderr, "DESOCK: close bind\n");
listen_fd = -1;
}
if (!handle) { __get_handle(); }
if (!o_close) { o_close = dlsym(handle, "close"); }
return o_close(socket);
}
int (*o_fork)(void);
int fork() {
if (do_fork) {
if (debug) fprintf(stderr, "DESOCK: fake fork\n");
return 0;
}
if (!handle) { __get_handle(); }
if (!o_fork) { o_fork = dlsym(handle, "fork"); }
return o_fork();
}
int (*o_accept)(int sockfd, struct mysockaddr *addr,
unsigned long int *addrlen);
int accept(int sockfd, struct mysockaddr *addr, unsigned long int *addrlen) {
if (!handle) { __get_handle(); }
if (!o_accept) { o_accept = dlsym(handle, "accept"); }
if (!running && sockfd == listen_fd) {
if (debug) fprintf(stderr, "DESOCK: intercepted accept on %d\n", sockfd);
if (addr && addrlen) {
// we need to fill this!
memset(addr, 0, *addrlen);
addr->sin_family = 2; // AF_INET
addr->sin_port = htons(1023); // Port 1023 in network byte order
addr->sin_addr.s_addr = 0x0100007f;
}
running = true;
return FUZZ_INPUT_FD;
}
return o_accept(sockfd, addr, addrlen);
}
int accept4(int sockfd, struct mysockaddr *addr, unsigned long int *addrlen,
int flags) {
return accept(sockfd, addr, addrlen); // ignore flags
}
int (*o_listen)(int sockfd, int backlog);
int listen(int sockfd, int backlog) {
if (!handle) { __get_handle(); }
if (!o_listen) { o_listen = dlsym(handle, "listen"); }
if (sockfd == listen_fd) {
if (debug) fprintf(stderr, "DESOCK: intercepted listen on %d\n", sockfd);
return 0;
}
return o_listen(sockfd, backlog);
}
int (*o_bind)(int sockfd, const struct mysockaddr *addr,
unsigned long int addrlen);
int bind(int sockfd, const struct mysockaddr *addr, unsigned long int addrlen) {
if (!handle) { __get_handle(); }
if (!o_bind) { o_bind = dlsym(handle, "bind"); }
if (addr->sin_port == htons(port)) {
if (debug) fprintf(stderr, "DESOCK: intercepted bind on %d\n", sockfd);
listen_fd = sockfd;
return 0;
}
return o_bind(sockfd, addr, addrlen);
}
int (*o_setsockopt)(int sockfd, int level, int optname, const void *optval,
unsigned long int optlen);
int setsockopt(int sockfd, int level, int optname, const void *optval,
unsigned long int optlen) {
if (!handle) { __get_handle(); }
if (!o_setsockopt) { o_setsockopt = dlsym(handle, "setsockopt"); }
if (listen_fd == sockfd) {
if (debug)
fprintf(stderr, "DESOCK: intercepted setsockopt on %d for %d\n", sockfd,
optname);
return 0;
}
return o_setsockopt(sockfd, level, optname, optval, optlen);
}
int (*o_getsockopt)(int sockfd, int level, int optname, void *optval,
unsigned long int *optlen);
int getsockopt(int sockfd, int level, int optname, void *optval,
unsigned long int *optlen) {
if (!handle) { __get_handle(); }
if (!o_getsockopt) { o_getsockopt = dlsym(handle, "getsockopt"); }
if (listen_fd == sockfd) {
if (debug)
fprintf(stderr, "DESOCK: intercepted getsockopt on %d for %d\n", sockfd,
optname);
int *o = (int *)optval;
if (o != NULL) {
*o = 1; // let's hope this is fine
}
return 0;
}
return o_getsockopt(sockfd, level, optname, optval, optlen);
}
int (*o_getpeername)(int sockfd, struct mysockaddr *addr,
unsigned long int *addrlen);
int getpeername(int sockfd, struct mysockaddr *addr,
unsigned long int *addrlen) {
if (!handle) { __get_handle(); }
if (!o_getpeername) { o_getpeername = dlsym(handle, "getpeername"); }
if (port != -1 && sockfd == FUZZ_INPUT_FD) {
if (debug) fprintf(stderr, "DESOCK: getpeername\n");
if (addr && addrlen) {
// we need to fill this!
memset(addr, 0, *addrlen);
addr->sin_family = 2; // AF_INET
addr->sin_port = htons(1023); // Port 1023 in network byte order
addr->sin_addr.s_addr = 0x0100007f;
}
return 0;
}
return o_getpeername(sockfd, addr, addrlen);
}
int (*o_getsockname)(int sockfd, struct mysockaddr *addr,
unsigned long int *addrlen);
int getsockname(int sockfd, struct mysockaddr *addr,
unsigned long int *addrlen) {
if (!handle) { __get_handle(); }
if (!o_getsockname) { o_getsockname = dlsym(handle, "getsockname"); }
if (port != -1 && sockfd == FUZZ_INPUT_FD) {
if (debug) fprintf(stderr, "DESOCK: getsockname\n");
if (addr && addrlen) {
// we need to fill this!
memset(addr, 0, *addrlen);
addr->sin_family = 2; // AF_INET
addr->sin_port = htons(port);
addr->sin_addr.s_addr = 0x0100007f;
}
return 0;
}
return o_getsockname(sockfd, addr, addrlen);
}
static FILE *(*o_fdopen)(int fd, const char *mode);
FILE *fdopen(int fd, const char *mode) {
if (!o_fdopen) {
if (!handle) { __get_handle(); }
o_fdopen = dlsym(handle, "fdopen");
if (!o_fdopen) {
fprintf(stderr, "%s(): can not find fdopen\n", dlerror());
exit(-1);
}
}
if (fd == FUZZ_INPUT_FD && strcmp(mode, "r") != 0) {
if (debug) fprintf(stderr, "DESOCK: intercepted fdopen(r+) for %d\n", fd);
return o_fdopen(fd, "r");
}
return o_fdopen(fd, mode);
}
/* TARGET SPECIFIC HOOKS - put extra needed code for your target here */

View File

@ -19,11 +19,11 @@ HELPER_PATH = $(PREFIX)/lib/afl
VERSION = $(shell grep '^\#define VERSION ' ../../config.h | cut -d '"' -f2)
CFLAGS ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2
override CFLAGS += -I ../../include/ -Wall -g -Wno-pointer-sign
CFLAGS += -I ../../include/ -Wall -g -Wno-pointer-sign
CFLAGS_ADD=$(USEHUGEPAGE:1=-DUSEHUGEPAGE)
CFLAGS_ADD += $(USENAMEDPAGE:1=-DUSENAMEDPAGE)
override CFLAGS += $(CFLAGS_ADD)
CFLAGS += $(CFLAGS_ADD)
all: libdislocator.so
@ -41,3 +41,4 @@ install: all
install -m 755 -d $${DESTDIR}$(HELPER_PATH)
install -m 755 ../../libdislocator.so $${DESTDIR}$(HELPER_PATH)
install -m 644 -T README.md $${DESTDIR}$(HELPER_PATH)/README.dislocator.md

View File

@ -2,9 +2,5 @@ all:
$(CC) -no-pie test.c -o test
$(CC) -fPIC -shared read_into_rdi.c -o read_into_rdi.so
all_mipsel: test.c mipsel_read_into_a0.c
$(CPU_TARGET_CC) -no-pie test.c -o mipsel_test
$(CC) -fPIC -shared mipsel_read_into_a0.c -o mipsel_read_into_a0.so
clean:
rm -rf in out test read_into_rdi.so mipsel_test mipsel_read_into_a0.so
rm -rf in out test read_into_rdi.so

Some files were not shown because too many files have changed in this diff Show More