aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCory Barker <cobark@google.com>2023-06-12 22:45:31 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-06-12 22:45:31 +0000
commit675c292b997a56063050e6bb6d186159cdc36560 (patch)
treefc20f17f4053f3b858e31a4f08a252715784a9b0
parent74716ae077e837b18b88f90c39de8fa18b0205fa (diff)
parente40f5ec2bd66ce5a238a7eab65e11a8af05c6b12 (diff)
downloadAFLplusplus-675c292b997a56063050e6bb6d186159cdc36560.tar.gz
updating AFLpp repository am: c39bdae8bc am: e40f5ec2bd
Original change: https://android-review.googlesource.com/c/platform/external/AFLplusplus/+/2617481 Change-Id: I8e1b1faa636ff8b4a7ffb9a845a39fdb0b97eb31 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rwxr-xr-x.custom-format.py115
-rw-r--r--.dockerignore86
-rw-r--r--.github/workflows/build_aflplusplus_docker.yaml30
-rw-r--r--.github/workflows/ci.yml61
-rw-r--r--.github/workflows/code-format.yml33
-rw-r--r--.github/workflows/codeql-analysis.yml43
-rw-r--r--.github/workflows/container.yml75
-rw-r--r--.github/workflows/rust_custom_mutator.yml13
-rw-r--r--.gitignore124
-rw-r--r--Android.bp2
-rw-r--r--Dockerfile140
-rw-r--r--GNUmakefile180
-rw-r--r--GNUmakefile.gcc_plugin26
-rw-r--r--GNUmakefile.llvm79
-rw-r--r--METADATA4
-rw-r--r--README.md16
-rw-r--r--TODO.md5
-rwxr-xr-xafl-cmin197
-rwxr-xr-xafl-cmin.bash153
-rwxr-xr-xafl-persistent-config10
-rwxr-xr-xafl-plot4
-rwxr-xr-xafl-system-config9
-rwxr-xr-xafl-whatsup18
-rw-r--r--docs/Changelog.md159
-rw-r--r--docs/FAQ.md26
-rw-r--r--docs/INSTALL.md42
-rw-r--r--docs/afl-fuzz_approach.md1
-rw-r--r--docs/best_practices.md5
-rw-r--r--docs/custom_mutators.md77
-rw-r--r--docs/env_variables.md84
-rw-r--r--docs/features.md2
-rw-r--r--docs/fuzzing_binary-only_targets.md10
-rw-r--r--docs/fuzzing_in_depth.md31
-rw-r--r--docs/ideas.md17
-rw-r--r--docs/third_party_tools.md22
-rw-r--r--docs/tutorials.md11
-rw-r--r--dynamic_list.txt2
-rw-r--r--include/afl-as.h2
-rw-r--r--include/afl-fuzz.h145
-rw-r--r--include/afl-prealloc.h2
-rw-r--r--include/alloc-inl.h11
-rw-r--r--include/cmplog.h4
-rw-r--r--include/common.h33
-rw-r--r--include/config.h24
-rw-r--r--include/debug.h4
-rw-r--r--include/envs.h25
-rw-r--r--include/forkserver.h51
-rw-r--r--include/hash.h2
-rw-r--r--include/list.h6
-rw-r--r--include/sharedmem.h4
-rw-r--r--include/snapshot-inl.h2
-rw-r--r--include/types.h4
-rw-r--r--include/xxhash.h52
-rw-r--r--instrumentation/README.gcc_plugin.md9
-rw-r--r--instrumentation/README.llvm.md32
-rw-r--r--instrumentation/README.lto.md129
-rw-r--r--instrumentation/SanitizerCoverageLTO.so.cc166
-rw-r--r--instrumentation/SanitizerCoveragePCGUARD.so.cc720
-rw-r--r--instrumentation/afl-compiler-rt.o.c566
-rw-r--r--instrumentation/afl-gcc-cmplog-pass.so.cc404
-rw-r--r--instrumentation/afl-gcc-cmptrs-pass.so.cc366
-rw-r--r--instrumentation/afl-gcc-common.h508
-rw-r--r--instrumentation/afl-llvm-common.cc8
-rw-r--r--instrumentation/afl-llvm-common.h11
-rw-r--r--instrumentation/afl-llvm-dict2file.so.cc35
-rw-r--r--instrumentation/afl-llvm-lto-instrumentlist.so.cc8
-rw-r--r--instrumentation/afl-llvm-pass.so.cc18
-rw-r--r--instrumentation/cmplog-instructions-pass.cc10
-rw-r--r--instrumentation/cmplog-routines-pass.cc42
-rw-r--r--instrumentation/cmplog-switches-pass.cc12
-rw-r--r--instrumentation/compare-transform-pass.so.cc22
-rw-r--r--instrumentation/split-compares-pass.so.cc332
-rw-r--r--instrumentation/split-switches-pass.so.cc36
-rw-r--r--src/afl-analyze.c172
-rw-r--r--src/afl-as.c24
-rw-r--r--src/afl-cc.c781
-rw-r--r--src/afl-common.c226
-rw-r--r--src/afl-forkserver.c361
-rw-r--r--src/afl-fuzz-bitmap.c80
-rw-r--r--src/afl-fuzz-cmplog.c25
-rw-r--r--src/afl-fuzz-extras.c10
-rw-r--r--src/afl-fuzz-init.c148
-rw-r--r--src/afl-fuzz-mutators.c131
-rw-r--r--src/afl-fuzz-one.c212
-rw-r--r--src/afl-fuzz-python.c220
-rw-r--r--src/afl-fuzz-queue.c234
-rw-r--r--src/afl-fuzz-redqueen.c93
-rw-r--r--src/afl-fuzz-run.c175
-rw-r--r--src/afl-fuzz-state.c108
-rw-r--r--src/afl-fuzz-stats.c196
-rw-r--r--src/afl-fuzz.c451
-rw-r--r--src/afl-gotcpu.c24
-rw-r--r--src/afl-ld-lto.c6
-rw-r--r--src/afl-sharedmem.c2
-rw-r--r--src/afl-showmap.c587
-rw-r--r--src/afl-tmin.c170
-rw-r--r--test-instr.c32
-rwxr-xr-xtest/test-all.sh2
-rwxr-xr-xtest/test-basic.sh107
-rw-r--r--test/test-cmplog.c6
-rwxr-xr-xtest/test-custom-mutators.sh146
-rw-r--r--test/test-dlopen.c2
-rwxr-xr-xtest/test-frida-mode.sh8
-rwxr-xr-xtest/test-gcc-plugin.sh4
-rwxr-xr-xtest/test-llvm.sh11
-rwxr-xr-xtest/test-performance.sh4
-rwxr-xr-xtest/test-pre.sh2
-rwxr-xr-xtest/test-qemu-mode.sh31
-rwxr-xr-xtest/test-unicorn-mode.sh6
-rw-r--r--utils/README.md2
-rw-r--r--utils/afl_network_proxy/afl-network-client.c12
-rw-r--r--utils/afl_network_proxy/afl-network-server.c25
-rw-r--r--utils/afl_proxy/README.md5
-rw-r--r--utils/afl_proxy/afl-proxy.c4
-rw-r--r--utils/afl_untracer/afl-untracer.c41
-rw-r--r--utils/afl_untracer/libtestinstr.c2
-rw-r--r--utils/aflpp_driver/GNUmakefile23
-rw-r--r--utils/aflpp_driver/aflpp_driver.c132
-rw-r--r--utils/aflpp_driver/aflpp_driver_test.c17
-rwxr-xr-xutils/analysis_scripts/queue2csv.sh4
-rw-r--r--utils/argv_fuzzing/Makefile17
-rw-r--r--utils/argv_fuzzing/README.md41
-rw-r--r--utils/argv_fuzzing/argv-fuzz-inl.h53
-rw-r--r--utils/argv_fuzzing/argv_fuzz_demo.c28
-rw-r--r--utils/argv_fuzzing/argv_fuzz_persistent_demo.c59
-rw-r--r--utils/argv_fuzzing/argvfuzz.c2
-rwxr-xr-xutils/distributed_fuzzing/sync_script.sh2
-rw-r--r--utils/libdislocator/README.md4
-rw-r--r--utils/libdislocator/libdislocator.so.c57
-rw-r--r--utils/libtokencap/README.md2
-rw-r--r--utils/libtokencap/libtokencap.so.c34
-rw-r--r--utils/persistent_mode/test-instr.c2
-rwxr-xr-xutils/qbdi_mode/template.cpp6
-rw-r--r--utils/socket_fuzzing/socketfuzz.c3
-rw-r--r--utils/target_intelligence/README.md61
135 files changed, 8104 insertions, 3048 deletions
diff --git a/.custom-format.py b/.custom-format.py
index 7ac63396..1d5c8839 100755
--- a/.custom-format.py
+++ b/.custom-format.py
@@ -3,10 +3,10 @@
# american fuzzy lop++ - custom code formatter
# --------------------------------------------
#
-# Written and maintaned by Andrea Fioraldi <andreafioraldi@gmail.com>
+# Written and maintained by Andrea Fioraldi <andreafioraldi@gmail.com>
#
# Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
-# Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+# Copyright 2019-2023 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.
@@ -18,41 +18,56 @@
import subprocess
import sys
import os
-import re
+# import re # TODO: for future use
+import shutil
+import importlib.metadata
+
+# string_re = re.compile('(\\"(\\\\.|[^"\\\\])*\\")') # TODO: for future use
+
+CURRENT_LLVM = os.getenv('LLVM_VERSION', 15)
+CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN", "")
+
+
+def check_clang_format_pip_version():
+ """
+ Check if the correct version of clang-format is installed via pip.
+
+ Returns:
+ bool: True if the correct version of clang-format is installed,
+ False otherwise.
+ """
+ # Check if clang-format is installed
+ if importlib.util.find_spec('clang_format'):
+ # Check if the installed version is the expected LLVM version
+ if importlib.metadata.version('clang-format')\
+ .startswith(str(CURRENT_LLVM)+'.'):
+ return True
+ else:
+ # Return False, because the clang-format version does not match
+ return False
+ else:
+ # If the 'clang_format' package isn't installed, return False
+ return False
-# string_re = re.compile('(\\"(\\\\.|[^"\\\\])*\\")') # future use
with open(".clang-format") as f:
fmt = f.read()
-CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN")
-if CLANG_FORMAT_BIN is None:
- o = 0
- try:
- p = subprocess.Popen(["clang-format-11", "--version"], stdout=subprocess.PIPE)
- o, _ = p.communicate()
- o = str(o, "utf-8")
- o = re.sub(r".*ersion ", "", o)
- # o = o[len("clang-format version "):].strip()
- o = o[: o.find(".")]
- o = int(o)
- except:
- print("clang-format-11 is needed. Aborted.")
- exit(1)
- # if o < 7:
- # if subprocess.call(['which', 'clang-format-7'], stdout=subprocess.PIPE) == 0:
- # CLANG_FORMAT_BIN = 'clang-format-7'
- # elif subprocess.call(['which', 'clang-format-8'], stdout=subprocess.PIPE) == 0:
- # CLANG_FORMAT_BIN = 'clang-format-8'
- # elif subprocess.call(['which', 'clang-format-9'], stdout=subprocess.PIPE) == 0:
- # CLANG_FORMAT_BIN = 'clang-format-9'
- # elif subprocess.call(['which', 'clang-format-11'], stdout=subprocess.PIPE) == 0:
- # CLANG_FORMAT_BIN = 'clang-format-11'
- # else:
- # print ("clang-format 7 or above is needed. Aborted.")
- # exit(1)
- else:
- CLANG_FORMAT_BIN = "clang-format-11"
+
+CLANG_FORMAT_PIP = check_clang_format_pip_version()
+
+if shutil.which(CLANG_FORMAT_BIN) is None:
+ CLANG_FORMAT_BIN = f"clang-format-{CURRENT_LLVM}"
+
+if shutil.which(CLANG_FORMAT_BIN) is None \
+ and CLANG_FORMAT_PIP is False:
+ print(f"[!] clang-format-{CURRENT_LLVM} is needed. Aborted.")
+ print(f"Run `pip3 install \"clang-format=={CURRENT_LLVM}.*\"` \
+to install via pip.")
+ exit(1)
+
+if CLANG_FORMAT_PIP:
+ CLANG_FORMAT_BIN = shutil.which("clang-format")
COLUMN_LIMIT = 80
for line in fmt.split("\n"):
@@ -72,43 +87,43 @@ def custom_format(filename):
for line in src.split("\n"):
if line.lstrip().startswith("#"):
- if line[line.find("#") + 1 :].lstrip().startswith("define"):
+ if line[line.find("#") + 1:].lstrip().startswith("define"):
in_define = True
if (
- "/*" in line
- and not line.strip().startswith("/*")
- and line.endswith("*/")
- and len(line) < (COLUMN_LIMIT - 2)
+ "/*" in line
+ and not line.strip().startswith("/*")
+ and line.endswith("*/")
+ and len(line) < (COLUMN_LIMIT - 2)
):
cmt_start = line.rfind("/*")
line = (
- line[:cmt_start]
- + " " * (COLUMN_LIMIT - 2 - len(line))
- + line[cmt_start:]
+ line[:cmt_start]
+ + " " * (COLUMN_LIMIT - 2 - len(line))
+ + line[cmt_start:]
)
define_padding = 0
if last_line is not None and in_define and last_line.endswith("\\"):
last_line = last_line[:-1]
- define_padding = max(0, len(last_line[last_line.rfind("\n") + 1 :]))
+ define_padding = max(0, len(last_line[last_line.rfind("\n") + 1:]))
if (
- last_line is not None
- and last_line.strip().endswith("{")
- and line.strip() != ""
+ last_line is not None
+ and last_line.strip().endswith("{")
+ and line.strip() != ""
):
line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
elif (
- last_line is not None
- and last_line.strip().startswith("}")
- and line.strip() != ""
+ last_line is not None
+ and last_line.strip().startswith("}")
+ and line.strip() != ""
):
line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
elif (
- line.strip().startswith("}")
- and last_line is not None
- and last_line.strip() != ""
+ line.strip().startswith("}")
+ and last_line is not None
+ and last_line.strip() != ""
):
line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
diff --git a/.dockerignore b/.dockerignore
index d05bf1c6..271d338c 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,65 +1,75 @@
-.test
-.test2
-.sync_tmp
+!/coresight_mode
+*.dSYM
*.o
-*.so
*.pyc
-*.dSYM
-as
-ld
-in
-out
-core*
+*.so
+.sync_tmp
+.test
+.test2
+.git
+.dockerignore
+.github
+CITATION.cff
+CONTRIBUTING.md
+Changelog.md
+Dockerfile
+LICENSE
+TODO.md
afl-analyze
+afl-analyze.8
afl-as
+afl-as.8
afl-clang
-afl-clang\+\+
afl-clang-fast
+afl-clang-fast.8
afl-clang-fast\+\+
+afl-clang-fast\+\+.8
afl-clang-lto
+afl-clang-lto.8
afl-clang-lto\+\+
+afl-clang-lto\+\+.8
+afl-clang\+\+
+afl-cmin.8
+afl-cmin.bash.8
afl-fuzz
+afl-fuzz.8
afl-g\+\+
+afl-g\+\+-fast
+afl-g\+\+-fast.8
afl-gcc
afl-gcc-fast
-afl-g\+\+-fast
+afl-gcc-fast.8
+afl-gcc.8
afl-gotcpu
+afl-gotcpu.8
afl-ld
afl-ld-lto
+afl-plot.8
afl-qemu-trace
afl-showmap
-afl-tmin
-afl-analyze.8
-afl-as.8
-afl-clang-fast\+\+.8
-afl-clang-fast.8
-afl-clang-lto.8
-afl-clang-lto\+\+.8
-afl-cmin.8
-afl-cmin.bash.8
-afl-fuzz.8
-afl-gcc.8
-afl-gcc-fast.8
-afl-g\+\+-fast.8
-afl-gotcpu.8
-afl-plot.8
afl-showmap.8
afl-system-config.8
+afl-tmin
afl-tmin.8
afl-whatsup.8
+as
+core*
+examples/afl_frida/afl-frida
+examples/afl_frida/frida-gum-example.c
+examples/afl_frida/frida-gum.h
+examples/afl_frida/libtestinstr.so
+examples/afl_network_proxy/afl-network-client
+examples/afl_network_proxy/afl-network-server
+in
+ld
+out
qemu_mode/libcompcov/compcovtest
qemu_mode/qemu-*
-unicorn_mode/samples/*/\.test-*
-unicorn_mode/samples/*/output
-unicorn_mode/unicornafl
+test/unittests/unit_hash
+test/unittests/unit_list
test/unittests/unit_maybe_alloc
test/unittests/unit_preallocable
-test/unittests/unit_list
test/unittests/unit_rand
-test/unittests/unit_hash
-examples/afl_network_proxy/afl-network-server
-examples/afl_network_proxy/afl-network-client
-examples/afl_frida/afl-frida
-examples/afl_frida/libtestinstr.so
-examples/afl_frida/frida-gum-example.c
-examples/afl_frida/frida-gum.h \ No newline at end of file
+unicorn_mode/samples/*/\.test-*
+unicorn_mode/samples/*/output
+unicorn_mode/unicornafl
diff --git a/.github/workflows/build_aflplusplus_docker.yaml b/.github/workflows/build_aflplusplus_docker.yaml
deleted file mode 100644
index fa96da8e..00000000
--- a/.github/workflows/build_aflplusplus_docker.yaml
+++ /dev/null
@@ -1,30 +0,0 @@
-name: Publish Docker Images
-
-on:
- push:
- branches: [ stable ]
-# paths:
-# - Dockerfile
-
-jobs:
- push_to_registry:
- name: Push Docker images to Dockerhub
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@master
- - name: Set up QEMU
- uses: docker/setup-qemu-action@v1
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v1
- - name: Login to Dockerhub
- uses: docker/login-action@v1
- with:
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKER_TOKEN }}
- - name: Publish aflpp to Registry
- uses: docker/build-push-action@v2
- with:
- context: .
- platforms: linux/amd64,linux/arm64
- push: true
- tags: aflplusplus/aflplusplus:latest
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 886148df..fdf618b9 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -2,52 +2,57 @@ name: CI
on:
push:
- branches: [ stable, dev ]
+ branches:
+ - stable
+ - dev
pull_request:
- branches: [ stable, dev ]
+ branches:
+ - dev # No need for stable-pull-request, as that equals dev-push
jobs:
linux:
- runs-on: '${{ matrix.os }}'
+ runs-on: "${{ matrix.os }}"
strategy:
matrix:
- os: [ubuntu-20.04, ubuntu-18.04]
+ os: [ubuntu-22.04, ubuntu-20.04]
env:
AFL_SKIP_CPUFREQ: 1
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: debug
run: apt-cache search plugin-dev | grep gcc-; echo; apt-cache search clang-format- | grep clang-format-
- name: update
- run: sudo apt-get update && sudo apt-get upgrade -y
+ run: sudo apt-get update
+ # && sudo apt-get upgrade -y
- name: install packages
- run: sudo apt-get install -y -m -f --install-suggests build-essential git libtool libtool-bin automake bison libglib2.0-0 clang llvm-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build
+ #run: sudo apt-get install -y -m -f --install-suggests build-essential git libtool libtool-bin automake bison libglib2.0-0 clang llvm-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build python3-pip
+ run: sudo apt-get install -y -m -f build-essential git libtool libtool-bin automake flex bison libglib2.0-0 clang llvm-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build python3-pip
- name: compiler installed
run: gcc -v; echo; clang -v
- name: install gcc plugin
run: sudo apt-get install -y -m -f --install-suggests $(readlink /usr/bin/gcc)-plugin-dev
- name: build afl++
- run: make distrib ASAN_BUILD=1
+ run: make distrib ASAN_BUILD=1 NO_NYX=1
- name: run tests
run: sudo -E ./afl-system-config; make tests
- macos:
- runs-on: macOS-latest
- env:
- AFL_MAP_SIZE: 65536
- AFL_SKIP_CPUFREQ: 1
- AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
- steps:
- - uses: actions/checkout@v2
- - name: install
- run: brew install make gcc
- - name: fix install
- run: cd /usr/local/bin; ln -s gcc-11 gcc; ln -s g++-11 g++; which gcc; gcc -v
- - name: build
- run: export PATH=/usr/local/Cellar/llvm/*/":$PATH"; export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; export LLVM_CONFIG=/usr/local/Cellar/llvm/*/bin/llvm-config; sudo -E ./afl-system-config; gmake ASAN_BUILD=1
- - name: frida
- run: export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; cd frida_mode; gmake
- - name: run tests
- run: sudo -E ./afl-system-config; export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; export PATH=/usr/local/Cellar/llvm/*/":/usr/local/bin:$PATH"; export LLVM_CONFIG=/usr/local/Cellar/llvm/*/bin/llvm-config; gmake tests
- - name: force frida test for MacOS
- run: export AFL_PATH=`pwd`; /usr/local/bin/gcc -o test-instr test-instr.c; mkdir in; echo > in/in; AFL_NO_UI=1 ./afl-fuzz -O -i in -o out -V 5 -- ./test-instr
+ # macos:
+ # runs-on: macOS-latest
+ # env:
+ # AFL_MAP_SIZE: 65536
+ # AFL_SKIP_CPUFREQ: 1
+ # AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
+ # steps:
+ # - uses: actions/checkout@v3
+ # - name: install
+ # run: brew install make gcc llvm
+ # - name: fix install
+ # run: cd /usr/local/bin; ln -s gcc-11 gcc; ln -s g++-11 g++; which gcc; gcc -v
+ # - name: build
+ # run: export PATH=/usr/local/Cellar/llvm/*/":$PATH"; export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; export LLVM_CONFIG=/usr/local/Cellar/llvm/*/bin/llvm-config; sudo -E ./afl-system-config; gmake ASAN_BUILD=1
+ # - name: frida
+ # run: export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; cd frida_mode; gmake
+ # - name: run tests
+ # run: sudo -E ./afl-system-config; export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; export PATH=/usr/local/Cellar/llvm/*/":/usr/local/bin:$PATH"; export LLVM_CONFIG=/usr/local/Cellar/llvm/*/bin/llvm-config; gmake tests
+ # - name: force frida test for MacOS
+ # run: export AFL_PATH=`pwd`; /usr/local/bin/gcc -o test-instr test-instr.c; mkdir in; echo > in/in; AFL_NO_UI=1 ./afl-fuzz -O -i in -o out -V 5 -- ./test-instr
diff --git a/.github/workflows/code-format.yml b/.github/workflows/code-format.yml
new file mode 100644
index 00000000..314137ff
--- /dev/null
+++ b/.github/workflows/code-format.yml
@@ -0,0 +1,33 @@
+name: Formatting
+
+on:
+ push:
+ branches:
+ - stable
+ - dev
+ pull_request:
+ branches:
+ - dev # No need for stable-pull-request, as that equals dev-push
+
+jobs:
+ code-format-check:
+ name: Check code format
+ if: ${{ 'false' == 'true' }} # Disable the job
+ runs-on: ubuntu-22.04
+ container: docker.io/aflplusplus/aflplusplus:dev
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ - name: Format
+ run: |
+ git config --global --add safe.directory /__w/AFLplusplus/AFLplusplus
+ apt-get update
+ apt-get install -y clang-format-${LLVM_VERSION}
+ make code-format
+ - name: Check if code needed formatting
+ run: |
+ git --no-pager -c color.ui=always diff HEAD
+ if ! git diff HEAD --quiet; then
+ echo "[!] Please run 'make code-format' and push its changes."
+ exit 1
+ fi
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index eda8dfd0..75935123 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -2,31 +2,32 @@ name: "CodeQL"
on:
push:
- branches: [ stable, dev ]
+ branches:
+ - stable
+ - dev
pull_request:
- branches: [ stable, dev ]
+ branches:
+ - dev # No need for stable-pull-request, as that equals dev-push
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
-
- strategy:
- fail-fast: false
- matrix:
- language: [ 'cpp' ]
-
+ container: # We use a previous image as it's expected to have all the dependencies
+ image: docker.io/aflplusplus/aflplusplus:dev
steps:
- - name: Checkout repository
- uses: actions/checkout@v2
-
- - name: Initialize CodeQL
- uses: github/codeql-action/init@v1
- with:
- languages: ${{ matrix.language }}
-
- - name: Autobuild
- uses: github/codeql-action/autobuild@v1
-
- - name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v1
+ - name: Fix for using external repo in container build # https://github.com/actions/checkout/issues/760
+ run: git config --global --add safe.directory /__w/AFLplusplus/AFLplusplus
+ - name: Checkout
+ uses: actions/checkout@v3
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v2
+ with:
+ languages: cpp, python
+ - name: Build AFLplusplus # Rebuild because CodeQL needs to monitor the build process
+ env:
+ CC: gcc # These are symlinked to the version used in the container build
+ CXX: g++
+ run: make -i all # Best effort using -i
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v2
diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml
new file mode 100644
index 00000000..8836997d
--- /dev/null
+++ b/.github/workflows/container.yml
@@ -0,0 +1,75 @@
+name: Container
+on:
+ push:
+ branches:
+ - stable
+ - dev
+ tags:
+ - "*"
+ pull_request:
+ branches:
+ - dev # No need for stable-pull-request, as that equals dev-push
+
+jobs:
+ build-and-test-amd64:
+ name: Test amd64 image
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v2
+ - name: Build amd64
+ uses: docker/build-push-action@v3
+ with:
+ context: .
+ tags: aflplusplus:test-amd64
+ load: true
+ cache-to: type=gha,mode=max
+ build-args: |
+ TEST_BUILD=1
+ - name: Test amd64
+ run: >
+ docker run --rm aflplusplus:test-amd64 bash -c "
+ apt-get update &&
+ apt-get install -y libcmocka-dev &&
+ make -i tests
+ "
+
+ push:
+ name: Push amd64 and arm64 images
+ runs-on: ubuntu-latest
+ needs:
+ - build-and-test-amd64
+ if: ${{ github.event_name == 'push' && github.repository == 'AFLplusplus/AFLplusplus' }}
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v2
+ with:
+ platforms: arm64
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v2
+ - name: Login to docker.io
+ uses: docker/login-action@v2
+ with:
+ username: ${{ secrets.DOCKER_USERNAME }}
+ password: ${{ secrets.DOCKER_TOKEN }}
+ - name: Set tags to push
+ id: push-tags
+ run: |
+ PUSH_TAGS=docker.io/aflplusplus/aflplusplus:${GITHUB_REF_NAME}
+ if [ "${GITHUB_REF_NAME}" = "stable" ]; then
+ PUSH_TAGS=${PUSH_TAGS},docker.io/aflplusplus/aflplusplus:latest
+ fi
+ export PUSH_TAGS
+ echo "::set-output name=PUSH_TAGS::${PUSH_TAGS}"
+ - name: Push to docker.io registry
+ uses: docker/build-push-action@v3
+ with:
+ context: .
+ platforms: linux/amd64,linux/arm64
+ push: true
+ tags: ${{ steps.push-tags.outputs.PUSH_TAGS }}
+ cache-from: type=gha
diff --git a/.github/workflows/rust_custom_mutator.yml b/.github/workflows/rust_custom_mutator.yml
index de2b184a..7c2f0c12 100644
--- a/.github/workflows/rust_custom_mutator.yml
+++ b/.github/workflows/rust_custom_mutator.yml
@@ -2,9 +2,12 @@ name: Rust Custom Mutators
on:
push:
- branches: [ stable, dev ]
+ branches:
+ - stable
+ - dev
pull_request:
- branches: [ stable, dev ]
+ branches:
+ - dev # No need for stable-pull-request, as that equals dev-push
jobs:
test:
@@ -15,9 +18,9 @@ jobs:
working-directory: custom_mutators/rust
strategy:
matrix:
- os: [ubuntu-20.04]
+ os: [ubuntu-22.04, ubuntu-20.04]
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Install Rust Toolchain
uses: actions-rs/toolchain@v1
with:
@@ -27,4 +30,4 @@ jobs:
- name: Run General Tests
run: cargo test
- name: Run Tests for afl_internals feature flag
- run: cd custom_mutator && cargo test --features=afl_internals \ No newline at end of file
+ run: cd custom_mutator && cargo test --features=afl_internals
diff --git a/.gitignore b/.gitignore
index 22ee6bf1..c01750e1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,99 +1,107 @@
-.test
-.test2
-.sync_tmp
-.vscode
+!coresight_mode
+!coresight_mode/coresight-trace
+*.dSYM
*.o
+*.o.tmp
+*.pyc
*.so
*.swp
-*.pyc
-*.dSYM
-as
-a.out
-ld
-in
-out
-core*
-compile_commands.json
+.sync_tmp
+.test
+.test2
+.vscode
afl-analyze
+afl-analyze.8
afl-as
+afl-as.8
+afl-c++
+afl-c++.8
+afl-cc
+afl-cc.8
afl-clang
afl-clang++
afl-clang-fast
afl-clang-fast++
+afl-clang-fast++.8
+afl-clang-fast.8
afl-clang-lto
afl-clang-lto++
+afl-clang-lto++.8
+afl-clang-lto.8
+afl-cmin.8
+afl-cmin.bash.8
+afl-cs-proxy
+afl-frida-trace.so
afl-fuzz
+afl-fuzz.8
afl-g++
+afl-g++.8
afl-gcc
+afl-gcc.8
afl-gcc-fast
+afl-gcc-fast.8
afl-g++-fast
+afl-g++-fast.8
afl-gotcpu
+afl-gotcpu.8
afl-ld
afl-ld-lto
-afl-cs-proxy
+afl-lto
+afl-lto++
+afl-lto++.8
+afl-lto.8
+afl-persistent-config.8
+afl-plot.8
afl-qemu-trace
afl-showmap
-afl-tmin
-afl-analyze.8
-afl-as.8
-afl-clang-fast++.8
-afl-clang-fast.8
-afl-clang-lto.8
-afl-clang-lto++.8
-afl-cmin.8
-afl-cmin.bash.8
-afl-fuzz.8
-afl-c++.8
-afl-cc.8
-afl-gcc.8
-afl-g++.8
-afl-gcc-fast.8
-afl-g++-fast.8
-afl-gotcpu.8
-afl-plot.8
afl-showmap.8
afl-system-config.8
+afl-tmin
afl-tmin.8
afl-whatsup.8
-afl-persistent-config.8
-afl-c++
-afl-cc
-afl-lto
-afl-lto++
-afl-lto++.8
-afl-lto.8
-qemu_mode/libcompcov/compcovtest
-qemu_mode/qemu-*
-qemu_mode/qemuafl
-unicorn_mode/samples/*/\.test-*
-unicorn_mode/samples/*/output/
-test/unittests/unit_maybe_alloc
-test/unittests/unit_preallocable
-test/unittests/unit_list
-test/unittests/unit_rand
-test/unittests/unit_hash
-examples/afl_network_proxy/afl-network-server
-examples/afl_network_proxy/afl-network-client
+a.out
+as
+compile_commands.json
+core*
examples/afl_frida/afl-frida
-examples/afl_frida/libtestinstr.so
examples/afl_frida/frida-gum-example.c
examples/afl_frida/frida-gum.h
+examples/afl_frida/libtestinstr.so
+examples/afl_network_proxy/afl-network-client
+examples/afl_network_proxy/afl-network-server
examples/aflpp_driver/libAFLDriver.a
examples/aflpp_driver/libAFLQemuDriver.a
+gmon.out
+in
+ld
libAFLDriver.a
libAFLQemuDriver.a
+out
+qemu_mode/libcompcov/compcovtest
+qemu_mode/qemu-*
+qemu_mode/qemuafl
test/.afl_performance
-gmon.out
-afl-frida-trace.so
+test-instr
+test/output
+test/test-c
+test/test-cmplog
+test/test-compcov
+test/test-instr.ts
+test/test-persistent
+test/unittests/unit_hash
+test/unittests/unit_list
+test/unittests/unit_maybe_alloc
+test/unittests/unit_preallocable
+test/unittests/unit_rand
+unicorn_mode/samples/*/output/
+unicorn_mode/samples/*/\.test-*
utils/afl_network_proxy/afl-network-client
utils/afl_network_proxy/afl-network-server
-utils/plot_ui/afl-plot-ui
-*.o.tmp
utils/afl_proxy/afl-proxy
utils/optimin/build
utils/optimin/optimin
utils/persistent_mode/persistent_demo
utils/persistent_mode/persistent_demo_new
utils/persistent_mode/test-instr
-!coresight_mode
-!coresight_mode/coresight-trace
+utils/plot_ui/afl-plot-ui
+vuln_prog
diff --git a/Android.bp b/Android.bp
index aae18d79..33fbda4e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -118,6 +118,8 @@ cc_binary {
"src/afl-sharedmem.c",
"src/afl-forkserver.c",
"src/afl-performance.c",
+ "src/afl-fuzz-mutators.c",
+ "src/afl-fuzz-python.c",
],
}
diff --git a/Dockerfile b/Dockerfile
index bdfa1c56..1b5ffd28 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,81 +1,97 @@
#
# This Dockerfile for AFLplusplus uses Ubuntu 22.04 jammy and
-# installs LLVM 14 for afl-clang-lto support :-)
+# installs LLVM 14 for afl-clang-lto support.
+#
+# GCC 11 is used instead of 12 because genhtml for afl-cov doesn't like it.
#
FROM ubuntu:22.04 AS aflplusplus
-LABEL "maintainer"="afl++ team <afl@aflplus.plus>"
-LABEL "about"="AFLplusplus docker image"
+LABEL "maintainer"="AFL++ team <afl@aflplus.plus>"
+LABEL "about"="AFLplusplus container image"
-ARG DEBIAN_FRONTEND=noninteractive
+### Comment out to enable these features
+# Only available on specific ARM64 boards
+ENV NO_CORESIGHT=1
+# Possible but unlikely in a docker container
+ENV NO_NYX=1
-env NO_ARCH_OPT 1
+### Only change these if you know what you are doing:
+# LLVM 15 does not look good so we stay at 14 to still have LTO
+ENV LLVM_VERSION=14
+# GCC 12 is producing compile errors for some targets so we stay at GCC 11
+ENV GCC_VERSION=11
-RUN apt-get update && \
- apt-get -y install --no-install-suggests --no-install-recommends \
- automake \
- cmake \
- meson \
- ninja-build \
- bison flex \
- build-essential \
- git \
- python3 python3-dev python3-setuptools python-is-python3 \
- libtool libtool-bin \
- libglib2.0-dev \
- wget vim jupp nano bash-completion less \
- apt-utils apt-transport-https ca-certificates gnupg dialog \
- libpixman-1-dev \
- gnuplot-nox \
- && rm -rf /var/lib/apt/lists/*
-
-# TODO: reactivate in timely manner
-#RUN echo "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main" >> /etc/apt/sources.list && \
-# wget -qO - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
-
-RUN echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu jammy main" >> /etc/apt/sources.list && \
- apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 1E9377A2BA9EF27F
+### No changes beyond the point unless you know what you are doing :)
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+ENV NO_ARCH_OPT=1
+ENV IS_DOCKER=1
RUN apt-get update && apt-get full-upgrade -y && \
- apt-get -y install --no-install-suggests --no-install-recommends \
- gcc-12 g++-12 gcc-12-plugin-dev gdb lcov \
- clang-14 clang-tools-14 libc++1-14 libc++-14-dev \
- libc++abi1-14 libc++abi-14-dev libclang1-14 libclang-14-dev \
- libclang-common-14-dev libclang-cpp14 libclang-cpp14-dev liblld-14 \
- liblld-14-dev liblldb-14 liblldb-14-dev libllvm14 libomp-14-dev \
- libomp5-14 lld-14 lldb-14 llvm-14 llvm-14-dev llvm-14-runtime llvm-14-tools
-
-# arm64 doesn't have gcc-multilib, and it's only used for -m32 support on x86
-ARG TARGETPLATFORM
-RUN [ "$TARGETPLATFORM" = "linux/amd64" ] && \
- apt-get -y install --no-install-suggests --no-install-recommends \
- gcc-10-multilib gcc-multilib || true
-
-RUN rm -rf /var/lib/apt/lists/*
-
-RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 0
-RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 0
-
-ENV LLVM_CONFIG=llvm-config-14
+ 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 apt-get update && \
+ apt-get -y install --no-install-recommends \
+ make cmake automake meson ninja-build bison flex \
+ git xz-utils bzip2 wget jupp nano bash-completion less vim joe ssh psmisc \
+ python3 python3-dev python3-pip python-is-python3 \
+ libtool libtool-bin libglib2.0-dev \
+ apt-transport-https gnupg dialog \
+ gnuplot-nox libpixman-1-dev \
+ gcc-${GCC_VERSION} g++-${GCC_VERSION} gcc-${GCC_VERSION}-plugin-dev gdb lcov \
+ clang-${LLVM_VERSION} clang-tools-${LLVM_VERSION} libc++1-${LLVM_VERSION} \
+ libc++-${LLVM_VERSION}-dev libc++abi1-${LLVM_VERSION} libc++abi-${LLVM_VERSION}-dev \
+ libclang1-${LLVM_VERSION} libclang-${LLVM_VERSION}-dev \
+ libclang-common-${LLVM_VERSION}-dev libclang-rt-${LLVM_VERSION}-dev libclang-cpp${LLVM_VERSION} \
+ libclang-cpp${LLVM_VERSION}-dev liblld-${LLVM_VERSION} \
+ liblld-${LLVM_VERSION}-dev liblldb-${LLVM_VERSION} liblldb-${LLVM_VERSION}-dev \
+ libllvm${LLVM_VERSION} libomp-${LLVM_VERSION}-dev libomp5-${LLVM_VERSION} \
+ lld-${LLVM_VERSION} lldb-${LLVM_VERSION} llvm-${LLVM_VERSION} \
+ llvm-${LLVM_VERSION}-dev llvm-${LLVM_VERSION}-runtime llvm-${LLVM_VERSION}-tools \
+ $([ "$(dpkg --print-architecture)" = "amd64" ] && echo gcc-${GCC_VERSION}-multilib gcc-multilib) \
+ $([ "$(dpkg --print-architecture)" = "arm64" ] && echo libcapstone-dev) && \
+ rm -rf /var/lib/apt/lists/*
+ # gcc-multilib is only used for -m32 support on x86
+ # libcapstone-dev is used for coresight_mode on arm64
+
+RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${GCC_VERSION} 0 && \
+ update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-${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 apt clean -y
+
+ENV LLVM_CONFIG=llvm-config-${LLVM_VERSION}
ENV AFL_SKIP_CPUFREQ=1
ENV AFL_TRY_AFFINITY=1
ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
-RUN git clone --depth=1 https://github.com/vanhauser-thc/afl-cov /afl-cov
-RUN cd /afl-cov && make install && cd ..
+RUN git clone --depth=1 https://github.com/vanhauser-thc/afl-cov && \
+ (cd afl-cov && make install) && rm -rf afl-cov
-COPY . /AFLplusplus
WORKDIR /AFLplusplus
+COPY . .
+
+ARG CC=gcc-$GCC_VERSION
+ARG CXX=g++-$GCC_VERSION
-RUN export CC=gcc-12 && export CXX=g++-12 && make clean && \
- make distrib && make install && make clean
+# Used in CI to prevent a 'make clean' which would remove the binaries to be tested
+ARG TEST_BUILD
-RUN sh -c 'echo set encoding=utf-8 > /root/.vimrc'
-RUN echo '. /etc/bash_completion' >> ~/.bashrc
-RUN echo 'alias joe="joe --wordwrap --joe_state -nobackup"' >> ~/.bashrc
-RUN echo "export PS1='"'[afl++ \h] \w$(__git_ps1) \$ '"'" >> ~/.bashrc
-ENV IS_DOCKER="1"
+RUN sed -i.bak 's/^ -/ /g' GNUmakefile && \
+ make clean && make distrib && \
+ ([ "${TEST_BUILD}" ] || (make install && make clean)) && \
+ mv GNUmakefile.bak GNUmakefile
-# Disabled as there are now better alternatives
-#COPY --from=aflplusplus/afl-dyninst /usr/local/lib/libdyninstAPI_RT.so /usr/local/lib/libdyninstAPI_RT.so
-#COPY --from=aflplusplus/afl-dyninst /afl-dyninst/libAflDyninst.so /usr/local/lib/libAflDyninst.so
+RUN echo "set encoding=utf-8" > /root/.vimrc && \
+ echo ". /etc/bash_completion" >> ~/.bashrc && \
+ echo 'alias joe="joe --wordwrap --joe_state -nobackup"' >> ~/.bashrc && \
+ echo "export PS1='"'[AFL++ \h] \w \$ '"'" >> ~/.bashrc
diff --git a/GNUmakefile b/GNUmakefile
index 072bd09d..55676d97 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -39,7 +39,7 @@ ASAN_OPTIONS=detect_leaks=0
SYS = $(shell uname -s)
ARCH = $(shell uname -m)
-$(info [*] Compiling afl++ for OS $(SYS) on ARCH $(ARCH))
+$(info [*] Compiling AFL++ for OS $(SYS) on ARCH $(ARCH))
ifdef NO_SPLICING
override CFLAGS_OPT += -DNO_SPLICING
@@ -91,9 +91,8 @@ ifneq "$(SYS)" "Darwin"
#ifeq "$(HAVE_MARCHNATIVE)" "1"
# SPECIAL_PERFORMANCE += -march=native
#endif
- # OS X does not like _FORTIFY_SOURCE=2
ifndef DEBUG
- CFLAGS_OPT += -D_FORTIFY_SOURCE=2
+ CFLAGS_OPT += -D_FORTIFY_SOURCE=1
endif
else
# On some odd MacOS system configurations, the Xcode sdk path is not set correctly
@@ -101,9 +100,14 @@ else
LDFLAGS += $(SDK_LD)
endif
+COMPILER_TYPE=$(shell $(CC) --version|grep "Free Software Foundation")
+ifneq "$(COMPILER_TYPE)" ""
+ #$(info gcc is being used)
+ CFLAGS_OPT += -Wno-error=format-truncation -Wno-format-truncation
+endif
+
ifeq "$(SYS)" "SunOS"
- CFLAGS_OPT += -Wno-format-truncation
- LDFLAGS = -lkstat -lrt
+ LDFLAGS = -lkstat -lrt -lsocket -lnsl
endif
ifdef STATIC
@@ -146,7 +150,7 @@ else
endif
override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wno-pointer-arith \
- -fPIC -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
+ -fPIC -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
-DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
# -fstack-protector
@@ -181,13 +185,13 @@ AFL_FUZZ_FILES = $(wildcard src/afl-fuzz*.c)
ifneq "$(shell command -v python3m 2>/dev/null)" ""
ifneq "$(shell command -v python3m-config 2>/dev/null)" ""
- PYTHON_INCLUDE ?= $(shell python3m-config --includes)
- PYTHON_VERSION ?= $(strip $(shell python3m --version 2>&1))
+ PYTHON_INCLUDE := $(shell python3m-config --includes)
+ PYTHON_VERSION := $(strip $(shell python3m --version 2>&1))
# Starting with python3.8, we need to pass the `embed` flag. Earlier versions didn't know this flag.
ifeq "$(shell python3m-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1"
- PYTHON_LIB ?= $(shell python3m-config --libs --embed --ldflags)
+ PYTHON_LIB := $(shell python3m-config --libs --embed --ldflags)
else
- PYTHON_LIB ?= $(shell python3m-config --ldflags)
+ PYTHON_LIB := $(shell python3m-config --ldflags)
endif
endif
endif
@@ -195,13 +199,13 @@ endif
ifeq "$(PYTHON_INCLUDE)" ""
ifneq "$(shell command -v python3 2>/dev/null)" ""
ifneq "$(shell command -v python3-config 2>/dev/null)" ""
- PYTHON_INCLUDE ?= $(shell python3-config --includes)
- PYTHON_VERSION ?= $(strip $(shell python3 --version 2>&1))
- # Starting with python3.8, we need to pass the `embed` flag. Earier versions didn't know this flag.
+ PYTHON_INCLUDE := $(shell python3-config --includes)
+ PYTHON_VERSION := $(strip $(shell python3 --version 2>&1))
+ # Starting with python3.8, we need to pass the `embed` flag. Earlier versions didn't know this flag.
ifeq "$(shell python3-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1"
- PYTHON_LIB ?= $(shell python3-config --libs --embed --ldflags)
+ PYTHON_LIB := $(shell python3-config --libs --embed --ldflags)
else
- PYTHON_LIB ?= $(shell python3-config --ldflags)
+ PYTHON_LIB := $(shell python3-config --ldflags)
endif
endif
endif
@@ -210,9 +214,9 @@ endif
ifeq "$(PYTHON_INCLUDE)" ""
ifneq "$(shell command -v python 2>/dev/null)" ""
ifneq "$(shell command -v python-config 2>/dev/null)" ""
- PYTHON_INCLUDE ?= $(shell python-config --includes)
- PYTHON_LIB ?= $(shell python-config --ldflags)
- PYTHON_VERSION ?= $(strip $(shell python --version 2>&1))
+ PYTHON_INCLUDE := $(shell python-config --includes)
+ PYTHON_LIB := $(shell python-config --ldflags)
+ PYTHON_VERSION := $(strip $(shell python --version 2>&1))
endif
endif
endif
@@ -221,9 +225,9 @@ endif
ifeq "$(PYTHON_INCLUDE)" ""
ifneq "$(shell command -v python3.7 2>/dev/null)" ""
ifneq "$(shell command -v python3.7-config 2>/dev/null)" ""
- PYTHON_INCLUDE ?= $(shell python3.7-config --includes)
- PYTHON_LIB ?= $(shell python3.7-config --ldflags)
- PYTHON_VERSION ?= $(strip $(shell python3.7 --version 2>&1))
+ PYTHON_INCLUDE := $(shell python3.7-config --includes)
+ PYTHON_LIB := $(shell python3.7-config --ldflags)
+ PYTHON_VERSION := $(strip $(shell python3.7 --version 2>&1))
endif
endif
endif
@@ -232,9 +236,9 @@ endif
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))
+ 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
@@ -309,10 +313,21 @@ endif
.PHONY: all
all: test_x86 test_shm test_python ready $(PROGS) afl-as llvm gcc_plugin test_build all_done
-$(MAKE) -C utils/aflpp_driver
+ @echo
+ @echo
+ @echo Build Summary:
+ @test -e afl-fuzz && echo "[+] afl-fuzz and supporting tools successfully built" || echo "[-] afl-fuzz could not be built, please set CC to a working compiler"
+ @test -e afl-llvm-pass.so && echo "[+] LLVM basic mode successfully built" || echo "[-] LLVM mode could not be built, please install at least llvm-11 and clang-11 or newer, see docs/INSTALL.md"
+ @test -e SanitizerCoveragePCGUARD.so && echo "[+] LLVM mode successfully built" || echo "[-] LLVM mode could not be built, please install at least llvm-11 and clang-11 or newer, see docs/INSTALL.md"
+ @test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode successfully built" || echo "[-] LLVM LTO mode could not be built, it is optional, if you want it, please install LLVM and LLD 11+. More information at instrumentation/README.lto.md on how to build it"
+ifneq "$(SYS)" "Darwin"
+ @test -e afl-gcc-pass.so && echo "[+] gcc_mode successfully built" || echo "[-] gcc_mode could not be built, it is optional, install gcc-VERSION-plugin-dev to enable this"
+endif
+ @echo
.PHONY: llvm
llvm:
- -$(MAKE) -j4 -f GNUmakefile.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; }
.PHONY: gcc_plugin
@@ -347,7 +362,7 @@ performance-test: source-only
help:
@echo "HELP --- the following make targets exist:"
@echo "=========================================="
- @echo "all: the main afl++ binaries and llvm/gcc instrumentation"
+ @echo "all: the main AFL++ binaries and llvm/gcc instrumentation"
@echo "binary-only: everything for binary-only fuzzing: frida_mode, nyx_mode, qemu_mode, frida_mode, unicorn_mode, coresight_mode, libdislocator, libtokencap"
@echo "source-only: everything for source code fuzzing: nyx_mode, libdislocator, libtokencap"
@echo "distrib: everything (for both binary-only and source code fuzzing)"
@@ -355,7 +370,7 @@ help:
@echo "install: installs everything you have compiled with the build option above"
@echo "clean: cleans everything compiled (not downloads when on a checkout)"
@echo "deepclean: cleans everything including downloads"
- @echo "uninstall: uninstall afl++ from the system"
+ @echo "uninstall: uninstall AFL++ from the system"
@echo "code-format: format the code, do this before you commit and send a PR please!"
@echo "tests: this runs the test framework. It is more catered for the developers, but if you run into problems this helps pinpointing the problem"
@echo "unit: perform unit tests (based on cmocka and GNU linker)"
@@ -367,17 +382,23 @@ help:
@echo Known build environment options:
@echo "=========================================="
@echo STATIC - compile AFL++ static
- @echo ASAN_BUILD - compiles with memory sanitizer for debug purposes
+ @echo "CODE_COVERAGE - compile the target for code coverage (see docs/instrumentation/README.llvm.md)"
+ @echo ASAN_BUILD - compiles AFL++ with memory sanitizer for debug purposes
+ @echo UBSAN_BUILD - compiles AFL++ tools with undefined behaviour sanitizer for debug purposes
@echo DEBUG - no optimization, -ggdb3, all warnings and -Werror
+ @echo LLVM_DEBUG - shows llvm deprecation warnings
@echo PROFILING - compile afl-fuzz with profiling information
@echo INTROSPECTION - compile afl-fuzz with mutation introspection
@echo NO_PYTHON - disable python support
@echo NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
@echo NO_NYX - disable building nyx mode dependencies
+ @echo "NO_CORESIGHT - disable building coresight (arm64 only)"
+ @echo NO_UNICORN_ARM64 - disable building unicorn on arm64
+ @echo "WAFL_MODE - enable for WASM fuzzing with https://github.com/fgsect/WAFL"
@echo AFL_NO_X86 - if compiling on non-intel/amd platforms
- @echo "LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g. Debian)"
+ @echo "LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g., Debian)"
@echo "=========================================="
- @echo e.g.: make ASAN_BUILD=1
+ @echo e.g.: make LLVM_CONFIG=llvm-config-16
.PHONY: test_x86
ifndef AFL_NO_X86
@@ -411,12 +432,12 @@ test_python:
@echo "[+] $(PYTHON_VERSION) support seems to be working."
else
test_python:
- @echo "[-] You seem to need to install the package python3-dev, python2-dev or python-dev (and perhaps python[23]-apt), but it is optional so we continue"
+ @echo "[-] You seem to need to install the package python3-dev or python-dev (and perhaps python[3]-apt), but it is optional so we continue"
endif
.PHONY: ready
ready:
- @echo "[+] Everything seems to be working, ready to compile."
+ @echo "[+] Everything seems to be working, ready to compile. ($(shell $(CC) --version 2>&1|head -n 1))"
afl-as: src/afl-as.c include/afl-as.h $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
@@ -438,7 +459,7 @@ afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) -lm
afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
- $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS)
+ $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-fuzz-mutators.c src/afl-fuzz-python.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS)
afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS)
@@ -532,8 +553,8 @@ ifndef AFL_NO_X86
test_build: afl-cc afl-gcc afl-as afl-showmap
@echo "[*] Testing the CC wrapper afl-cc and its instrumentation output..."
@unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c $(LDFLAGS) -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 )
- ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
- echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
+ -ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -q -m none -o .test-instr0 ./test-instr < /dev/null
+ -echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
@rm -f test-instr
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation of afl-cc does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
@echo
@@ -572,12 +593,13 @@ clean:
-$(MAKE) -f GNUmakefile.gcc_plugin clean
-$(MAKE) -C utils/libdislocator clean
-$(MAKE) -C utils/libtokencap clean
- $(MAKE) -C utils/aflpp_driver clean
+ -$(MAKE) -C utils/aflpp_driver clean
-$(MAKE) -C utils/afl_network_proxy clean
-$(MAKE) -C utils/socket_fuzzing clean
-$(MAKE) -C utils/argv_fuzzing clean
-$(MAKE) -C utils/plot_ui clean
-$(MAKE) -C qemu_mode/unsigaction clean
+ -$(MAKE) -C qemu_mode/fastexit clean
-$(MAKE) -C qemu_mode/libcompcov clean
-$(MAKE) -C qemu_mode/libqasan clean
-$(MAKE) -C frida_mode clean
@@ -610,34 +632,44 @@ endif
.PHONY: distrib
distrib: all
- -$(MAKE) -j4 -f GNUmakefile.llvm
+ -$(MAKE) -j$(nproc) -f GNUmakefile.llvm
ifneq "$(SYS)" "Darwin"
-$(MAKE) -f GNUmakefile.gcc_plugin
-endif
-$(MAKE) -C utils/libdislocator
-$(MAKE) -C utils/libtokencap
+endif
-$(MAKE) -C utils/afl_network_proxy
-$(MAKE) -C utils/socket_fuzzing
-$(MAKE) -C utils/argv_fuzzing
# -$(MAKE) -C utils/plot_ui
-$(MAKE) -C frida_mode
ifneq "$(SYS)" "Darwin"
-ifeq "$(ARCH)" "aarch64"
+ ifeq "$(ARCH)" "aarch64"
+ ifndef NO_CORESIGHT
-$(MAKE) -C coresight_mode
-endif
-ifeq "$(SYS)" "Linux"
-ifndef NO_NYX
+ endif
+ endif
+ ifeq "$(SYS)" "Linux"
+ ifndef NO_NYX
-cd nyx_mode && ./build_nyx_support.sh
-endif
-endif
+ endif
+ endif
-cd qemu_mode && sh ./build_qemu_support.sh
+ ifeq "$(ARCH)" "aarch64"
+ ifndef NO_UNICORN_ARM64
-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
+ endif
+ else
+ -cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
+ endif
endif
.PHONY: binary-only
binary-only: test_shm test_python ready $(PROGS)
+ifneq "$(SYS)" "Darwin"
-$(MAKE) -C utils/libdislocator
-$(MAKE) -C utils/libtokencap
+endif
-$(MAKE) -C utils/afl_network_proxy
-$(MAKE) -C utils/socket_fuzzing
-$(MAKE) -C utils/argv_fuzzing
@@ -645,7 +677,9 @@ binary-only: test_shm test_python ready $(PROGS)
-$(MAKE) -C frida_mode
ifneq "$(SYS)" "Darwin"
ifeq "$(ARCH)" "aarch64"
+ ifndef NO_CORESIGHT
-$(MAKE) -C coresight_mode
+ endif
endif
ifeq "$(SYS)" "Linux"
ifndef NO_NYX
@@ -653,26 +687,73 @@ ifndef NO_NYX
endif
endif
-cd qemu_mode && sh ./build_qemu_support.sh
+ ifeq "$(ARCH)" "aarch64"
+ ifndef NO_UNICORN_ARM64
+ -cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
+ endif
+ else
-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
+ endif
+endif
+ @echo
+ @echo
+ @echo Build Summary:
+ @test -e afl-fuzz && echo "[+] afl-fuzz and supporting tools successfully built" || echo "[-] afl-fuzz could not be built, please set CC to a working compiler"
+ifneq "$(SYS)" "Darwin"
+ifeq "$(ARCH)" "aarch64"
+ ifndef NO_CORESIGHT
+ @test -e afl-cs-proxy && echo "[+] coresight_mode successfully built" || echo "[-] coresight_mode could not be built, it is optional and experimental, see coresight_mode/README.md for what is needed"
+ endif
+endif
+ifeq "$(SYS)" "Linux"
+ifndef NO_NYX
+ @test -e libnyx.so && echo "[+] nyx_mode successfully built" || echo "[-] nyx_mode could not be built, it is optional, see nyx_mode/README.md for what is needed"
endif
+endif
+ @test -e afl-qemu-trace && echo "[+] qemu_mode successfully built" || echo "[-] qemu_mode could not be built, see docs/INSTALL.md for what is needed"
+ ifeq "$(ARCH)" "aarch64"
+ ifndef NO_UNICORN_ARM64
+ @test -e unicorn_mode/unicornafl/build_python/libunicornafl.so && echo "[+] unicorn_mode successfully built" || echo "[-] unicorn_mode could not be built, it is optional, see unicorn_mode/README.md for what is needed"
+ endif
+ else
+ @test -e unicorn_mode/unicornafl/build_python/libunicornafl.so && echo "[+] unicorn_mode successfully built" || echo "[-] unicorn_mode could not be built, it is optional, see unicorn_mode/README.md for what is needed"
+ endif
+endif
+ @echo
.PHONY: source-only
source-only: all
- -$(MAKE) -j4 -f GNUmakefile.llvm
+ -$(MAKE) -j$(nproc) -f GNUmakefile.llvm
ifneq "$(SYS)" "Darwin"
-$(MAKE) -f GNUmakefile.gcc_plugin
-endif
-$(MAKE) -C utils/libdislocator
-$(MAKE) -C utils/libtokencap
+endif
# -$(MAKE) -C utils/plot_ui
ifeq "$(SYS)" "Linux"
ifndef NO_NYX
-cd nyx_mode && ./build_nyx_support.sh
endif
endif
+ @echo
+ @echo
+ @echo Build Summary:
+ @test -e afl-fuzz && echo "[+] afl-fuzz and supporting tools successfully built" || echo "[-] afl-fuzz could not be built, please set CC to a working compiler"
+ @test -e afl-llvm-pass.so && echo "[+] LLVM basic mode successfully built" || echo "[-] LLVM mode could not be built, please install at least llvm-11 and clang-11 or newer, see docs/INSTALL.md"
+ @test -e SanitizerCoveragePCGUARD.so && echo "[+] LLVM mode successfully built" || echo "[-] LLVM mode could not be built, please install at least llvm-11 and clang-11 or newer, see docs/INSTALL.md"
+ @test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode successfully built" || echo "[-] LLVM LTO mode could not be built, it is optional, if you want it, please install LLVM 11-14. More information at instrumentation/README.lto.md on how to build it"
+ifneq "$(SYS)" "Darwin"
+ test -e afl-gcc-pass.so && echo "[+] gcc_mode successfully built" || echo "[-] gcc_mode could not be built, it is optional, install gcc-VERSION-plugin-dev to enable this"
+endif
+ifeq "$(SYS)" "Linux"
+ifndef NO_NYX
+ @test -e libnyx.so && echo "[+] nyx_mode successfully built" || echo "[-] nyx_mode could not be built, it is optional, see nyx_mode/README.md for what is needed"
+endif
+endif
+ @echo
%.8: %
- @echo .TH $* 8 $(BUILD_DATE) "afl++" > $@
+ @echo .TH $* 8 $(BUILD_DATE) "AFL++" > $@
@echo .SH NAME >> $@
@echo .B $* >> $@
@echo >> $@
@@ -684,8 +765,8 @@ endif
@./$* -hh 2>&1 | tail -n +4 >> $@
@echo >> $@
@echo .SH AUTHOR >> $@
- @echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> $@
- @echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> $@
+ @echo "AFL++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Dominik Maier <domenukk@gmail.com>, Andrea Fioraldi <andreafioraldi@gmail.com> and Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>" >> $@
+ @echo The homepage of AFL++ is: https://github.com/AFLplusplus/AFLplusplus >> $@
@echo >> $@
@echo .SH LICENSE >> $@
@echo Apache License Version 2.0, January 2004 >> $@
@@ -696,6 +777,7 @@ install: all $(MANPAGES)
@rm -f $${DESTDIR}$(BIN_PATH)/afl-plot.sh
@rm -f $${DESTDIR}$(BIN_PATH)/afl-as
@rm -f $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt.o
+ @for i in afl-llvm-dict2file.so afl-llvm-lto-instrumentlist.so afl-llvm-pass.so cmplog-instructions-pass.so cmplog-routines-pass.so cmplog-switches-pass.so compare-transform-pass.so libcompcov.so libdislocator.so libnyx.so libqasan.so libtokencap.so SanitizerCoverageLTO.so SanitizerCoveragePCGUARD.so split-compares-pass.so split-switches-pass.so; do echo rm -fv $${DESTDIR}$(HELPER_PATH)/$${i}; done
install -m 755 $(PROGS) $(SH_PROGS) $${DESTDIR}$(BIN_PATH)
@if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi
@if [ -f utils/plot_ui/afl-plot-ui ]; then install -m 755 utils/plot_ui/afl-plot-ui $${DESTDIR}$(BIN_PATH); fi
diff --git a/GNUmakefile.gcc_plugin b/GNUmakefile.gcc_plugin
index e21203ae..41face4c 100644
--- a/GNUmakefile.gcc_plugin
+++ b/GNUmakefile.gcc_plugin
@@ -11,7 +11,7 @@
# from Laszlo Szekeres.
#
# Copyright 2015 Google Inc. All rights reserved.
-# Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+# Copyright 2019-2023 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.
@@ -28,14 +28,14 @@ MAN_PATH ?= $(PREFIX)/share/man/man8
VERSION = $(shell grep '^$(HASH)define VERSION ' ./config.h | cut -d '"' -f2)
-CFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=2
+CFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=1
CFLAGS_SAFE := -Wall -Iinclude -Wno-pointer-sign \
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
-DGCC_VERSION=\"$(GCCVER)\" -DGCC_BINDIR=\"$(GCCBINDIR)\" \
-Wno-unused-function
override CFLAGS += $(CFLAGS_SAFE)
-CXXFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=2
+CXXFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=1
CXXEFLAGS := $(CXXFLAGS) -Wall -std=c++11
CC ?= gcc
@@ -100,7 +100,9 @@ ifeq "$(SYS)" "SunOS"
endif
-PROGS = ./afl-gcc-pass.so ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o
+PASSES = ./afl-gcc-pass.so ./afl-gcc-cmplog-pass.so ./afl-gcc-cmptrs-pass.so
+
+PROGS = $(PASSES) ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o
.PHONY: all
all: test_shm test_deps $(PROGS) test_build all_done
@@ -141,6 +143,8 @@ afl-common.o: ./src/afl-common.c
@printf "[*] Building 64-bit variant of the runtime (-m64)... "
@$(CC) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
+$(PASSES): instrumentation/afl-gcc-common.h
+
./afl-gcc-pass.so: instrumentation/afl-gcc-pass.so.cc | test_deps
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
ln -sf afl-cc afl-gcc-fast
@@ -148,6 +152,12 @@ afl-common.o: ./src/afl-common.c
ln -sf afl-cc.8 afl-gcc-fast.8
ln -sf afl-cc.8 afl-g++-fast.8
+./afl-gcc-cmplog-pass.so: instrumentation/afl-gcc-cmplog-pass.so.cc | test_deps
+ $(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
+
+./afl-gcc-cmptrs-pass.so: instrumentation/afl-gcc-cmptrs-pass.so.cc | test_deps
+ $(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
+
.PHONY: test_build
test_build: $(PROGS)
@echo "[*] Testing the CC wrapper and instrumentation output..."
@@ -165,7 +175,7 @@ all_done: test_build
.NOTPARALLEL: clean
%.8: %
- @echo .TH $* 8 `date "+%Y-%m-%d"` "afl++" > ./$@
+ @echo .TH $* 8 `date "+%Y-%m-%d"` "AFL++" > ./$@
@echo .SH NAME >> ./$@
@echo .B $* >> ./$@
@echo >> ./$@
@@ -177,8 +187,8 @@ all_done: test_build
@./$* -h 2>&1 | tail -n +4 >> ./$@
@echo >> ./$@
@echo .SH AUTHOR >> ./$@
- @echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> ./$@
- @echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ./$@
+ @echo "AFL++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Dominik Maier <domenukk@gmail.com>, Andrea Fioraldi <andreafioraldi@gmail.com> and Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>" >> ./$@
+ @echo The homepage of AFL++ is: https://github.com/AFLplusplus/AFLplusplus >> ./$@
@echo >> ./$@
@echo .SH LICENSE >> ./$@
@echo Apache License Version 2.0, January 2004 >> ./$@
@@ -190,6 +200,8 @@ install: all
ln -sf afl-c++ $${DESTDIR}$(BIN_PATH)/afl-g++-fast
ln -sf afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt.o
install -m 755 ./afl-gcc-pass.so $${DESTDIR}$(HELPER_PATH)
+ install -m 755 ./afl-gcc-cmplog-pass.so $${DESTDIR}$(HELPER_PATH)
+ install -m 755 ./afl-gcc-cmptrs-pass.so $${DESTDIR}$(HELPER_PATH)
install -m 644 -T instrumentation/README.gcc_plugin.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.md
.PHONY: clean
diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm
index e775ca98..6ffac68f 100644
--- a/GNUmakefile.llvm
+++ b/GNUmakefile.llvm
@@ -45,11 +45,12 @@ endif
LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' | sed 's/svn//' )
LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//' )
LLVM_MINOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/.*\.//' | sed 's/git//' | sed 's/svn//' | sed 's/ .*//' )
-LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^[0-2]\.|^3.[0-7]\.' && echo 1 || echo 0 )
-LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[5-9]' && echo 1 || echo 0 )
-LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-9]' && echo 1 || echo 0 )
-LLVM_10_OK = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]|^10\.[1-9]|^10\.0.[1-9]' && echo 1 || echo 0 )
-LLVM_HAVE_LTO = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]' && echo 1 || echo 0 )
+LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^[0-2]\.|^3.[0-7]\.' && echo 1 || echo 0 )
+LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[7-9]' && echo 1 || echo 0 )
+LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[0-9]' && echo 1 || echo 0 )
+LLVM_NEWER_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[6-9]' && echo 1 || echo 0 )
+LLVM_13_OK = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[3-9]' && echo 1 || echo 0 )
+LLVM_HAVE_LTO = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[1-9]' && echo 1 || echo 0 )
LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)
LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir 2>/dev/null)
LLVM_STDCXX = gnu++11
@@ -81,25 +82,23 @@ ifeq "$(LLVM_NEW_API)" "1"
LLVM_TOO_OLD=0
endif
+ifeq "$(LLVM_NEWER_API)" "1"
+ $(info [+] llvm_mode detected llvm 16+, enabling c++17)
+ LLVM_STDCXX = c++17
+endif
+
ifeq "$(LLVM_TOO_OLD)" "1"
$(info [!] llvm_mode detected an old version of llvm, upgrade to at least 9 or preferable 11!)
$(shell sleep 1)
endif
-ifeq "$(LLVM_MAJOR)" "15"
- $(info [!] llvm_mode detected llvm 15, which is currently broken for LTO plugins.)
- LLVM_LTO = 0
- LLVM_HAVE_LTO = 0
-endif
-
ifeq "$(LLVM_HAVE_LTO)" "1"
$(info [+] llvm_mode detected llvm 11+, enabling afl-lto LTO implementation)
LLVM_LTO = 1
- #TEST_MMAP = 1
endif
ifeq "$(LLVM_LTO)" "0"
- $(info [+] llvm_mode detected llvm < 11 or llvm 15, afl-lto LTO will not be build.)
+ $(info [+] llvm_mode detected llvm < 11, afl-lto LTO will not be build.)
endif
ifeq "$(LLVM_APPLE_XCODE)" "1"
@@ -220,6 +219,17 @@ ifeq "$(LLVM_LTO)" "1"
ifeq "$(AFL_REAL_LD)" ""
ifneq "$(shell readlink $(LLVM_BINDIR)/ld.lld 2>&1)" ""
AFL_REAL_LD = $(LLVM_BINDIR)/ld.lld
+ else ifneq "$(shell command -v ld.lld 2>/dev/null)" ""
+ AFL_REAL_LD = $(shell command -v ld.lld)
+ TMP_LDLDD_VERSION = $(shell $(AFL_REAL_LD) --version | awk '{ print $$2 }')
+ ifeq "$(LLVMVER)" "$(TMP_LDLDD_VERSION)"
+ $(warning ld.lld found in a weird location ($(AFL_REAL_LD)), but its the same version as LLVM so we will allow it)
+ else
+ $(warning ld.lld found in a weird location ($(AFL_REAL_LD)) and its of a different version than LLMV ($(TMP_LDLDD_VERSION) vs. $(LLVMVER)) - cannot enable LTO mode)
+ AFL_REAL_LD=
+ LLVM_LTO = 0
+ endif
+ undefine TMP_LDLDD_VERSION
else
$(warning ld.lld not found, cannot enable LTO mode)
LLVM_LTO = 0
@@ -235,7 +245,7 @@ AFL_CLANG_FUSELD=
ifeq "$(LLVM_LTO)" "1"
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fuse-ld=`command -v ld` -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
AFL_CLANG_FUSELD=1
- ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fuse-ld=ld.lld --ld-path=$(LLVM_BINDIR)/ld.lld -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
+ ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fuse-ld=ld.lld --ld-path=$(AFL_REAL_LD) -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
AFL_CLANG_LDPATH=1
endif
else
@@ -250,26 +260,34 @@ else
AFL_CLANG_DEBUG_PREFIX =
endif
-CFLAGS ?= -O3 -funroll-loops -fPIC -D_FORTIFY_SOURCE=2
-CFLAGS_SAFE := -Wall -g -Wno-cast-qual -Wno-variadic-macros -Wno-pointer-sign -I ./include/ -I ./instrumentation/ \
+CFLAGS ?= -O3 -funroll-loops -fPIC -D_FORTIFY_SOURCE=1
+CFLAGS_SAFE := -Wall -g -Wno-cast-qual -Wno-variadic-macros -Wno-pointer-sign \
+ -I ./include/ -I ./instrumentation/ \
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
-DLLVM_BINDIR=\"$(LLVM_BINDIR)\" -DVERSION=\"$(VERSION)\" \
-DLLVM_LIBDIR=\"$(LLVM_LIBDIR)\" -DLLVM_VERSION=\"$(LLVMVER)\" \
- -Wno-deprecated -DAFL_CLANG_FLTO=\"$(AFL_CLANG_FLTO)\" \
- -DAFL_REAL_LD=\"$(AFL_REAL_LD)\" \
- -DAFL_CLANG_LDPATH=\"$(AFL_CLANG_LDPATH)\" \
- -DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" \
- -DCLANG_BIN=\"$(CLANG_BIN)\" -DCLANGPP_BIN=\"$(CLANGPP_BIN)\" -DUSE_BINDIR=$(USE_BINDIR) -Wno-unused-function \
- $(AFL_CLANG_DEBUG_PREFIX)
+ -DAFL_CLANG_FLTO=\"$(AFL_CLANG_FLTO)\" -DAFL_REAL_LD=\"$(AFL_REAL_LD)\" \
+ -DAFL_CLANG_LDPATH=\"$(AFL_CLANG_LDPATH)\" -DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" \
+ -DCLANG_BIN=\"$(CLANG_BIN)\" -DCLANGPP_BIN=\"$(CLANGPP_BIN)\" -DUSE_BINDIR=$(USE_BINDIR) \
+ -Wno-unused-function $(AFL_CLANG_DEBUG_PREFIX)
+ifndef LLVM_DEBUG
+ CFLAGS_SAFE += -Wno-deprecated
+endif
+
+ifdef CODE_COVERAGE
+ override CFLAGS_SAFE += -D__AFL_CODE_COVERAGE=1
+ override LDFLAGS += -ldl
+endif
+
override CFLAGS += $(CFLAGS_SAFE)
ifdef AFL_TRACE_PC
$(info Compile option AFL_TRACE_PC is deprecated, just set AFL_LLVM_INSTRUMENT=PCGUARD to activate when compiling targets )
endif
-CXXFLAGS ?= -O3 -funroll-loops -fPIC -D_FORTIFY_SOURCE=2
+CXXFLAGS ?= -O3 -funroll-loops -fPIC -D_FORTIFY_SOURCE=1
override CXXFLAGS += -Wall -g -I ./include/ \
- -DVERSION=\"$(VERSION)\" -Wno-variadic-macros \
+ -DVERSION=\"$(VERSION)\" -Wno-variadic-macros -Wno-deprecated-copy-with-dtor \
-DLLVM_MINOR=$(LLVM_MINOR) -DLLVM_MAJOR=$(LLVM_MAJOR)
ifneq "$(shell $(LLVM_CONFIG) --includedir) 2> /dev/null" ""
@@ -281,6 +299,11 @@ endif
CLANG_CPPFL = `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC $(CXXFLAGS) -Wno-deprecated-declarations
CLANG_LFL = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS)
+# wasm fuzzing: disable thread-local storage and unset LLVM debug flag
+ifdef WAFL_MODE
+ $(info Compiling libraries for use with WAVM)
+ CLANG_CPPFL += -DNDEBUG -DNO_TLS
+endif
# User teor2345 reports that this is required to make things work on MacOS X.
ifeq "$(SYS)" "Darwin"
@@ -399,7 +422,7 @@ endif
$(CXX) $(CLANG_CPPFL) -Wdeprecated -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
./SanitizerCoveragePCGUARD.so: instrumentation/SanitizerCoveragePCGUARD.so.cc instrumentation/afl-llvm-common.o | test_deps
-ifeq "$(LLVM_10_OK)" "1"
+ifeq "$(LLVM_13_OK)" "1"
-$(CXX) $(CLANG_CPPFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) -Wno-deprecated-copy-dtor -Wdeprecated instrumentation/afl-llvm-common.o
endif
@@ -492,7 +515,7 @@ install: all
install -m 644 instrumentation/README.*.md $${DESTDIR}$(DOC_PATH)/
%.8: %
- @echo .TH $* 8 $(BUILD_DATE) "afl++" > ./$@
+ @echo .TH $* 8 $(BUILD_DATE) "AFL++" > ./$@
@echo .SH NAME >> ./$@
@printf "%s" ".B $* \- " >> ./$@
@./$* -h 2>&1 | head -n 1 | sed -e "s/$$(printf '\e')[^m]*m//g" >> ./$@
@@ -506,8 +529,8 @@ install: all
@./$* -h 2>&1 | tail -n +4 >> ./$@
@echo >> ./$@
@echo .SH AUTHOR >> ./$@
- @echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>, Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <domenukk@gmail.com>" >> ./$@
- @echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ./$@
+ @echo "AFL++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse <mh@mh-sec.de>, Dominik Maier <domenukk@gmail.com>, Andrea Fioraldi <andreafioraldi@gmail.com> and Heiko \"hexcoder-\" Eissfeldt <heiko.eissfeldt@hexco.de>" >> ./$@
+ @echo The homepage of AFL++ is: https://github.com/AFLplusplus/AFLplusplus >> ./$@
@echo >> ./$@
@echo .SH LICENSE >> ./$@
@echo Apache License Version 2.0, January 2004 >> ./$@
diff --git a/METADATA b/METADATA
index 06830cc4..a15779f8 100644
--- a/METADATA
+++ b/METADATA
@@ -14,9 +14,9 @@ third_party: {
value: "https://github.com/AFLplusplus/AFLplusplus"
}
license_type: NOTICE
- version: "ba3c7bfe40f9b17a691958e3525828385127ad25"
+ version: "26cbc1e99337da4dc82c7c827dc2dac0a3733dc2"
last_upgrade_date {
- year: 2022
+ year: 2023
month: 6
day: 6
}
diff --git a/README.md b/README.md
index a29ce792..0208a9fe 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,10 @@
# American Fuzzy Lop plus plus (AFL++)
-<img align="right" src="https://raw.githubusercontent.com/AFLplusplus/Website/master/static/aflpp_bg.svg" alt="AFL++ logo" width="250" heigh="250">
+<img align="right" src="https://raw.githubusercontent.com/AFLplusplus/Website/main/static/aflpp_bg.svg" alt="AFL++ logo" width="250" heigh="250">
-Release version: [4.00c](https://github.com/AFLplusplus/AFLplusplus/releases)
+Release version: [4.06c](https://github.com/AFLplusplus/AFLplusplus/releases)
-GitHub version: 4.01a
+GitHub version: 4.07a
Repository:
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
@@ -12,9 +12,9 @@ Repository:
AFL++ is maintained by:
* Marc "van Hauser" Heuse <mh@mh-sec.de>
-* Heiko "hexcoder-" Eißfeldt <heiko.eissfeldt@hexco.de>
* Andrea Fioraldi <andreafioraldi@gmail.com>
* Dominik Maier <mail@dmnk.co>
+* Heiko "hexcoder-" Eißfeldt <heiko.eissfeldt@hexco.de>
* Documentation: Jana Aydinbas <jana.aydinbas@gmail.com>
Originally developed by Michał "lcamtuf" Zalewski.
@@ -50,17 +50,20 @@ Here is some information to get you started:
## Building and installing AFL++
To have AFL++ easily available with everything compiled, pull the image directly
-from the Docker Hub (available for x86_64 and arm64):
+from the Docker Hub (available for both x86_64 and arm64):
```shell
docker pull aflplusplus/aflplusplus
docker run -ti -v /location/of/your/target:/src aflplusplus/aflplusplus
```
-This image is automatically generated when a push to the stable repo happens
+This image is automatically published when a push to the stable branch happens
(see [branches](#branches)). If you use the command above, you will find your
target source code in `/src` in the container.
+Note: you can also pull `aflplusplus/aflplusplus:dev` which is the most current
+development state of AFL++.
+
To build AFL++ yourself - *which we recommend* - continue at
[docs/INSTALL.md](docs/INSTALL.md).
@@ -225,6 +228,7 @@ Thank you! (For people sending pull requests - please add yourself to this list
Thomas Rooijakkers David Carlier
Ruben ten Hove Joey Jiao
fuzzah @intrigus-lgtm
+ Yaakov Saxon
```
</details>
diff --git a/TODO.md b/TODO.md
index 99d2c419..2b7e8fcf 100644
--- a/TODO.md
+++ b/TODO.md
@@ -2,18 +2,19 @@
## Should
- - better documentation for custom mutators
+ - test cmplog for less than 16bit
+ - support persistent and deferred fork server in afl-showmap?
- better autodetection of shifting runtime timeout values
- Update afl->pending_not_fuzzed for MOpt
- afl-plot to support multiple plot_data
- parallel builds for source-only targets
- get rid of check_binary, replace with more forkserver communication
+ - first fuzzer should be a main automatically? not sure.
## Maybe
- forkserver tells afl-fuzz if cmplog is supported and if so enable
it by default, with AFL_CMPLOG_NO=1 (?) set to skip?
- - afl_custom_fuzz_splice_optin()
- afl_custom_splice()
- cmdline option from-to range for mutations
diff --git a/afl-cmin b/afl-cmin
index 853c9398..ae723c1b 100755
--- a/afl-cmin
+++ b/afl-cmin
@@ -103,30 +103,38 @@ function usage() {
" -o dir - output directory for minimized files\n" \
"\n" \
"Execution control settings:\n" \
+" -T tasks - how many parallel tasks to run (default: 1, all=nproc)\n" \
" -f file - location read by the fuzzed program (stdin)\n" \
" -m megs - memory limit for child process ("mem_limit" MB)\n" \
-" -t msec - run time limit for child process (none)\n" \
+" -t msec - run time limit for child process (default: 5000)\n" \
" -O - use binary-only instrumentation (FRIDA mode)\n" \
" -Q - use binary-only instrumentation (QEMU mode)\n" \
" -U - use unicorn-based instrumentation (unicorn mode)\n" \
+" -X - use Nyx mode\n" \
"\n" \
"Minimization settings:\n" \
+" -A - allow crashes and timeouts (not recommended)\n" \
" -C - keep crashing inputs, reject everything else\n" \
" -e - solve for edge coverage only, ignore hit counts\n" \
"\n" \
"For additional tips, please consult README.md\n" \
"\n" \
"Environment variables used:\n" \
-"AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n" \
"AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" \
"AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the forkserver to come up\n" \
"AFL_KEEP_TRACES: leave the temporary <out_dir>/.traces directory\n" \
"AFL_KILL_SIGNAL: Signal delivered to child processes on timeout (default: SIGKILL)\n" \
+"AFL_FORK_SERVER_KILL_SIGNAL: Signal delivered to fork server processes on\n" \
+" termination (default: SIGTERM). If this is not set and AFL_KILL_SIGNAL is\n" \
+" set, this will be set to the same value as AFL_KILL_SIGNAL.\n" \
"AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n" \
+"AFL_CMIN_ALLOW_ANY: write tuples for crashing inputs also\n" \
"AFL_PATH: path for the afl-showmap binary if not found anywhere in PATH\n" \
"AFL_PRINT_FILENAMES: If set, the filename currently processed will be " \
"printed to stdout\n" \
"AFL_SKIP_BIN_CHECK: skip afl instrumentation checks for target binary\n"
+"AFL_CUSTOM_MUTATOR_LIBRARY: custom mutator library (post_process and send)\n"
+"AFL_PYTHON_MODULE: custom mutator library (post_process and send)\n"
exit 1
}
@@ -135,22 +143,35 @@ function exists_and_is_executable(binarypath) {
}
BEGIN {
- print "corpus minimization tool for afl++ (awk version)\n"
+ if (0 != system( "test -t 1")) {
+ redirected = 1
+ } else {
+ redirected = 0
+ }
+
+ print "corpus minimization tool for AFL++ (awk version)\n"
# defaults
extra_par = ""
AFL_CMIN_CRASHES_ONLY = ""
+ AFL_CMIN_ALLOW_ANY = ""
# process options
Opterr = 1 # default is to diagnose
Optind = 1 # skip ARGV[0]
- while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eCOQU?")) != -1) {
+ while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eACOQUXYT:?")) != -1) {
if (_go_c == "i") {
if (!Optarg) usage()
if (in_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
in_dir = Optarg
continue
} else
+ if (_go_c == "T") {
+ if (!Optarg) usage()
+ if (threads) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
+ threads = Optarg
+ continue
+ } else
if (_go_c == "o") {
if (!Optarg) usage()
if (out_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
@@ -180,6 +201,10 @@ BEGIN {
AFL_CMIN_CRASHES_ONLY = "AFL_CMIN_CRASHES_ONLY=1 "
continue
} else
+ if (_go_c == "A") {
+ AFL_CMIN_ALLOW_ANY = "AFL_CMIN_ALLOW_ANY=1 "
+ continue
+ } else
if (_go_c == "e") {
extra_par = extra_par " -e"
continue
@@ -201,6 +226,12 @@ BEGIN {
extra_par = extra_par " -U"
unicorn_mode = 1
continue
+ } else
+ if (_go_c == "X" || _go_c == "Y") {
+ if (nyx_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
+ extra_par = extra_par " -X"
+ nyx_mode = 1
+ continue
} else
if (_go_c == "?") {
exit 1
@@ -209,7 +240,7 @@ BEGIN {
} # while options
if (!mem_limit) mem_limit = "none"
- if (!timeout) timeout = "none"
+ if (!timeout) timeout = "5000"
# get program args
i = 0
@@ -228,21 +259,30 @@ BEGIN {
# Do a sanity check to discourage the use of /tmp, since we can't really
# handle this safely from an awk script.
- if (!ENVIRON["AFL_ALLOW_TMP"]) {
- dirlist[0] = in_dir
- dirlist[1] = target_bin
- dirlist[2] = out_dir
- dirlist[3] = stdin_file
- "pwd" | getline dirlist[4] # current directory
- for (dirind in dirlist) {
- dir = dirlist[dirind]
-
- if (dir ~ /^(\/var)?\/tmp/) {
- print "[-] Error: do not use this script in /tmp or /var/tmp." > "/dev/stderr"
- exit 1
- }
- }
- delete dirlist
+ #if (!ENVIRON["AFL_ALLOW_TMP"]) {
+ # dirlist[0] = in_dir
+ # dirlist[1] = target_bin
+ # dirlist[2] = out_dir
+ # dirlist[3] = stdin_file
+ # "pwd" | getline dirlist[4] # current directory
+ # for (dirind in dirlist) {
+ # dir = dirlist[dirind]
+ #
+ # if (dir ~ /^(\/var)?\/tmp/) {
+ # print "[-] Error: do not use this script in /tmp or /var/tmp." > "/dev/stderr"
+ # exit 1
+ # }
+ # }
+ # delete dirlist
+ #}
+
+ if (threads && stdin_file) {
+ print "[-] Error: -T and -f cannot be used together." > "/dev/stderr"
+ exit 1
+ }
+
+ if (!threads && !stdin_file && !nyx_mode) {
+ print "[*] Are you aware of the '-T all' parallelize option that improves the speed for large/slow corpuses?"
}
# If @@ is specified, but there's no -f, let's come up with a temporary input
@@ -275,7 +315,8 @@ BEGIN {
exit 1
}
- if (target_bin && !exists_and_is_executable(target_bin)) {
+
+ if (!nyx_mode && target_bin && !exists_and_is_executable(target_bin)) {
"command -v "target_bin" 2>/dev/null" | getline tnew
if (!tnew || !exists_and_is_executable(tnew)) {
@@ -285,7 +326,17 @@ BEGIN {
target_bin = tnew
}
- if (!ENVIRON["AFL_SKIP_BIN_CHECK"] && !qemu_mode && !frida_mode && !unicorn_mode) {
+ if (0 == system ( "grep -aq AFL_DUMP_MAP_SIZE " target_bin )) {
+ echo "[!] Trying to obtain the map size of the target ..."
+ get_map_size = "AFL_DUMP_MAP_SIZE=1 " target_bin
+ get_map_size | getline mapsize
+ if (mapsize && mapsize > 65535 && mapsize < 100000000) {
+ AFL_MAP_SIZE = "AFL_MAP_SIZE="mapsize" "
+ print "[+] Setting "AFL_MAP_SIZE
+ }
+ }
+
+ if (!ENVIRON["AFL_SKIP_BIN_CHECK"] && !qemu_mode && !frida_mode && !unicorn_mode && !nyx_mode) {
if (0 != system( "grep -q __AFL_SHM_ID "target_bin )) {
print "[-] Error: binary '"target_bin"' doesn't appear to be instrumented." > "/dev/stderr"
exit 1
@@ -314,6 +365,18 @@ BEGIN {
exit 1
}
+ if (threads) {
+ "nproc" | getline nproc
+ if (threads == "all") {
+ threads = nproc
+ } else {
+ if (!(threads > 1 && threads <= nproc)) {
+ print "[-] Error: -T option must be between 1 and "nproc" or \"all\"." > "/dev/stderr"
+ exit 1
+ }
+ }
+ }
+
# Check for the more efficient way to copy files...
if (0 != system("mkdir -p -m 0700 "trace_dir)) {
print "[-] Error: Cannot create directory "trace_dir > "/dev/stderr"
@@ -393,10 +456,10 @@ BEGIN {
print "[*] Testing the target binary..."
if (!stdin_file) {
- system( "AFL_CMIN_ALLOW_ANY=1 "AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/.run_test\" -Z "extra_par" -- \""target_bin"\" "prog_args_string" <\""in_dir"/"first_file"\"")
+ system(AFL_MAP_SIZE "AFL_CMIN_ALLOW_ANY=1 "AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/.run_test\" -Z "extra_par" -- \""target_bin"\" "prog_args_string" <\""in_dir"/"first_file"\"")
} else {
system("cp \""in_dir"/"first_file"\" "stdin_file)
- system( "AFL_CMIN_ALLOW_ANY=1 "AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/.run_test\" -Z "extra_par" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null")
+ system(AFL_MAP_SIZE "AFL_CMIN_ALLOW_ANY=1 "AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/.run_test\" -Z "extra_par" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null")
}
first_count = 0
@@ -423,27 +486,79 @@ BEGIN {
# STEP 1: Collecting traces #
#############################
+ if (threads) {
+
+ inputsperfile = in_count / threads
+ if (in_count % threads) {
+ inputsperfile++;
+ }
+
+ cnt = 0;
+ tmpfile=out_dir "/.filelist"
+ for (instance = 1; instance < threads; instance++) {
+ for (i = 0; i < inputsperfile; i++) {
+ print in_dir"/"infilesSmallToBigFull[cnt] >> tmpfile"."instance
+ cnt++
+ }
+ }
+ for (; cnt < in_count; cnt++) {
+ print in_dir"/"infilesSmallToBigFull[cnt] >> tmpfile"."threads
+ }
+
+ }
+
print "[*] Obtaining traces for "in_count" input files in '"in_dir"'."
cur = 0;
- if (!stdin_file) {
- print " Processing "in_count" files (forkserver mode)..."
-# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string
- retval = system( AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string)
+
+ if (threads > 1) {
+
+ print "[*] Creating " threads " parallel tasks with about " inputsperfile " each."
+ for (i = 1; i <= threads; i++) {
+
+ if (!stdin_file) {
+# print " { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -- \""target_bin"\" "prog_args_string"; > "tmpfile"."i".done ; } &"
+ retval = system(" { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -- \""target_bin"\" "prog_args_string"; > "tmpfile"."i".done ; } &")
+ } else {
+ stdin_file=tmpfile"."i".stdin"
+# print " { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null; > "tmpfile"."i".done ; } &"
+ retval = system(" { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null; > "tmpfile"."i".done ; } &")
+ }
+ }
+ print "[*] Waiting for parallel tasks to complete ..."
+ # wait for all processes to finish
+ ok=0
+ while (ok < threads) {
+ ok=0
+ for (i = 1; i <= threads; i++) {
+ if (system("test -f "tmpfile"."i".done") == 0) {
+ ok++
+ }
+ }
+ }
+ print "[*] Done!"
+ system("rm -f "tmpfile"*")
} else {
- print " Processing "in_count" files (forkserver mode)..."
+ if (!stdin_file) {
+ print " Processing "in_count" files (forkserver mode)..."
+# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string
+ retval = system(AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string)
+ } else {
+ print " Processing "in_count" files (forkserver mode)..."
# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null"
- retval = system( AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null")
- }
+ retval = system(AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null")
+ }
- if (retval && !AFL_CMIN_CRASHES_ONLY) {
- print "[!] Exit code "retval" != 0 received from afl-showmap, terminating..."
+ if (retval && (!AFL_CMIN_CRASHES_ONLY && !AFL_CMIN_ALLOW_ANY)) {
+ print "[!] Exit code "retval" != 0 received from afl-showmap (this means a crashing or timeout input is likely present), terminating..."
- if (!ENVIRON["AFL_KEEP_TRACES"]) {
- system("rm -rf "trace_dir" 2>/dev/null")
- system("rmdir "out_dir)
+ if (!ENVIRON["AFL_KEEP_TRACES"]) {
+ system("rm -rf "trace_dir" 2>/dev/null")
+ system("rmdir "out_dir)
+ }
+ exit retval
}
- exit retval
+
}
#######################################################
@@ -463,7 +578,8 @@ BEGIN {
while (cur < in_count) {
fn = infilesSmallToBig[cur]
++cur
- printf "\r Processing file "cur"/"in_count
+ if (redirected == 0) { printf "\r Processing file "cur"/"in_count }
+ else { print " Processing file "cur"/"in_count }
# create path for the trace file from afl-showmap
tracefile_path = trace_dir"/"fn
# gather all keys, and count them
@@ -502,7 +618,9 @@ BEGIN {
key = field[nrFields]
++tcnt;
- printf "\r Processing tuple "tcnt"/"tuple_count" with count "key_count[key]"..."
+ if (redirected == 0) { printf "\r Processing tuple "tcnt"/"tuple_count" with count "key_count[key]"..." }
+ else { print " Processing tuple "tcnt"/"tuple_count" with count "key_count[key]"..." }
+
if (key in keyAlreadyKnown) {
continue
}
@@ -525,7 +643,6 @@ BEGIN {
}
}
close(sortedKeys)
- print ""
print "[+] Found "tuple_count" unique tuples across "in_count" files."
if (out_count == 1) {
diff --git a/afl-cmin.bash b/afl-cmin.bash
index 9ac65199..dc6d5342 100755
--- a/afl-cmin.bash
+++ b/afl-cmin.bash
@@ -7,6 +7,8 @@
#
# Copyright 2014, 2015 Google Inc. All rights reserved.
#
+# Copyright 2019-2023 AFLplusplus
+#
# 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:
@@ -36,7 +38,7 @@
# array sizes.
#
-echo "corpus minimization tool for afl-fuzz by Michal Zalewski"
+echo "corpus minimization tool for afl-fuzz"
echo
#########
@@ -46,14 +48,14 @@ echo
# Process command-line options...
MEM_LIMIT=none
-TIMEOUT=none
+TIMEOUT=5000
-unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN \
- AFL_CMIN_CRASHES_ONLY AFL_CMIN_ALLOW_ANY QEMU_MODE UNICORN_MODE
+unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN F_ARG \
+ AFL_CMIN_CRASHES_ONLY AFL_CMIN_ALLOW_ANY QEMU_MODE UNICORN_MODE T_ARG
export AFL_QUIET=1
-while getopts "+i:o:f:m:t:eOQUCh" opt; do
+while getopts "+i:o:f:m:t:T:eOQUAChXY" opt; do
case "$opt" in
@@ -69,6 +71,7 @@ while getopts "+i:o:f:m:t:eOQUCh" opt; do
;;
"f")
STDIN_FILE="$OPTARG"
+ F_ARG=1
;;
"m")
MEM_LIMIT="$OPTARG"
@@ -80,6 +83,9 @@ while getopts "+i:o:f:m:t:eOQUCh" opt; do
"e")
EXTRA_PAR="$EXTRA_PAR -e"
;;
+ "A")
+ export AFL_CMIN_ALLOW_ANY=1
+ ;;
"C")
export AFL_CMIN_CRASHES_ONLY=1
;;
@@ -91,10 +97,21 @@ while getopts "+i:o:f:m:t:eOQUCh" opt; do
EXTRA_PAR="$EXTRA_PAR -Q"
QEMU_MODE=1
;;
+ "Y")
+ EXTRA_PAR="$EXTRA_PAR -X"
+ NYX_MODE=1
+ ;;
+ "X")
+ EXTRA_PAR="$EXTRA_PAR -X"
+ NYX_MODE=1
+ ;;
"U")
EXTRA_PAR="$EXTRA_PAR -U"
UNICORN_MODE=1
;;
+ "T")
+ T_ARG="$OPTARG"
+ ;;
"?")
exit 1
;;
@@ -119,15 +136,18 @@ Required parameters:
Execution control settings:
- -f file - location read by the fuzzed program (stdin)
- -m megs - memory limit for child process ($MEM_LIMIT MB)
- -t msec - run time limit for child process (none)
+ -T tasks - how many parallel processes to create (default=1, "all"=nproc)
+ -f file - location read by the fuzzed program (default: stdin)
+ -m megs - memory limit for child process (default=$MEM_LIMIT MB)
+ -t msec - run time limit for child process (default: 5000ms)
-O - use binary-only instrumentation (FRIDA mode)
-Q - use binary-only instrumentation (QEMU mode)
-U - use unicorn-based instrumentation (Unicorn mode)
+ -X - use Nyx mode
Minimization settings:
+ -A - allow crashing and timeout inputs
-C - keep crashing inputs, reject everything else
-e - solve for edge coverage only, ignore hit counts
@@ -138,6 +158,8 @@ AFL_KEEP_TRACES: leave the temporary <out_dir>\.traces directory
AFL_NO_FORKSRV: run target via execve instead of using the forkserver
AFL_PATH: last resort location to find the afl-showmap binary
AFL_SKIP_BIN_CHECK: skip check for target binary
+AFL_CUSTOM_MUTATOR_LIBRARY: custom mutator library (post_process and send)
+AFL_PYTHON_MODULE: custom mutator library (post_process and send)
_EOF_
exit 1
fi
@@ -184,6 +206,11 @@ fi
# Check for obvious errors.
+if [ ! "$T_ARG" = "" -a -n "$F_ARG" -a ! "$NYX_MODE" == 1 ]; then
+ echo "[-] Error: -T and -f can not be used together." 1>&2
+ exit 1
+fi
+
if [ ! "$MEM_LIMIT" = "none" ]; then
if [ "$MEM_LIMIT" -lt "5" ]; then
@@ -202,20 +229,32 @@ if [ ! "$TIMEOUT" = "none" ]; then
fi
-if [ ! -f "$TARGET_BIN" -o ! -x "$TARGET_BIN" ]; then
+if [ "$NYX_MODE" = "" ]; then
+ if [ ! -f "$TARGET_BIN" -o ! -x "$TARGET_BIN" ]; then
- TNEW="`which "$TARGET_BIN" 2>/dev/null`"
+ TNEW="`which "$TARGET_BIN" 2>/dev/null`"
- if [ ! -f "$TNEW" -o ! -x "$TNEW" ]; then
- echo "[-] Error: binary '$TARGET_BIN' not found or not executable." 1>&2
- exit 1
- fi
+ if [ ! -f "$TNEW" -o ! -x "$TNEW" ]; then
+ echo "[-] Error: binary '$TARGET_BIN' not found or not executable." 1>&2
+ exit 1
+ fi
- TARGET_BIN="$TNEW"
+ TARGET_BIN="$TNEW"
+
+ fi
fi
-if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" -a "$FRIDA_MODE" = "" -a "$UNICORN_MODE" = "" ]; then
+grep -aq AFL_DUMP_MAP_SIZE "$TARGET_BIN" && {
+ echo "[!] Trying to obtain the map size of the target ..."
+ MAPSIZE=`AFL_DUMP_MAP_SIZE=1 "./$TARGET_BIN" 2>/dev/null`
+ test -n "$MAPSIZE" && {
+ export AFL_MAP_SIZE=$MAPSIZE
+ echo "[+] Setting AFL_MAP_SIZE=$MAPSIZE"
+ }
+}
+
+if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" -a "$FRIDA_MODE" = "" -a "$UNICORN_MODE" = "" -a "$NYX_MODE" = "" ]; then
if ! grep -qF "__AFL_SHM_ID" "$TARGET_BIN"; then
echo "[-] Error: binary '$TARGET_BIN' doesn't appear to be instrumented." 1>&2
@@ -272,14 +311,34 @@ if [ ! -x "$SHOWMAP" ]; then
exit 1
fi
+THREADS=
+if [ ! "$T_ARG" = "" ]; then
+ if [ "$T_ARG" = "all" ]; then
+ THREADS=$(nproc)
+ else
+ if [ "$T_ARG" -gt 1 -a "$T_ARG" -le "$(nproc)" ]; then
+ THREADS=$T_ARG
+ else
+ echo "[-] Error: -T parameter must between 2 and $(nproc) or \"all\"." 1>&2
+ fi
+ fi
+else
+ if [ -z "$F_ARG" ]; then
+ echo "[*] Are you aware of the '-T all' parallelize option that massively improves the speed?"
+ fi
+fi
+
IN_COUNT=$((`ls -- "$IN_DIR" 2>/dev/null | wc -l`))
if [ "$IN_COUNT" = "0" ]; then
- echo "[+] Hmm, no inputs in the target directory. Nothing to be done."
+ echo "[-] Hmm, no inputs in the target directory. Nothing to be done."
rm -rf "$TRACE_DIR"
exit 1
fi
+echo "[*] Are you aware that afl-cmin is faster than this afl-cmin.bash script?"
+echo "[+] Found $IN_COUNT files for minimizing."
+
FIRST_FILE=`ls "$IN_DIR" | head -1`
# Make sure that we're not dealing with a directory.
@@ -328,6 +387,18 @@ else
fi
+TMPFILE=$OUT_DIR/.list.$$
+if [ ! "$THREADS" = "" ]; then
+ ls -- "$IN_DIR" > $TMPFILE 2>/dev/null
+ IN_COUNT=$(cat $TMPFILE | wc -l)
+ SPLIT=$(($IN_COUNT / $THREADS))
+ if [ "$(($IN_COUNT % $THREADS))" -gt 0 ]; then
+ SPLIT=$(($SPLIT + 1))
+ fi
+ echo "[+] Splitting workload into $THREADS tasks with $SPLIT items on average each."
+ split -l $SPLIT $TMPFILE $TMPFILE.
+fi
+
# Let's roll!
#############################
@@ -336,6 +407,7 @@ fi
echo "[*] Obtaining traces for input files in '$IN_DIR'..."
+if [ "$THREADS" = "" ]; then
(
CUR=0
@@ -359,17 +431,58 @@ echo "[*] Obtaining traces for input files in '$IN_DIR'..."
printf "\\r Processing file $CUR/$IN_COUNT... "
cp "$IN_DIR/$fn" "$STDIN_FILE"
-
"$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -H "$STDIN_FILE" -- "$@" </dev/null
done
-
fi
+ echo
+
)
-echo
+else
+
+ PIDS=
+ CNT=0
+ for inputs in $(ls ${TMPFILE}.*); do
+
+(
+
+ if [ "$STDIN_FILE" = "" ]; then
+
+ cat $inputs | while read -r fn; do
+
+ "$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -- "$@" <"$IN_DIR/$fn"
+
+ done
+
+ else
+
+ STDIN_FILE="$inputs.$$"
+ cat $inputs | while read -r fn; do
+
+ cp "$IN_DIR/$fn" "$STDIN_FILE"
+ "$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -H "$STDIN_FILE" -- "$@" </dev/null
+
+ done
+
+ fi
+
+) &
+
+ PIDS="$PIDS $!"
+ done
+
+ echo "[+] Waiting for running tasks IDs:$PIDS"
+ wait
+ echo "[+] all $THREADS running tasks completed."
+ rm -f ${TMPFILE}*
+
+ echo trace dir files: $(ls $TRACE_DIR/*|wc -l)
+
+fi
+
##########################
# STEP 2: SORTING TUPLES #
diff --git a/afl-persistent-config b/afl-persistent-config
index fd453cbc..6d96c196 100755
--- a/afl-persistent-config
+++ b/afl-persistent-config
@@ -111,12 +111,12 @@ kernel.sched_latency_ns=250000000
EOF
}
- egrep -q '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub 2>/dev/null || echo Error: /etc/default/grub with GRUB_CMDLINE_LINUX_DEFAULT is not present, cannot set boot options
- egrep -q '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub 2>/dev/null && {
- egrep '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub | egrep -q hardened_usercopy=off || {
+ grep -E -q '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub 2>/dev/null || echo Error: /etc/default/grub with GRUB_CMDLINE_LINUX_DEFAULT is not present, cannot set boot options
+ grep -E -q '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub 2>/dev/null && {
+ grep -E '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub | grep -E -q 'noibrs pcid nopti' || {
echo "Configuring performance boot options"
- LINE=`egrep '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub | sed 's/^GRUB_CMDLINE_LINUX_DEFAULT=//' | tr -d '"'`
- OPTIONS="$LINE ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx=on tsx_async_abort=off mitigations=off audit=0 hardened_usercopy=off ssbd=force-off"
+ LINE=`grep -E '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub | sed 's/^GRUB_CMDLINE_LINUX_DEFAULT=//' | tr -d '"'`
+ OPTIONS="$LINE ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs pcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=on pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx=on tsx_async_abort=off mitigations=off audit=0 hardened_usercopy=off ssbd=force-off"
echo Setting boot options in /etc/default/grub to GRUB_CMDLINE_LINUX_DEFAULT=\"$OPTIONS\"
sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=.*|GRUB_CMDLINE_LINUX_DEFAULT=\"$OPTIONS\"|" /etc/default/grub
}
diff --git a/afl-plot b/afl-plot
index 90a46d24..230d3bfe 100755
--- a/afl-plot
+++ b/afl-plot
@@ -287,9 +287,9 @@ $PLOT_EG
_EOF_
-) | gnuplot
+) | gnuplot || echo "Note: if you see errors concerning 'unknown or ambiguous terminal type' then you need to use a gnuplot that has png support compiled in."
-echo "[?] You can also use -g flag to view the plots in an GUI window, and interact with the plots (if you have built afl-plot-ui). Run \"afl-plot-h\" to know more."
+echo "[?] You can also use -g flag to view the plots in an GUI window, and interact with the plots (if you have built afl-plot-ui). Run \"afl-plot -h\" to know more."
fi
diff --git a/afl-system-config b/afl-system-config
index ef343704..b50bb06e 100755
--- a/afl-system-config
+++ b/afl-system-config
@@ -47,9 +47,9 @@ if [ "$PLATFORM" = "Linux" ] ; then
} > /dev/null
echo Settings applied.
echo
- dmesg | egrep -q 'nospectre_v2|spectre_v2=off' || {
+ dmesg | grep -E -q 'noibrs pcid nopti' || {
echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this:
- echo ' /etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=0 l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx_async_abort=off arm64.nopauth audit=0 hardened_usercopy=off ssbd=force-off"'
+ echo ' /etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=0 l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs pcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=on pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx_async_abort=off arm64.nopauth audit=0 hardened_usercopy=off ssbd=force-off"'
echo
}
echo If you run fuzzing instances in docker, run them with \"--security-opt seccomp=unconfined\" for more speed.
@@ -110,7 +110,7 @@ if [ "$PLATFORM" = "Darwin" ] ; then
sysctl kern.sysv.shmall=131072000
echo Settings applied.
echo
- if [ $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') ] ; then
+ if $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') ; then
echo
echo Unloading the default crash reporter
SL=/System/Library; PL=com.apple.ReportCrash
@@ -118,7 +118,8 @@ if [ "$PLATFORM" = "Darwin" ] ; then
sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist >/dev/null 2>&1
echo
fi
- echo It is recommended to disable System Integration Protection for increased performance.
+ echo It is recommended to disable System Integrity Protection for increased performance.
+ echo See: https://developer.apple.com/documentation/security/disabling_and_enabling_system_integrity_protection
echo
DONE=1
fi
diff --git a/afl-whatsup b/afl-whatsup
index 160a8c74..6f29ab24 100755
--- a/afl-whatsup
+++ b/afl-whatsup
@@ -6,7 +6,7 @@
# Originally written by Michal Zalewski
#
# Copyright 2015 Google Inc. All rights reserved.
-# Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+# Copyright 2019-2023 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.
@@ -70,10 +70,10 @@ if [ -d queue ]; then
fi
-RED=`tput setaf 9 1 1`
-GREEN=`tput setaf 2 1 1`
-BLUE=`tput setaf 4 1 1`
-YELLOW=`tput setaf 11 1 1`
+RED=`tput setaf 9 1 1 2>/dev/null`
+GREEN=`tput setaf 2 1 1 2>/dev/null`
+BLUE=`tput setaf 4 1 1 2>/dev/null`
+YELLOW=`tput setaf 11 1 1 2>/dev/null`
NC=`tput sgr0`
RESET="$NC"
@@ -88,6 +88,7 @@ TOTAL_TIME=0
TOTAL_EXECS=0
TOTAL_EPS=0
TOTAL_CRASHES=0
+TOTAL_HANGS=0
TOTAL_PFAV=0
TOTAL_PENDING=0
@@ -141,7 +142,8 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
sed 's/^command_line.*$/_skip:1/;s/[ ]*:[ ]*/="/;s/$/"/' "$i" >"$TMP"
. "$TMP"
-
+ DIR=$(dirname "$i")
+ DIR=${DIR##*/}
RUN_UNIX=$run_time
RUN_DAYS=$((RUN_UNIX / 60 / 60 / 24))
RUN_HRS=$(((RUN_UNIX / 60 / 60) % 24))
@@ -154,7 +156,7 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
if [ "$SUMMARY_ONLY" = "" ]; then
- echo ">>> $afl_banner ($RUN_DAYS days, $RUN_HRS hrs) fuzzer PID: $fuzzer_pid <<<"
+ echo ">>> $afl_banner instance: $DIR ($RUN_DAYS days, $RUN_HRS hrs) fuzzer PID: $fuzzer_pid <<<"
echo
fi
@@ -189,6 +191,7 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
TOTAL_EPS=$((TOTAL_EPS + EXEC_SEC))
TOTAL_EXECS=$((TOTAL_EXECS + execs_done))
TOTAL_CRASHES=$((TOTAL_CRASHES + saved_crashes))
+ TOTAL_HANGS=$((TOTAL_HANGS + saved_hangs))
TOTAL_PENDING=$((TOTAL_PENDING + pending_total))
TOTAL_PFAV=$((TOTAL_PFAV + pending_favs))
@@ -300,6 +303,7 @@ if [ "$ALIVE_CNT" -gt "1" ]; then
fi
echo " Crashes saved : $TOTAL_CRASHES"
+echo " Hangs saved : $TOTAL_HANGS"
echo "Cycles without finds : $TOTAL_WCOP"
echo " Time without finds : $TOTAL_LAST_FIND"
echo
diff --git a/docs/Changelog.md b/docs/Changelog.md
index b18bf30f..facf2196 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -3,13 +3,154 @@
This is the list of all noteworthy changes made in every public
release of the tool. See README.md for the general instruction manual.
-## Staying informed
+### Version ++4.07a (dev)
+ - afl-fuzz:
+ - reverse reading the seeds only on restarts (increases performance)
+ - new env `AFL_POST_PROCESS_KEEP_ORIGINAL` to keep the orignal
+ data before post process on finds (for atnwalk custom mutator)
+ - new env `AFL_IGNORE_PROBLEMS_COVERAGE` to ignore coverage from
+ loaded libs after forkserver initialization (required by Mozilla)
+ - afl-cc:
+ - added @responsefile support
+ - new env `AFL_LLVM_LTO_SKIPINIT` to support the AFL++ based WASM
+ (https://github.com/fgsect/WAFL) project
+ - error and print help if afl-clan-lto is used with lto=thin
+ - rewrote our PCGUARD pass to be compatible with LLVM 15+ shenanigans,
+ requires LLVM 13+ now instead of 10.0.1+
+ - fallback to native LLVM PCGUARD if our PCGUARD is unavailable
+ - afl-showmap:
+ - added custom mutator post_process and send support
+ - add `-I filelist` option, an alternative to `-i in_dir`
+ - afl-cmin + afl-cmin.bash:
+ - `-T threads` parallel task support, can be a huge speedup!
+ - qemu_mode:
+ - Persistent mode + QASAN support for ppc32 targets by @worksbutnottested
+ - a new grammar custom mutator atnwalk was submitted by @voidptr127 !
+ - two new custom mutators are now available:
+ - TritonDSE in custom_mutators/aflpp_tritondse
+ - SymQEMU in custom_mutators/symqemu
+
-Want to stay in the loop on major new features? Join our mailing list by
-sending a mail to <afl-users+subscribe@googlegroups.com>.
+### Version ++4.06c (release)
+ - afl-fuzz:
+ - ensure temporary file descriptor is closed when not used
+ - added `AFL_NO_WARN_INSTABILITY`
+ - added time_wo_finds to fuzzer_stats
+ - fixed a crash in pizza (1st april easter egg) mode. Sorry for
+ everyone who was affected!
+ - allow pizza mode to be disabled when AFL_PIZZA_MODE is set to -1
+ - option `-p mmopt` now also selects new queue items more often
+ - fix bug in post_process custom mutator implementation
+ - print name of custom mutator in UI
+ - slight changes that improve fuzzer performance
+ - afl-cc:
+ - add CFI sanitizer variant to gcc targets
+ - llvm 16 + 17 support (thanks to @devnexen!)
+ - support llvm 15 native pcguard changes
+ - support for LLVMFuzzerTestOneInput -1 return
+ - LTO autoken and llvm_mode: added AFL_LLVM_DICT2FILE_NO_MAIN support
+ - qemu_mode:
+ - fix _RANGES envs to allow hyphens in the filenames
+ - basic riscv support
+ - frida_mode:
+ - added `AFL_FRIDA_STATS_INTERVAL`
+ - fix issue on MacOS
+ - unicorn_mode:
+ - updated and minor issues fixed
+ - nyx_mode support for all tools
+ - better sanitizer default options support for all tools
+ - new custom module: autotoken, a grammar free fuzzer for text inputs
+ - fixed custom mutator C examples
+ - more minor fixes and cross-platform support
+
+### Version ++4.05c (release)
+ - MacOS: libdislocator, libtokencap etc. do not work with modern
+ MacOS anymore, but could be patched to work, see this issue if you
+ want to make the effort and send a PR:
+ https://github.com/AFLplusplus/AFLplusplus/issues/1594
+ - afl-fuzz:
+ - added afl_custom_fuzz_send custom mutator feature. Now your can
+ send fuzz data to the target as you need, e.g. via IPC.
+ - cmplog mode now has a -l R option for random colorization, thanks
+ to guyf2010 for the PR!
+ - queue statistics are written every 30 minutes to
+ out/NAME/queue_data if compiled with INTROSPECTION
+ - new env: AFL_FORK_SERVER_KILL_SIGNAL
+ - afl-showmap/afl-cmin
+ - `-t none` now translates to `-t 120000` (120 seconds)
+ - unicorn_mode updated
+ - updated rust custom mutator dependencies and LibAFL custom mutator
+ - overall better sanitizer default setting handling
+ - several minor bugfixes
+
+### Version ++4.04c (release)
+ - fix gramatron and grammar_mutator build scripts
+ - enhancements to the afl-persistent-config and afl-system-config
+ scripts
+ - afl-fuzz:
+ - force writing all stats on exit
+ - ensure targets are killed on exit
+ - `AFL_FORK_SERVER_KILL_SIGNAL` added
+ - afl-cc:
+ - make gcc_mode (afl-gcc-fast) work with gcc down to version 3.6
+ - qemu_mode:
+ - fixed 10x speed degredation in v4.03c, thanks to @ele7enxxh for
+ reporting!
+ - added qemu_mode/fastexit helper library
+ - unicorn_mode:
+ - Enabled tricore arch (by @jma-qb)
+ - Updated Capstone version in Rust bindings
+ - llvm-mode:
+ - AFL runtime will always pass inputs via shared memory, when possible,
+ ignoring the command line.
+
+
+### Version ++4.03c (release)
+ - Building now gives a build summary what succeeded and what not
+ - afl-fuzz:
+ - added AFL_NO_STARTUP_CALIBRATION to start fuzzing at once instead
+ of calibrating all initial seeds first. Good for large queues
+ and long execution times, especially in CIs.
+ - default calibration cycles set to 7 from 8, and only add 5 cycles
+ to variables queue items instead of 12.
+ - afl-cc:
+ - fixed off-by-one bug in our pcguard implemenation, thanks for
+ @tokatoka for reporting
+ - fix for llvm 15 and reenabling LTO, thanks to nikic for the PR!
+ - better handling of -fsanitize=..,...,.. lists
+ - support added for LLVMFuzzerRunDriver()
+ - fix gcc_mode cmplog
+ - obtain the map size of a target with setting AFL_DUMP_MAP_SIZE=1
+ note that this will exit the target before main()
+ - qemu_mode:
+ - added AFL_QEMU_TRACK_UNSTABLE to log the addresses of unstable
+ edges (together with AFL_DEBUG=1 afl-fuzz). thanks to
+ worksbutnottested!
+ - afl-analyze broke at some point, fix by CodeLogicError, thank you!
+ - afl-cmin/afl-cmin.bash now have an -A option to allow also crashing
+ and timeout inputs
+ - unicorn_mode:
+ - updated upstream unicorn version
+ - fixed builds for aarch64
+ - build now uses all available cores
+
+
+### Version ++4.02c (release)
+ - afl-cc:
+ - important fix for the default pcguard mode when LLVM IR vector
+ selects are produced, thanks to @juppytt for reporting!
+ - gcc_plugin:
+ - Adacore submitted CMPLOG support to the gcc_plugin! :-)
+ - llvm_mode:
+ - laf cmp splitting fixed for more comparison types
+ - frida_mode:
+ - now works on Android!
+ - afl-fuzz:
+ - change post_process hook to allow returning NULL and 0 length to
+ tell afl-fuzz to skip this mutated input
-### Version ++4.01a (dev)
- - fix */build_...sh scripts to work outside of git
+### Version ++4.01c (release)
+ - fixed */build_...sh scripts to work outside of git
- new custom_mutator: libafl with token fuzzing :)
- afl-fuzz:
- when you just want to compile once and set CMPLOG, then just
@@ -17,6 +158,8 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
CMPLOG.
- new commandline options -g/G to set min/max length of generated
fuzz inputs
+ - you can set the time for syncing to other fuzzer now with
+ AFL_SYNC_TIME
- reintroduced AFL_PERSISTENT and AFL_DEFER_FORKSRV to allow
persistent mode and manual forkserver support if these are not
in the target binary (e.g. are in a shared library)
@@ -28,6 +171,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
kept), unless AFL_KEEP_TIMEOUTS are set
- AFL never implemented auto token inserts (but user token inserts,
user token overwrite and auto token overwrite), added now!
+ - fixed a mutation type in havoc mode
- Mopt fix to always select the correct algorithm
- fix effector map calculation (deterministic mode)
- fix custom mutator post_process functionality
@@ -41,6 +185,9 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
- update to new frida release, handles now c++ throw/catch
- unicorn_mode:
- update unicorn engine, fix C example
+ - utils:
+ - removed optimin because it looses coverage due to a bug and is
+ unmaintained :-(
### Version ++4.00c (release)
@@ -92,7 +239,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
afl-showmap and other tools.
- afl-cc:
- detect overflow reads on initial input buffer for asan
- - new cmplog mode (incompatible with older afl++ versions)
+ - new cmplog mode (incompatible with older AFL++ versions)
- support llvm IR select instrumentation for default PCGUARD and LTO
- fix for shared linking on MacOS
- better selective instrumentation AFL_LLVM_{ALLOW|DENY}LIST
diff --git a/docs/FAQ.md b/docs/FAQ.md
index 1822e46b..8178db46 100644
--- a/docs/FAQ.md
+++ b/docs/FAQ.md
@@ -171,6 +171,14 @@ If you find an interesting or important question missing, submit it via
The more "unstable" edges there are, the harder it is for AFL++ to identify
valid new paths.
+ If you fuzz in persistent mode (`AFL_LOOP` or `LLVMFuzzerTestOneInput()`
+ harnesses, a large number of unstable edges can mean that the target keeps
+ internal state and therefore it is possible that crashes cannot be replayed.
+ In such a case do either **not** fuzz in persistent mode (remove `AFL_LOOP()`
+ from your harness or call `LLVMFuzzerTestOneInput()` harnesses with `@@`),
+ or set a low `AFL_LOOP` value, e.g. 100, and enable `AFL_PERSISTENT_RECORD`
+ in `config.h` with the same value.
+
A value above 90% is usually fine and a value above 80% is also still ok, and
even a value above 20% can still result in successful finds of bugs. However,
it is recommended that for values below 90% or 80% you should take
@@ -229,7 +237,8 @@ If you find an interesting or important question missing, submit it via
If this is not a viable option, you can set `AFL_IGNORE_PROBLEMS=1` but then
the existing map will be used also for the newly loaded libraries, which
allows it to work, however, the efficiency of the fuzzing will be partially
- degraded.
+ degraded. Note that there is additionally `AFL_IGNORE_PROBLEMS_COVERAGE` to
+ additionally tell AFL++ to ignore any coverage from the late loaded libaries.
</p></details>
<details>
@@ -255,3 +264,18 @@ If you find an interesting or important question missing, submit it via
Solution: `git pull ; make clean install` of AFL++.
</p></details>
+
+<details>
+ <summary id="afl-map-size-warning">AFL++ map size warning.</summary><p>
+
+ When you run a large instrumented program stand-alone or via afl-showmap
+ you might see a warning like the following:
+
+ ```
+ Warning: AFL++ tools might need to set AFL_MAP_SIZE to 223723 to be able to run this instrumented program if this crashes!
+ ```
+
+ Depending how the target works it might also crash afterwards.
+
+ Solution: just do an `export AFL_MAP_SIZE=(the value in the warning)`.
+</p></details>
diff --git a/docs/INSTALL.md b/docs/INSTALL.md
index 01343b7f..9005a7eb 100644
--- a/docs/INSTALL.md
+++ b/docs/INSTALL.md
@@ -3,26 +3,31 @@
## Linux on x86
An easy way to install AFL++ with everything compiled is available via docker:
-You can use the [Dockerfile](../Dockerfile) (which has gcc-10 and clang-12 -
-hence afl-clang-lto is available) or just pull directly from the Docker Hub
-(for x86_64 and arm64):
+You can use the [Dockerfile](../Dockerfile) or just pull directly from the
+Docker Hub (for x86_64 and arm64):
```shell
-docker pull aflplusplus/aflplusplus
+docker pull aflplusplus/aflplusplus:
docker run -ti -v /location/of/your/target:/src aflplusplus/aflplusplus
```
-This image is automatically generated when a push to the stable repo happens.
+This image is automatically generated when a push to the stable branch happens.
You will find your target source code in `/src` in the container.
+Note: you can also pull `aflplusplus/aflplusplus:dev` which is the most current
+development state of AFL++.
+
If you want to build AFL++ yourself, you have many options. The easiest choice
is to build and install everything:
+NOTE: depending on your Debian/Ubuntu/Kali/... release, replace `-14` with
+whatever llvm version is available. We recommend llvm 13, 14, 15 or 16.
+
```shell
sudo apt-get update
-sudo apt-get install -y build-essential python3-dev automake cmake git flex bison libglib2.0-dev libpixman-1-dev python3-setuptools
-# try to install llvm 12 and install the distro default if that fails
-sudo apt-get install -y lld-12 llvm-12 llvm-12-dev clang-12 || sudo apt-get install -y lld llvm llvm-dev clang
+sudo apt-get install -y build-essential python3-dev automake cmake git flex bison libglib2.0-dev libpixman-1-dev python3-setuptools cargo libgtk-3-dev
+# try to install llvm 14 and install the distro default if that fails
+sudo apt-get install -y lld-14 llvm-14 llvm-14-dev clang-14 || sudo apt-get install -y lld llvm llvm-dev clang
sudo apt-get install -y gcc-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-plugin-dev libstdc++-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-dev
sudo apt-get install -y ninja-build # for QEMU mode
git clone https://github.com/AFLplusplus/AFLplusplus
@@ -45,7 +50,7 @@ make source-only
These build targets exist:
-* all: the main afl++ binaries and llvm/gcc instrumentation
+* all: the main AFL++ binaries and llvm/gcc instrumentation
* binary-only: everything for binary-only fuzzing: frida_mode, nyx_mode,
qemu_mode, frida_mode, unicorn_mode, coresight_mode, libdislocator,
libtokencap
@@ -73,19 +78,22 @@ make STATIC=1
These build options exist:
* STATIC - compile AFL++ static
-* ASAN_BUILD - compiles with memory sanitizer for debug purposes
+* CODE_COVERAGE - compile the target for code coverage (see docs/instrumentation/README.llvm.md)
+* ASAN_BUILD - compiles AFL++ with memory sanitizer for debug purposes
+* UBSAN_BUILD - compiles AFL++ tools with undefined behaviour sanitizer for debug purposes
* DEBUG - no optimization, -ggdb3, all warnings and -Werror
-* PROFILING - compile with profiling information (gprof)
+* LLVM_DEBUG - shows llvm deprecation warnings
+* PROFILING - compile afl-fuzz with profiling information
* INTROSPECTION - compile afl-fuzz with mutation introspection
* NO_PYTHON - disable python support
-* NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for
- normal fuzzing
+* NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
* NO_NYX - disable building nyx mode dependencies
+* NO_CORESIGHT - disable building coresight (arm64 only)
+* NO_UNICORN_ARM64 - disable building unicorn on arm64
* AFL_NO_X86 - if compiling on non-intel/amd platforms
-* LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config
- (e.g., Debian)
+* LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g., Debian)
-e.g.: `make ASAN_BUILD=1`
+e.g.: `make LLVM_CONFIG=llvm-config-14`
## MacOS X on x86 and arm64 (M1)
@@ -142,7 +150,7 @@ and definitely don't look POSIX-compliant. This means two things:
environment before starting afl-fuzz.
User emulation mode of QEMU does not appear to be supported on MacOS X, so
-black-box instrumentation mode (`-Q`) will not work. However, Frida mode (`-O`)
+black-box instrumentation mode (`-Q`) will not work. However, FRIDA mode (`-O`)
works on both x86 and arm64 MacOS boxes.
MacOS X supports SYSV shared memory used by AFL's instrumentation, but the
diff --git a/docs/afl-fuzz_approach.md b/docs/afl-fuzz_approach.md
index 6af39769..cb173f10 100644
--- a/docs/afl-fuzz_approach.md
+++ b/docs/afl-fuzz_approach.md
@@ -483,6 +483,7 @@ directory. This includes:
- `fuzzer_pid` - PID of the fuzzer process
- `cycles_done` - queue cycles completed so far
- `cycles_wo_finds` - number of cycles without any new paths found
+- `time_wo_finds` - longest time in seconds no new path was found
- `execs_done` - number of execve() calls attempted
- `execs_per_sec` - overall number of execs per second
- `corpus_count` - total number of entries in the queue
diff --git a/docs/best_practices.md b/docs/best_practices.md
index 133c645e..459fcaf7 100644
--- a/docs/best_practices.md
+++ b/docs/best_practices.md
@@ -131,6 +131,11 @@ jitter, or is a hash map function etc., then it should not be instrumented.
To be able to exclude these functions (based on AFL++'s measured stability), the
following process will allow to identify functions with variable edges.
+Note that this is only useful for non-persistent targets!
+If a persistent target is unstable whereas when run non-persistent is fine,
+then this means that the target is keeping internal state, which is bad for
+fuzzing. Fuzz such targets **without** persistent mode.
+
Four steps are required to do this and it also requires quite some knowledge of
coding and/or disassembly and is effectively possible only with `afl-clang-fast`
`PCGUARD` and `afl-clang-lto` `LTO` instrumentation.
diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md
index 7b4e0516..3f7e9e6e 100644
--- a/docs/custom_mutators.md
+++ b/docs/custom_mutators.md
@@ -38,11 +38,17 @@ performed with the custom mutator.
## 2) APIs
+**IMPORTANT NOTE**: If you use our C/C++ API and you want to increase the size
+of an **out_buf buffer, you have to use `afl_realloc()` for this, so include
+`include/alloc-inl.h` - otherwise afl-fuzz will crash when trying to free
+your buffers.
+
C/C++:
```c
void *afl_custom_init(afl_state_t *afl, unsigned int seed);
unsigned int afl_custom_fuzz_count(void *data, const unsigned char *buf, size_t buf_size);
+void afl_custom_splice_optout(void *data);
size_t afl_custom_fuzz(void *data, unsigned char *buf, size_t buf_size, unsigned char **out_buf, unsigned char *add_buf, size_t add_buf_size, size_t max_size);
const char *afl_custom_describe(void *data, size_t max_description_len);
size_t afl_custom_post_process(void *data, unsigned char *buf, size_t buf_size, unsigned char **out_buf);
@@ -52,6 +58,7 @@ int afl_custom_post_trim(void *data, unsigned char success);
size_t afl_custom_havoc_mutation(void *data, unsigned char *buf, size_t buf_size, unsigned char **out_buf, size_t max_size);
unsigned char afl_custom_havoc_mutation_probability(void *data);
unsigned char afl_custom_queue_get(void *data, const unsigned char *filename);
+void (*afl_custom_fuzz_send)(void *data, const u8 *buf, size_t buf_size);
u8 afl_custom_queue_new_entry(void *data, const unsigned char *filename_new_queue, const unsigned int *filename_orig_queue);
const char* afl_custom_introspection(my_mutator_t *data);
void afl_custom_deinit(void *data);
@@ -63,9 +70,12 @@ Python:
def init(seed):
pass
-def fuzz_count(buf, add_buf, max_size):
+def fuzz_count(buf):
return cnt
+def splice_optout()
+ pass
+
def fuzz(buf, add_buf, max_size):
return mutated_out
@@ -93,6 +103,9 @@ def havoc_mutation_probability():
def queue_get(filename):
return True
+def fuzz_send(buf):
+ pass
+
def queue_new_entry(filename_new_queue, filename_orig_queue):
return False
@@ -105,7 +118,7 @@ def deinit(): # optional for Python
### Custom Mutation
-- `init`:
+- `init` (optional in Python):
This method is called when AFL++ starts up and is used to seed RNG and set
up buffers and state.
@@ -123,6 +136,13 @@ def deinit(): # optional for Python
for a specific queue entry, use this function. This function is most useful
if `AFL_CUSTOM_MUTATOR_ONLY` is **not** used.
+- `splice_optout` (optional):
+
+ If this function is present, no splicing target is passed to the `fuzz`
+ function. This saves time if splicing data is not needed by the custom
+ fuzzing function.
+ This function is never called, just needs to be present to activate.
+
- `fuzz` (optional):
This method performs custom mutations on a given input. It also accepts an
@@ -130,6 +150,7 @@ def deinit(): # optional for Python
sense to use it. You would only skip this if `post_process` is used to fix
checksums etc. so if you are using it, e.g., as a post processing library.
Note that a length > 0 *must* be returned!
+ The returned output buffer is under **your** memory management!
- `describe` (optional):
@@ -159,6 +180,22 @@ def deinit(): # optional for Python
This can return any python object that implements the buffer protocol and
supports PyBUF_SIMPLE. These include bytes, bytearray, etc.
+ You can decide in the post_process mutator to not send the mutated data
+ to the target, e.g. if it is too short, too corrupted, etc. If so,
+ return a NULL buffer and zero length (or a 0 length string in Python).
+
+ NOTE: Do not make any random changes to the data in this function!
+
+ PERFORMANCE for C/C++: If possible make the changes in-place (so modify
+ the `*data` directly, and return it as `*outbuf = data`.
+
+- `fuzz_send` (optional):
+
+ This method can be used if you want to send data to the target yourself,
+ e.g. via IPC. This replaces some usage of utils/afl_proxy but requires
+ that you start the target with afl-fuzz.
+ Example: [custom_mutators/examples/custom_send.c](custom_mutators/examples/custom_send.c)
+
- `queue_new_entry` (optional):
This methods is called after adding a new test case to the queue. If the
@@ -170,7 +207,7 @@ def deinit(): # optional for Python
discovered if compiled with INTROSPECTION. The custom mutator can then
return a string (const char *) that reports the exact mutations used.
-- `deinit`:
+- `deinit` (optional in Python):
The last method to be called, deinitializing the state.
@@ -260,13 +297,41 @@ sudo apt install python-dev
```
Then, AFL++ can be compiled with Python support. The AFL++ Makefile detects
-Python 2 and 3 through `python-config` if it is in the PATH and compiles
-`afl-fuzz` with the feature if available.
+Python3 through `python-config`/`python3-config` if it is in the PATH and
+compiles `afl-fuzz` with the feature if available.
-Note: for some distributions, you might also need the package `python[23]-apt`.
+Note: for some distributions, you might also need the package `python[3]-apt`.
In case your setup is different, set the necessary variables like this:
`PYTHON_INCLUDE=/path/to/python/include LDFLAGS=-L/path/to/python/lib make`.
+### Helpers
+
+For C/C++ custom mutators you get a pointer to `afl_state_t *afl` in the
+`afl_custom_init()` which contains all information that you need.
+Note that if you access it, you need to recompile your custom mutator if
+you update AFL++ because the structure might have changed!
+
+For mutators written in Python, Rust, GO, etc. there are a few environment
+variables set to help you to get started:
+
+`AFL_CUSTOM_INFO_PROGRAM` - the program name of the target that is executed.
+If your custom mutator is used with modes like Qemu (`-Q`), this will still
+contain the target program, not afl-qemu-trace.
+
+`AFL_CUSTOM_INFO_PROGRAM_INPUT` - if the `-f` parameter is used with afl-fuzz
+then this value is found in this environment variable.
+
+`AFL_CUSTOM_INFO_PROGRAM_ARGV` - this contains the parameters given to the
+target program and still has the `@@` identifier in there.
+
+Note: If `AFL_CUSTOM_INFO_PROGRAM_INPUT` is empty and `AFL_CUSTOM_INFO_PROGRAM_ARGV`
+is either empty or does not contain `@@` then the target gets the input via
+`stdin`.
+
+`AFL_CUSTOM_INFO_OUT` - This is the output directory for this fuzzer instance,
+so if `afl-fuzz` was called with `-o out -S foobar`, then this will be set to
+`out/foobar`.
+
### Custom Mutator Preparation
For C/C++ mutators, the source code must be compiled as a shared object:
diff --git a/docs/env_variables.md b/docs/env_variables.md
index fe9c6e07..0f0869d2 100644
--- a/docs/env_variables.md
+++ b/docs/env_variables.md
@@ -129,6 +129,9 @@ subset of the settings discussed in section 1, with the exception of:
write all constant string comparisons to this file to be used later with
afl-fuzz' `-x` option.
+ - An option to `AFL_LLVM_DICT2FILE` is `AFL_LLVM_DICT2FILE_NO_MAIN=1` which
+ skill not parse `main()`.
+
- `TMPDIR` and `AFL_KEEP_ASSEMBLY`, since no temporary assembly files are
created.
@@ -153,13 +156,15 @@ Available options:
- LTO - LTO instrumentation
- NATIVE - clang's original pcguard based instrumentation
- NGRAM-x - deeper previous location coverage (from NGRAM-2 up to NGRAM-16)
- - PCGUARD - our own pcgard based instrumentation (default)
+ - PCGUARD - our own pcguard based instrumentation (default)
#### CMPLOG
Setting `AFL_LLVM_CMPLOG=1` during compilation will tell afl-clang-fast to
produce a CmpLog binary.
+For afl-gcc-fast, set `AFL_GCC_CMPLOG=1` instead.
+
For more information, see
[instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md).
@@ -235,7 +240,9 @@ combined.
the default `0x10000`. A value of 0 or empty sets the map address to be
dynamic (the original AFL way, which is slower).
- `AFL_LLVM_MAP_DYNAMIC` sets the shared memory address to be dynamic.
-
+ - `AFL_LLVM_LTO_SKIPINIT` skips adding initialization code. Some global vars
+ (e.g. the highest location ID) are not injected. Needed to instrument with
+ [WAFL](https://github.com/fgsect/WAFL.git).
For more information, see
[instrumentation/README.lto.md](../instrumentation/README.lto.md).
@@ -352,6 +359,9 @@ checks or alter some of the more exotic semantics of the tool:
- Setting `AFL_KEEP_TIMEOUTS` will keep longer running inputs if they reach
new coverage
+ - On the contrary, if you are not interested in any timeouts, you can set
+ `AFL_IGNORE_TIMEOUTS` to get a bit of speed instead.
+
- `AFL_EXIT_ON_SEED_ISSUES` will restore the vanilla afl-fuzz behavior which
does not allow crashes or timeout seeds in the initial -i corpus.
@@ -376,10 +386,10 @@ checks or alter some of the more exotic semantics of the tool:
valid terminal was detected (for virtual consoles).
- Setting `AFL_FORKSRV_INIT_TMOUT` allows you to specify a different timeout
- to wait for the forkserver to spin up. The default is the `-t` value times
- `FORK_WAIT_MULT` from `config.h` (usually 10), so for a `-t 100`, the
- default would wait for `1000` milliseconds. Setting a different time here is
- useful if the target has a very slow startup time, for example, when doing
+ to wait for the forkserver to spin up. The specified value is the new timeout, in milliseconds.
+ The default is the `-t` value times `FORK_WAIT_MULT` from `config.h` (usually 10), so for a `-t 100`, the default would wait for `1000` milliseconds.
+ The `AFL_FORKSRV_INIT_TMOUT` value does not get multiplied. It overwrites the initial timeout afl-fuzz waits for the target to come up with a constant time.
+ Setting a different time here is useful if the target has a very slow startup time, for example, when doing
full-system fuzzing or emulation, but you don't want the actual runs to wait
too long for timeouts.
@@ -396,7 +406,8 @@ checks or alter some of the more exotic semantics of the tool:
- If afl-fuzz encounters an incorrect fuzzing setup during a fuzzing session
(not at startup), it will terminate. If you do not want this, then you can
- set `AFL_IGNORE_PROBLEMS`.
+ set `AFL_IGNORE_PROBLEMS`. If you additionally want to also ignore coverage
+ from late loaded libraries, you can set `AFL_IGNORE_PROBLEMS_COVERAGE`.
- When running in the `-M` or `-S` mode, setting `AFL_IMPORT_FIRST` causes the
fuzzer to import test cases from other instances before doing anything else.
@@ -407,11 +418,22 @@ checks or alter some of the more exotic semantics of the tool:
the afl-fuzz -g/-G command line option to control the minimum/maximum
of fuzzing input generated.
- - `AFL_KILL_SIGNAL`: Set the signal ID to be delivered to child processes on
- timeout. Unless you implement your own targets or instrumentation, you
+ - `AFL_KILL_SIGNAL`: Set the signal ID to be delivered to child processes
+ on timeout. Unless you implement your own targets or instrumentation, you
likely don't have to set it. By default, on timeout and on exit, `SIGKILL`
(`AFL_KILL_SIGNAL=9`) will be delivered to the child.
+ - `AFL_FORK_SERVER_KILL_SIGNAL`: Set the signal ID to be delivered to the
+ fork server when AFL++ is terminated. Unless you implement your
+ fork server, you likely do not have to set it. By default, `SIGTERM`
+ (`AFL_FORK_SERVER_KILL_SIGNAL=15`) will be delivered to the fork server.
+ If only `AFL_KILL_SIGNAL` is provided, `AFL_FORK_SERVER_KILL_SIGNAL` will
+ be set to same value as `AFL_KILL_SIGNAL` to provide backward compatibility.
+ If `AFL_FORK_SERVER_KILL_SIGNAL` is also set, it takes precedence.
+
+ NOTE: Uncatchable signals, such as `SIGKILL`, cause child processes of
+ the fork server to be orphaned and leaves them in a zombie state.
+
- `AFL_MAP_SIZE` sets the size of the shared map that afl-analyze, afl-fuzz,
afl-showmap, and afl-tmin create to gather instrumentation data from the
target. This must be equal or larger than the size the target was compiled
@@ -453,14 +475,20 @@ checks or alter some of the more exotic semantics of the tool:
normally done when starting up the forkserver and causes a pretty
significant performance drop.
- - `AFL_NO_SNAPSHOT` will advice afl-fuzz not to use the snapshot feature if
+ - `AFL_NO_SNAPSHOT` will advise afl-fuzz not to use the snapshot feature if
the snapshot lkm is loaded.
- Setting `AFL_NO_UI` inhibits the UI altogether and just periodically prints
some basic stats. This behavior is also automatically triggered when the
output from afl-fuzz is redirected to a file or to a pipe.
- - In QEMU mode (-Q) and Frida mode (-O), `AFL_PATH` will be searched for
+ - Setting `AFL_NO_STARTUP_CALIBRATION` will skip the initial calibration
+ of all starting seeds, and start fuzzing at once. Use with care, this
+ degrades the fuzzing performance!
+
+ - Setting `AFL_NO_WARN_INSTABILITY` will suppress instability warnings.
+
+ - In QEMU mode (-Q) and FRIDA mode (-O), `AFL_PATH` will be searched for
afl-qemu-trace and afl-frida-trace.so.
- If you are using persistent mode (you should, see
@@ -468,7 +496,7 @@ checks or alter some of the more exotic semantics of the tool:
some targets keep inherent state due which a detected crash test case does
not crash the target again when the test case is given. To be able to still
re-trigger these crashes, you can use the `AFL_PERSISTENT_RECORD` variable
- with a value of how many previous fuzz cases to keep prio a crash. If set to
+ with a value of how many previous fuzz cases to keep prior a crash. If set to
e.g., 10, then the 9 previous inputs are written to out/default/crashes as
RECORD:000000,cnt:000000 to RECORD:000000,cnt:000008 and
RECORD:000000,cnt:000009 being the crash case. NOTE: This option needs to be
@@ -517,6 +545,10 @@ checks or alter some of the more exotic semantics of the tool:
(empty/non present) will add no tags to the metrics. For more information,
see [rpc_statsd.md](rpc_statsd.md).
+ - `AFL_SYNC_TIME` allows you to specify a different minimal time (in minutes)
+ between fuzzing instances synchronization. Default sync time is 30 minutes,
+ note that time is halved for -M main nodes.
+
- Setting `AFL_TARGET_ENV` causes AFL++ to set extra environment variables for
the target binary. Example: `AFL_TARGET_ENV="VAR1=1 VAR2='a b c'" afl-fuzz
... `. This exists mostly for things like `LD_LIBRARY_PATH` but it would
@@ -549,12 +581,18 @@ checks or alter some of the more exotic semantics of the tool:
in the target binary
- If you need an early forkserver in your target because of early
- constructors in your target you can set `AFL_EARLY_FORKSERVER`.
+ constructors in your target, you can set `AFL_EARLY_FORKSERVER`.
Note that this is not a compile time option but a runtime option :-)
- - set `AFL_PIZZA_MODE` to 1 to enable the April 1st stats menu, set to 0
+ - Set `AFL_PIZZA_MODE` to 1 to enable the April 1st stats menu, set to -1
to disable although it is 1st of April.
+ - If you need a specific interval to update fuzzer_stats file, you can
+ set `AFL_FUZZER_STATS_UPDATE_INTERVAL` to the interval in seconds you'd
+ the file to be updated.
+ Note that will not be exact and with slow targets it can take seconds
+ until there is a slice for the time test.
+
## 5) Settings for afl-qemu-trace
The QEMU wrapper used to instrument binary-only code supports several settings:
@@ -581,6 +619,14 @@ The QEMU wrapper used to instrument binary-only code supports several settings:
- Setting `AFL_INST_LIBS` causes the translator to also instrument the code
inside any dynamically linked libraries (notably including glibc).
+ - You can use `AFL_QEMU_INST_RANGES=0xaaaa-0xbbbb,0xcccc-0xdddd` to just
+ instrument specific memory locations, e.g. a specific library.
+ Excluding ranges takes priority over any included ranges or `AFL_INST_LIBS`.
+
+ - You can use `AFL_QEMU_EXCLUDE_RANGES=0xaaaa-0xbbbb,0xcccc-0xdddd` to **NOT**
+ instrument specific memory locations, e.g. a specific library.
+ Excluding ranges takes priority over any included ranges or `AFL_INST_LIBS`.
+
- It is possible to set `AFL_INST_RATIO` to skip the instrumentation on some
of the basic blocks, which can be useful when dealing with very complex
binaries.
@@ -615,6 +661,10 @@ The QEMU wrapper used to instrument binary-only code supports several settings:
emulation" variables (e.g., `QEMU_STACK_SIZE`), but there should be no
reason to touch them.
+ - Normally a `README.txt` is written to the `crashes/` directory when a first
+ crash is found. Setting `AFL_NO_CRASH_README` will prevent this. Useful when
+ counting crashes based on a file count in that directory.
+
## 7) Settings for afl-frida-trace
The FRIDA wrapper used to instrument binary-only code supports many of the same
@@ -638,6 +688,8 @@ support.
* `AFL_FRIDA_INST_JIT` - Enable the instrumentation of Just-In-Time compiled
code. Code is considered to be JIT if the executable segment is not backed by
a file.
+* `AFL_FRIDA_INST_NO_DYNAMIC_LOAD` - Don't instrument the code loaded late at
+ runtime. Strictly limits instrumentation to what has been included.
* `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage
instrumentation (the default where available). Required to use
`AFL_FRIDA_INST_TRACE`.
@@ -681,8 +733,8 @@ support.
* `AFL_FRIDA_STALKER_ADJACENT_BLOCKS` - Configure the number of adjacent blocks
to fetch when generating instrumented code. By fetching blocks in the same
order they appear in the original program, rather than the order of execution
- should help reduce locallity and adjacency. This includes allowing us to
- vector between adjancent blocks using a NOP slide rather than an immediate
+ should help reduce locality and adjacency. This includes allowing us to
+ vector between adjacent blocks using a NOP slide rather than an immediate
branch.
* `AFL_FRIDA_STALKER_IC_ENTRIES` - Configure the number of inline cache entries
stored along-side branch instructions which provide a cache to avoid having to
diff --git a/docs/features.md b/docs/features.md
index dd3d2bcb..212302f8 100644
--- a/docs/features.md
+++ b/docs/features.md
@@ -12,7 +12,7 @@ QEMU 5.1 with laf-intel and Redqueen, FRIDA mode, unicorn mode, gcc plugin, full
| NeverZero [B] | x86[_64] | x(1) | x | x | x | x | | |
| Persistent Mode [C] | | x | x | x86[_64]/arm64 | x86[_64]/arm[64] | x | | |
| LAF-Intel / CompCov [D] | | x | | | x86[_64]/arm[64] | x86[_64]/arm[64] | x86[_64] | |
-| CmpLog [E] | | x | | x86[_64]/arm64 | x86[_64]/arm[64] | | | |
+| CmpLog [E] | | x | x | x86[_64]/arm64 | x86[_64]/arm[64] | | | |
| Selective Instrumentation [F] | | x | x | x | x | | | |
| Non-Colliding Coverage [G] | | x(4) | | | (x)(5) | | | |
| Ngram prev_loc Coverage [H] | | x(6) | | | | | | |
diff --git a/docs/fuzzing_binary-only_targets.md b/docs/fuzzing_binary-only_targets.md
index c97af1b9..9d9d6bb6 100644
--- a/docs/fuzzing_binary-only_targets.md
+++ b/docs/fuzzing_binary-only_targets.md
@@ -201,10 +201,10 @@ afl-clang-fast's.
### RetroWrite
RetroWrite is a static binary rewriter that can be combined with AFL++. If you
-have an x86_64 binary that still has its symbols (i.e., not stripped binary), is
-compiled with position independent code (PIC/PIE), and does not contain C++
-exceptions, then the RetroWrite solution might be for you. It decompiles to ASM
-files which can then be instrumented with afl-gcc.
+have an x86_64 or arm64 binary that does not contain C++ exceptions and - if
+x86_64 - still has it's symbols and compiled with position independent code
+(PIC/PIE), then the RetroWrite solution might be for you.
+It decompiles to ASM files which can then be instrumented with afl-gcc.
Binaries that are statically instrumented for fuzzing using RetroWrite are close
in performance to compiler-instrumented binaries and outperform the QEMU-based
@@ -291,7 +291,7 @@ its IPT performance is just 6%!
There are many binary-only fuzzing frameworks. Some are great for CTFs but don't
work with large binaries, others are very slow but have good path discovery,
-some are very hard to set-up...
+some are very hard to set up...
* Jackalope:
[https://github.com/googleprojectzero/Jackalope](https://github.com/googleprojectzero/Jackalope)
diff --git a/docs/fuzzing_in_depth.md b/docs/fuzzing_in_depth.md
index 2c27dfe1..f75ca5dc 100644
--- a/docs/fuzzing_in_depth.md
+++ b/docs/fuzzing_in_depth.md
@@ -523,7 +523,7 @@ mode!) and switch the input directory with a dash (`-`):
afl-fuzz -i - -o output -- bin/target -someopt @@
```
-Adding a dictionary is helpful. You have to following options:
+Adding a dictionary is helpful. You have the following options:
* See the directory
[dictionaries/](../dictionaries/), if something is already included for your
@@ -534,6 +534,8 @@ dictionaries/FORMAT.dict`.
* With `afl-clang-fast`, you can set
`AFL_LLVM_DICT2FILE=/full/path/to/new/file.dic` to automatically generate a
dictionary during target compilation.
+ Adding `AFL_LLVM_DICT2FILE_NO_MAIN=1` to not parse main (usually command line
+ parameter parsing) is often a good idea too.
* You also have the option to generate a dictionary yourself during an
independent run of the target, see
[utils/libtokencap/README.md](../utils/libtokencap/README.md).
@@ -626,6 +628,10 @@ from other fuzzers in the campaign first.
If you have a large corpus, a corpus from a previous run or are fuzzing in a CI,
then also set `export AFL_CMPLOG_ONLY_NEW=1` and `export AFL_FAST_CAL=1`.
+If the queue in the CI is huge and/or the execution time is slow then you can
+also add `AFL_NO_STARTUP_CALIBRATION=1` to skip the initial queue calibration
+phase and start fuzzing at once - but only do this if the calibration phase
+would be too long for your fuzz run time.
You can also use different fuzzers. If you are using AFL spinoffs or AFL
conforming fuzzers, then just use the same -o directory and give it a unique
@@ -669,7 +675,7 @@ The syncing process itself is very simple. As the `-M main-$HOSTNAME` instance
syncs to all `-S` secondaries as well as to other fuzzers, you have to copy only
this directory to the other machines.
-Lets say all servers have the `-o out` directory in /target/foo/out, and you
+Let's say all servers have the `-o out` directory in /target/foo/out, and you
created a file `servers.txt` which contains the hostnames of all participating
servers, plus you have an ssh key deployed to all of them, then run:
@@ -838,9 +844,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 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)
+ 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)
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)
@@ -896,11 +903,23 @@ then color-codes the input based on which sections appear to be critical and
which are not; while not bulletproof, it can often offer quick insights into
complex file formats.
+`casr-afl` from [CASR](https://github.com/ispras/casr) tools provides
+comfortable triaging for crashes found by AFL++. Reports are clustered and
+contain severity and other information.
+```shell
+casr-afl -i /path/to/afl/out/dir -o /path/to/casr/out/dir
+```
+
## 5. CI fuzzing
Some notes on continuous integration (CI) fuzzing - this fuzzing is different to
normal fuzzing campaigns as these are much shorter runnings.
+If the queue in the CI is huge and/or the execution time is slow then you can
+also add `AFL_NO_STARTUP_CALIBRATION=1` to skip the initial queue calibration
+phase and start fuzzing at once. But only do that if the calibration time is
+too long for your overall available fuzz run time.
+
1. Always:
* LTO has a much longer compile time which is diametrical to short fuzzing -
hence use afl-clang-fast instead.
@@ -920,7 +939,7 @@ normal fuzzing campaigns as these are much shorter runnings.
3. Also randomize the afl-fuzz runtime options, e.g.:
* 65% for `AFL_DISABLE_TRIM`
* 50% for `AFL_KEEP_TIMEOUTS`
- * 50% use a dictionary generated by `AFL_LLVM_DICT2FILE`
+ * 50% use a dictionary generated by `AFL_LLVM_DICT2FILE` + `AFL_LLVM_DICT2FILE_NO_MAIN=1`
* 40% use MOpt (`-L 0`)
* 40% for `AFL_EXPAND_HAVOC_NOW`
* 20% for old queue processing (`-Z`)
diff --git a/docs/ideas.md b/docs/ideas.md
index e2360ab2..4e419b80 100644
--- a/docs/ideas.md
+++ b/docs/ideas.md
@@ -3,6 +3,8 @@
In the following, we describe a variety of ideas that could be implemented for
future AFL++ versions.
+**NOTE:** Our GSoC participation is concerning [libafl](https://github.com/AFLplusplus/libafl), not AFL++.
+
## Analysis software
Currently analysis is done by using afl-plot, which is rather outdated. A GTK or
@@ -16,21 +18,10 @@ and Y axis, zoom factor, log scaling on-off, etc.
Mentor: vanhauser-thc
-## WASM Instrumentation
-
-Currently, AFL++ can be used for source code fuzzing and traditional binaries.
-With the rise of WASM as a compile target, however, a novel way of instrumentation
-needs to be implemented for binaries compiled to Webassembly. This can either be
-done by inserting instrumentation directly into the WASM AST, or by patching
-feedback into a WASM VM of choice, similar to the current Unicorn
-instrumentation.
-
-Mentor: any
-
## Support other programming languages
-Other programming languages also use llvm hence they could be (easily?) supported
-for fuzzing, e.g., mono, swift, go, kotlin native, fortran, ...
+Other programming languages also use llvm hence they could be (easily?)
+supported for fuzzing, e.g., mono, swift, go, kotlin native, fortran, ...
GCC also supports: Objective-C, Fortran, Ada, Go, and D (according to
[Gcc homepage](https://gcc.gnu.org/))
diff --git a/docs/third_party_tools.md b/docs/third_party_tools.md
index 8d40c429..02a40ce5 100644
--- a/docs/third_party_tools.md
+++ b/docs/third_party_tools.md
@@ -1,11 +1,18 @@
# Tools that help fuzzing with AFL++
-Speeding up fuzzing:
+## AFL++ and other development languages
+
+* [afl-rs](https://github.com/rust-fuzz/afl.rs) - AFL++ for RUST
+* [WASM](https://github.com/fgsect/WAFL) - AFL++ for WASM
+
+## Speeding up fuzzing
+
* [libfiowrapper](https://github.com/marekzmyslowski/libfiowrapper) - if the
function you want to fuzz requires loading a file, this allows using the
shared memory test case feature :-) - recommended.
-Minimization of test cases:
+## Minimization of test cases
+
* [afl-pytmin](https://github.com/ilsani/afl-pytmin) - a wrapper for afl-tmin
that tries to speed up the process of minimization of a single test case by
using many CPU cores.
@@ -14,7 +21,8 @@ Minimization of test cases:
* [halfempty](https://github.com/googleprojectzero/halfempty) - is a fast
utility for minimizing test cases by Tavis Ormandy based on parallelization.
-Distributed execution:
+## Distributed execution
+
* [disfuzz-afl](https://github.com/MartijnB/disfuzz-afl) - distributed fuzzing
for AFL.
* [AFLDFF](https://github.com/quantumvm/AFLDFF) - AFL distributed fuzzing
@@ -26,7 +34,8 @@ Distributed execution:
* [afl-in-the-cloud](https://github.com/abhisek/afl-in-the-cloud) - another
script for running AFL in AWS.
-Deployment, management, monitoring, reporting
+## Deployment, management, monitoring, reporting
+
* [afl-utils](https://gitlab.com/rc0r/afl-utils) - a set of utilities for
automatic processing/analysis of crashes and reducing the number of test
cases.
@@ -44,7 +53,8 @@ Deployment, management, monitoring, reporting
* [afl-extras](https://github.com/fekir/afl-extras) - shell scripts to
parallelize afl-tmin, startup, and data collection.
-Crash processing
+## Crash processing
+
* [AFLTriage](https://github.com/quic/AFLTriage) -
triage crashing input files using gdb.
* [afl-crash-analyzer](https://github.com/floyd-fuh/afl-crash-analyzer) -
@@ -57,3 +67,5 @@ Crash processing
generates builds of debian packages suitable for AFL.
* [afl-fid](https://github.com/FoRTE-Research/afl-fid) - a set of tools for
working with input data.
+* [CASR](https://github.com/ispras/casr) - a set of tools for crash triage and
+ analysis.
diff --git a/docs/tutorials.md b/docs/tutorials.md
index 64d2b376..342080fd 100644
--- a/docs/tutorials.md
+++ b/docs/tutorials.md
@@ -1,5 +1,9 @@
# Tutorials
+If you are a total newbie, try this guide:
+
+* [https://github.com/alex-maleno/Fuzzing-Module](https://github.com/alex-maleno/Fuzzing-Module)
+
Here are some good write-ups to show how to effectively use AFL++:
* [https://aflplus.plus/docs/tutorials/libxml2_tutorial/](https://aflplus.plus/docs/tutorials/libxml2_tutorial/)
@@ -16,8 +20,12 @@ training, then we can highly recommend the following:
* [https://github.com/antonio-morales/Fuzzing101](https://github.com/antonio-morales/Fuzzing101)
+Here is good workflow description for frida_mode:
+
+* [https://blog.quarkslab.com/android-greybox-fuzzing-with-afl-frida-mode.html](https://blog.quarkslab.com/android-greybox-fuzzing-with-afl-frida-mode.html)
+
If you are interested in fuzzing structured data (where you define what the
-structure is), these links have you covered:
+structure is), these links have you covered (some are outdated though):
* libprotobuf for AFL++:
[https://github.com/P1umer/AFLplusplus-protobuf-mutator](https://github.com/P1umer/AFLplusplus-protobuf-mutator)
@@ -29,6 +37,7 @@ structure is), these links have you covered:
[https://github.com/adrian-rt/superion-mutator](https://github.com/adrian-rt/superion-mutator)
## Video Tutorials
+
* [Install AFL++ Ubuntu](https://www.youtube.com/watch?v=5dCvhkbi3RA)
* [[Fuzzing with AFLplusplus] Installing AFLPlusplus and fuzzing a simple C program](https://www.youtube.com/watch?v=9wRVo0kYSlc)
* [[Fuzzing with AFLplusplus] How to fuzz a binary with no source code on Linux in persistent mode](https://www.youtube.com/watch?v=LGPJdEO02p4)
diff --git a/dynamic_list.txt b/dynamic_list.txt
index 7293ae77..50c0c6b8 100644
--- a/dynamic_list.txt
+++ b/dynamic_list.txt
@@ -8,6 +8,7 @@
"__afl_auto_first";
"__afl_auto_init";
"__afl_auto_second";
+ "__afl_connected";
"__afl_coverage_discard";
"__afl_coverage_interesting";
"__afl_coverage_off";
@@ -53,4 +54,5 @@
"__sanitizer_cov_trace_pc_guard";
"__sanitizer_cov_trace_pc_guard_init";
"__sanitizer_cov_trace_switch";
+ "LLVMFuzzerTestOneInput";
};
diff --git a/include/afl-as.h b/include/afl-as.h
index bbbd5582..486314e2 100644
--- a/include/afl-as.h
+++ b/include/afl-as.h
@@ -10,7 +10,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h
index 9992e841..beb2de2a 100644
--- a/include/afl-fuzz.h
+++ b/include/afl-fuzz.h
@@ -10,7 +10,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -169,12 +169,23 @@ struct queue_entry {
u32 bitmap_size, /* Number of bits set in bitmap */
fuzz_level, /* Number of fuzzing iterations */
- n_fuzz_entry; /* offset in n_fuzz */
+ n_fuzz_entry /* offset in n_fuzz */
+#ifdef INTROSPECTION
+ ,
+ stats_selected, /* stats: how often selected */
+ stats_skipped, /* stats: how often skipped */
+ stats_finds, /* stats: # of saved finds */
+ stats_crashes, /* stats: # of saved crashes */
+ stats_tmouts /* stats: # of saved timeouts */
+#endif
+ ;
u64 exec_us, /* Execution time (us) */
handicap, /* Number of queue cycles behind */
depth, /* Path depth */
- exec_cksum; /* Checksum of the execution trace */
+ exec_cksum, /* Checksum of the execution trace */
+ custom, /* Marker for custom mutators */
+ stats_mutated; /* stats: # of mutations performed */
u8 *trace_mini; /* Trace bytes, if kept */
u32 tc_ref; /* Trace bytes ref count */
@@ -188,7 +199,7 @@ struct queue_entry {
u8 *testcase_buf; /* The testcase buffer, if loaded. */
- u8 * cmplog_colorinput; /* the result buf of colorization */
+ u8 *cmplog_colorinput; /* the result buf of colorization */
struct tainted *taint; /* Taint information from CmpLog */
struct queue_entry *mother; /* queue entry this based on */
@@ -333,6 +344,8 @@ enum {
/* 11 */ PY_FUNC_QUEUE_NEW_ENTRY,
/* 12 */ PY_FUNC_INTROSPECTION,
/* 13 */ PY_FUNC_DESCRIBE,
+ /* 14 */ PY_FUNC_FUZZ_SEND,
+ /* 15 */ PY_FUNC_SPLICE_OPTOUT,
PY_FUNC_COUNT
};
@@ -341,18 +354,18 @@ typedef struct py_mutator {
PyObject *py_module;
PyObject *py_functions[PY_FUNC_COUNT];
- void * afl_state;
- void * py_data;
+ void *afl_state;
+ void *py_data;
- u8 * fuzz_buf;
+ u8 *fuzz_buf;
size_t fuzz_size;
Py_buffer post_process_buf;
- u8 * trim_buf;
+ u8 *trim_buf;
size_t trim_size;
- u8 * havoc_buf;
+ u8 *havoc_buf;
size_t havoc_size;
} py_mutator_t;
@@ -361,13 +374,13 @@ typedef struct py_mutator {
typedef struct MOpt_globals {
- u64 * finds;
- u64 * finds_v2;
- u64 * cycles;
- u64 * cycles_v2;
- u64 * cycles_v3;
+ u64 *finds;
+ u64 *finds_v2;
+ u64 *cycles;
+ u64 *cycles_v2;
+ u64 *cycles_v3;
u32 is_pilot_mode;
- u64 * pTime;
+ u64 *pTime;
u64 period;
char *havoc_stagename;
char *splice_stageformat;
@@ -386,14 +399,18 @@ typedef struct afl_env_vars {
afl_bench_until_crash, afl_debug_child, afl_autoresume, afl_cal_fast,
afl_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new,
afl_exit_on_seed_issues, afl_try_affinity, afl_ignore_problems,
- afl_keep_timeouts, afl_pizza_mode;
+ afl_keep_timeouts, afl_no_crash_readme, afl_ignore_timeouts,
+ afl_no_startup_calibration, afl_no_warn_instability,
+ afl_post_process_keep_original;
u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path,
*afl_hang_tmout, *afl_forksrv_init_tmout, *afl_preload,
*afl_max_det_extras, *afl_statsd_host, *afl_statsd_port,
*afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size,
- *afl_testcache_entries, *afl_kill_signal, *afl_target_env,
- *afl_persistent_record, *afl_exit_on_time;
+ *afl_testcache_entries, *afl_child_kill_signal, *afl_fsrv_kill_signal,
+ *afl_target_env, *afl_persistent_record, *afl_exit_on_time;
+
+ s32 afl_pizza_mode;
} afl_env_vars_t;
@@ -406,7 +423,7 @@ struct afl_pass_stat {
struct foreign_sync {
- u8 * dir;
+ u8 *dir;
time_t mtime;
};
@@ -418,7 +435,7 @@ typedef struct afl_state {
afl_forkserver_t fsrv;
sharedmem_t shm;
- sharedmem_t * shm_fuzz;
+ sharedmem_t *shm_fuzz;
afl_env_vars_t afl_env;
char **argv; /* argv if needed */
@@ -483,6 +500,7 @@ typedef struct afl_state {
no_unlink, /* do not unlink cur_input */
debug, /* Debug mode */
custom_only, /* Custom mutator only mode */
+ custom_splice_optout, /* Custom mutator no splice buffer */
is_main_node, /* if this is the main node */
is_secondary_node, /* if this is a secondary instance */
pizza_is_served; /* pizza mode */
@@ -529,7 +547,7 @@ typedef struct afl_state {
*virgin_crash; /* Bits we haven't seen in crashes */
double *alias_probability; /* alias weighted probabilities */
- u32 * alias_table; /* alias weighted random lookup table */
+ u32 *alias_table; /* alias weighted random lookup table */
u32 active_items; /* enabled entries in the queue */
u8 *var_bytes; /* Bytes that appear to be variable */
@@ -577,7 +595,9 @@ typedef struct afl_state {
last_find_time, /* Time for most recent path (ms) */
last_crash_time, /* Time for most recent crash (ms) */
last_hang_time, /* Time for most recent hang (ms) */
- exit_on_time; /* Delay to exit if no new paths */
+ longest_find_time, /* Longest time taken for a find */
+ exit_on_time, /* Delay to exit if no new paths */
+ sync_time; /* Sync time (ms) */
u32 slowest_exec_ms, /* Slowest testcase non hang in ms */
subseq_tmouts; /* Number of timeouts in a row */
@@ -642,7 +662,7 @@ typedef struct afl_state {
/* CmpLog */
- char * cmplog_binary;
+ char *cmplog_binary;
afl_forkserver_t cmplog_fsrv; /* cmplog has its own little forkserver */
/* Custom mutators */
@@ -654,10 +674,10 @@ typedef struct afl_state {
u32 cmplog_max_filesize;
u32 cmplog_lvl;
u32 colorize_success;
- u8 cmplog_enable_arith, cmplog_enable_transform;
+ u8 cmplog_enable_arith, cmplog_enable_transform, cmplog_random_colorization;
struct afl_pass_stat *pass_stats;
- struct cmp_map * orig_cmp_map;
+ struct cmp_map *orig_cmp_map;
u8 describe_op_buf_256[256]; /* describe_op will use this to return a string
up to 256 */
@@ -678,20 +698,22 @@ typedef struct afl_state {
/* statistics file */
double last_bitmap_cvg, last_stability, last_eps;
+ u64 stats_file_update_freq_msecs; /* Stats update frequency (msecs) */
/* plot file saves from last run */
u32 plot_prev_qp, plot_prev_pf, plot_prev_pnf, plot_prev_ce, plot_prev_md;
u64 plot_prev_qc, plot_prev_uc, plot_prev_uh, plot_prev_ed;
- u64 stats_last_stats_ms, stats_last_plot_ms, stats_last_ms, stats_last_execs;
+ u64 stats_last_stats_ms, stats_last_plot_ms, stats_last_queue_ms,
+ stats_last_ms, stats_last_execs;
/* StatsD */
u64 statsd_last_send_ms;
struct sockaddr_in statsd_server;
int statsd_sock;
- char * statsd_tags_flavor;
- char * statsd_tags_format;
- char * statsd_metric_format;
+ char *statsd_tags_flavor;
+ char *statsd_tags_format;
+ char *statsd_metric_format;
int statsd_metric_format_type;
double stats_avg_exec;
@@ -769,9 +791,9 @@ typedef struct afl_state {
struct custom_mutator {
const char *name;
- char * name_short;
- void * dh;
- u8 * post_process_buf;
+ char *name_short;
+ void *dh;
+ u8 *post_process_buf;
u8 stacked_custom_prob, stacked_custom;
void *data; /* custom mutator data ptr */
@@ -815,17 +837,29 @@ struct custom_mutator {
u32 (*afl_custom_fuzz_count)(void *data, const u8 *buf, size_t buf_size);
/**
- * Perform custom mutations on a given input
+ * Opt-out of a splicing input for the fuzz mutator
*
- * (Optional for now. Required in the future)
+ * Empty dummy function. It's presence tells afl-fuzz not to pass a
+ * splice data pointer and len.
*
* @param data pointer returned in afl_custom_init by this custom mutator
+ * @noreturn
+ */
+ void (*afl_custom_splice_optout)(void *data);
+
+ /**
+ * Perform custom mutations on a given input
+ *
+ * (Optional)
+ *
+ * Getting an add_buf can be skipped by using afl_custom_splice_optout().
+ *
+ * @param[in] data Pointer returned in afl_custom_init by this custom mutator
* @param[in] buf Pointer to the input data to be mutated and the mutated
* output
* @param[in] buf_size Size of the input/output data
- * @param[out] out_buf the new buffer. We may reuse *buf if large enough.
- * *out_buf = NULL is treated as FATAL.
- * @param[in] add_buf Buffer containing the additional test case
+ * @param[out] out_buf The new buffer, under your memory mgmt.
+ * @param[in] add_buf Buffer containing an additional test case (splicing)
* @param[in] add_buf_size Size of the additional test case
* @param[in] max_size Maximum size of the mutated output. The mutation must
* not produce data larger than max_size.
@@ -853,14 +887,19 @@ struct custom_mutator {
* A post-processing function to use right before AFL writes the test case to
* disk in order to execute the target.
*
- * (Optional) If this functionality is not needed, simply don't define this
+ * NOTE: Do not do any random changes to the data in this function!
+ *
+ * PERFORMANCE: If you can modify the data in-place you will have a better
+ * performance. Modify *data and set `*out_buf = data`.
+ *
+ * (Optional) If this functionality is not needed, simply do not define this
* function.
*
* @param[in] data pointer returned in afl_custom_init by this custom mutator
* @param[in] buf Buffer containing the test case to be executed
* @param[in] buf_size Size of the test case
* @param[out] out_buf Pointer to the buffer storing the test case after
- * processing. External library should allocate memory for out_buf.
+ * processing. The external library should allocate memory for out_buf.
* It can chose to alter buf in-place, if the space is large enough.
* @return Size of the output buffer.
*/
@@ -967,6 +1006,19 @@ struct custom_mutator {
u8 (*afl_custom_queue_get)(void *data, const u8 *filename);
/**
+ * This method can be used if you want to send data to the target yourself,
+ * e.g. via IPC. This replaces some usage of utils/afl_proxy but requires
+ * that you start the target with afl-fuzz.
+ *
+ * (Optional)
+ *
+ * @param data pointer returned in afl_custom_init by this custom mutator
+ * @param buf Buffer containing the test case
+ * @param buf_size Size of the test case
+ */
+ void (*afl_custom_fuzz_send)(void *data, const u8 *buf, size_t buf_size);
+
+ /**
* Allow for additional analysis (e.g. calling a different tool that does a
* different kind of coverage and saves this for the custom mutator).
*
@@ -1020,6 +1072,7 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *, char *);
void finalize_py_module(void *);
u32 fuzz_count_py(void *, const u8 *, size_t);
+void fuzz_send_py(void *, const u8 *, size_t);
size_t post_process_py(void *, u8 *, size_t, u8 **);
s32 init_trim_py(void *, u8 *, size_t);
s32 post_trim_py(void *, u8);
@@ -1029,6 +1082,7 @@ u8 havoc_mutation_probability_py(void *);
u8 queue_get_py(void *, const u8 *);
const char *introspection_py(void *);
u8 queue_new_entry_py(void *, const u8 *, const u8 *);
+void splice_optout(void *);
void deinit_py(void *);
#endif
@@ -1051,7 +1105,6 @@ u32 count_bits(afl_state_t *, u8 *);
u32 count_bytes(afl_state_t *, u8 *);
u32 count_non_255_bytes(afl_state_t *, u8 *);
void simplify_trace(afl_state_t *, u8 *);
-void classify_counts(afl_forkserver_t *);
#ifdef WORD_SIZE_64
void discover_word(u8 *ret, u64 *current, u64 *virgin);
#else
@@ -1065,6 +1118,9 @@ u8 *describe_op(afl_state_t *, u8, size_t);
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
/* Extras */
@@ -1084,6 +1140,7 @@ void load_stats_file(afl_state_t *);
void write_setup_file(afl_state_t *, u32, char **);
void write_stats_file(afl_state_t *, u32, double, double, double);
void maybe_update_plot_file(afl_state_t *, u32, double, double);
+void write_queue_stats(afl_state_t *);
void show_stats(afl_state_t *);
void show_stats_normal(afl_state_t *);
void show_stats_pizza(afl_state_t *);
@@ -1139,11 +1196,13 @@ void fix_up_sync(afl_state_t *);
void check_asan_opts(afl_state_t *);
void check_binary(afl_state_t *, u8 *);
void check_if_tty(afl_state_t *);
-void setup_signal_handlers(void);
void save_cmdline(afl_state_t *, u32, char **);
void read_foreign_testcases(afl_state_t *, int);
void write_crash_readme(afl_state_t *afl);
u8 check_if_text_buf(u8 *buf, u32 len);
+#ifndef AFL_SHOWMAP
+void setup_signal_handlers(void);
+#endif
/* CmpLog */
@@ -1165,7 +1224,7 @@ double rand_next_percent(afl_state_t *afl);
static inline u32 rand_below(afl_state_t *afl, u32 limit) {
- if (limit <= 1) return 0;
+ if (unlikely(limit <= 1)) return 0;
/* The boundary not being necessarily a power of 2,
we need to ensure the result uniformity. */
@@ -1198,7 +1257,7 @@ static inline u32 rand_below(afl_state_t *afl, u32 limit) {
expand havoc mode */
static inline u32 rand_below_datalen(afl_state_t *afl, u32 limit) {
- if (limit <= 1) return 0;
+ if (unlikely(limit <= 1)) return 0;
switch (rand_below(afl, 3)) {
diff --git a/include/afl-prealloc.h b/include/afl-prealloc.h
index bdf0d87f..d19a7b52 100644
--- a/include/afl-prealloc.h
+++ b/include/afl-prealloc.h
@@ -10,7 +10,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
diff --git a/include/alloc-inl.h b/include/alloc-inl.h
index 6c2bafff..1e9a192b 100644
--- a/include/alloc-inl.h
+++ b/include/alloc-inl.h
@@ -10,7 +10,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -42,7 +42,7 @@
// Be careful! _WANT_ORIGINAL_AFL_ALLOC is not compatible with custom mutators
#ifndef _WANT_ORIGINAL_AFL_ALLOC
- // afl++ stuff without memory corruption checks - for speed
+ // AFL++ stuff without memory corruption checks - for speed
/* User-facing macro to sprintf() to a dynamically allocated buffer. */
@@ -704,12 +704,11 @@ static inline void *afl_realloc(void **buf, size_t size_needed) {
*buf = NULL;
return NULL;
- } else {
-
- new_buf = newer_buf;
-
}
+ new_buf = newer_buf;
+ memset(((u8 *)new_buf) + current_size, 0, next_size - current_size);
+
new_buf->complete_size = next_size;
*buf = (void *)(new_buf->buf);
return *buf;
diff --git a/include/cmplog.h b/include/cmplog.h
index c6d2957e..e4821444 100644
--- a/include/cmplog.h
+++ b/include/cmplog.h
@@ -12,7 +12,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -34,7 +34,7 @@
#define CMP_MAP_W 65536
#define CMP_MAP_H 32
-#define CMP_MAP_RTN_H (CMP_MAP_H / 4)
+#define CMP_MAP_RTN_H (CMP_MAP_H / 2)
#define SHAPE_BYTES(x) (x + 1)
diff --git a/include/common.h b/include/common.h
index 896c5fb2..8d85d201 100644
--- a/include/common.h
+++ b/include/common.h
@@ -10,7 +10,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -32,6 +32,7 @@
#include <unistd.h>
#include <sys/time.h>
#include <stdbool.h>
+#include "forkserver.h"
#include "types.h"
/* STRINGIFY_VAL_SIZE_MAX will fit all stringify_ strings. */
@@ -42,6 +43,7 @@ u32 check_binary_signatures(u8 *fn);
void detect_file_args(char **argv, u8 *prog_in, bool *use_stdin);
void print_suggested_envs(char *mispelled_env);
void check_environment_vars(char **env);
+void set_sanitizer_defaults();
char **argv_cpy_dup(int argc, char **argv);
void argv_cpy_free(char **argv);
@@ -49,7 +51,7 @@ void argv_cpy_free(char **argv);
char **get_cs_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv);
char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv);
char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv);
-char * get_afl_env(char *env);
+char *get_afl_env(char *env);
/* Extract env vars from input string and set them using setenv()
For use with AFL_TARGET_ENV, ... */
@@ -67,10 +69,19 @@ u8 *find_binary(u8 *fname);
u8 *find_afl_binary(u8 *own_loc, u8 *fname);
-/* Parses the kill signal environment variable, FATALs on error.
- If the env is not set, sets the env to default_signal for the signal handlers
- and returns the default_signal. */
-int parse_afl_kill_signal_env(u8 *afl_kill_signal_env, int default_signal);
+/* Parses the (numeric) kill signal environment variable passed
+ via `numeric_signal_as_str`.
+ If NULL is passed, the `default_signal` value is returned.
+ FATALs if `numeric_signal_as_str` is not a valid integer .*/
+int parse_afl_kill_signal(u8 *numeric_signal_as_str, int default_signal);
+
+/* Configure the signals that are used to kill the forkserver
+ and the forked childs. If `afl_kill_signal_env` or `afl_fsrv_kill_signal_env`
+ is NULL, the appropiate values are read from the environment. */
+void configure_afl_kill_signals(afl_forkserver_t *fsrv,
+ char *afl_kill_signal_env,
+ char *afl_fsrv_kill_signal_env,
+ int default_server_kill_signal);
/* Read a bitmap from file fname to memory
This is for the -B option again. */
@@ -132,5 +143,15 @@ FILE *create_ffile(u8 *fn);
/* create a file */
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,
+ size_t needlelen);
+
+#ifdef __linux__
+/* Nyx helper functions to create and remove tmp workdirs */
+char *create_nyx_tmp_workdir(void);
+void remove_nyx_tmp_workdir(afl_forkserver_t *fsrv, char *nyx_out_dir_path);
+#endif
+
#endif
diff --git a/include/config.h b/include/config.h
index 9fc92b06..194786f7 100644
--- a/include/config.h
+++ b/include/config.h
@@ -10,7 +10,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -26,7 +26,7 @@
/* Version string: */
// c = release, a = volatile github dev, e = experimental branch
-#define VERSION "++4.01a"
+#define VERSION "++4.07a"
/******************************************************
* *
@@ -81,7 +81,7 @@
will be kept and written to the crash/ directory as RECORD:... files.
Note that every crash will be written, not only unique ones! */
-//#define AFL_PERSISTENT_RECORD
+// #define AFL_PERSISTENT_RECORD
/* console output colors: There are three ways to configure its behavior
* 1. default: colored outputs fixed on: defined USE_COLOR && defined
@@ -153,8 +153,9 @@
/* Number of calibration cycles per every new test case (and for test
cases that show variable behavior): */
-#define CAL_CYCLES 8U
-#define CAL_CYCLES_LONG 20U
+#define CAL_CYCLES_FAST 3U
+#define CAL_CYCLES 7U
+#define CAL_CYCLES_LONG 12U
/* Number of subsequent timeouts before abandoning an input file: */
@@ -289,10 +290,11 @@
#define UI_TARGET_HZ 5
-/* Fuzzer stats file and plot update intervals (sec): */
+/* Fuzzer stats file, queue stats and plot update intervals (sec): */
#define STATS_UPDATE_SEC 60
#define PLOT_UPDATE_SEC 5
+#define QUEUE_UPDATE_SEC 1800
/* Smoothing divisor for CPU load and exec speed stats (1 - no smoothing). */
@@ -362,9 +364,9 @@
* *
***********************************************************/
-/* Call count interval between reseeding the libc PRNG from /dev/urandom: */
+/* Call count interval between reseeding the PRNG from /dev/urandom: */
-#define RESEED_RNG 100000
+#define RESEED_RNG 2500000
/* The default maximum testcase cache size in MB, 0 = disable.
A value between 50 and 250 is a good default value. Note that the
@@ -489,10 +491,14 @@
#define AFL_TXT_MIN_LEN 12
+/* Maximum length of a queue input to be evaluated for "is_ascii"? */
+
+#define AFL_TXT_MAX_LEN 65535
+
/* What is the minimum percentage of ascii characters present to be classifed
as "is_ascii"? */
-#define AFL_TXT_MIN_PERCENT 94
+#define AFL_TXT_MIN_PERCENT 99
/* How often to perform ASCII mutations 0 = disable, 1-8 are good values */
diff --git a/include/debug.h b/include/debug.h
index c2f20f0f..cd621a72 100644
--- a/include/debug.h
+++ b/include/debug.h
@@ -10,7 +10,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -192,7 +192,7 @@ static inline const char *colorfilter(const char *x) {
if (likely(disabled)) return x;
static char monochromestring[4096];
- char * d = monochromestring;
+ char *d = monochromestring;
int in_seq = 0;
while (*x) {
diff --git a/include/envs.h b/include/envs.h
index 25b792fa..edfd06e4 100644
--- a/include/envs.h
+++ b/include/envs.h
@@ -37,11 +37,16 @@ static char *afl_environment_variables[] = {
"AFL_CRASH_EXITCODE",
"AFL_CUSTOM_MUTATOR_LIBRARY",
"AFL_CUSTOM_MUTATOR_ONLY",
+ "AFL_CUSTOM_INFO_PROGRAM",
+ "AFL_CUSTOM_INFO_PROGRAM_ARGV",
+ "AFL_CUSTOM_INFO_PROGRAM_INPUT",
+ "AFL_CUSTOM_INFO_OUT",
"AFL_CXX",
"AFL_CYCLE_SCHEDULES",
"AFL_DEBUG",
"AFL_DEBUG_CHILD",
"AFL_DEBUG_GDB",
+ "AFL_DEBUG_UNICORN",
"AFL_DISABLE_TRIM",
"AFL_DISABLE_LLVM_INSTRUMENTATION",
"AFL_DONT_OPTIMIZE",
@@ -58,15 +63,19 @@ static char *afl_environment_variables[] = {
"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",
@@ -87,6 +96,7 @@ static char *afl_environment_variables[] = {
"AFL_FRIDA_TRACEABLE",
"AFL_FRIDA_VERBOSE",
"AFL_FUZZER_ARGS", // oss-fuzz
+ "AFL_FUZZER_STATS_UPDATE_INTERVAL",
"AFL_GDB",
"AFL_GCC_ALLOWLIST",
"AFL_GCC_DENYLIST",
@@ -100,6 +110,8 @@ static char *afl_environment_variables[] = {
"AFL_HARDEN",
"AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES",
"AFL_IGNORE_PROBLEMS",
+ "AFL_IGNORE_PROBLEMS_COVERAGE",
+ "AFL_IGNORE_TIMEOUTS",
"AFL_IGNORE_UNKNOWN_ENVS",
"AFL_IMPORT_FIRST",
"AFL_INPUT_LEN_MIN",
@@ -108,6 +120,7 @@ static char *afl_environment_variables[] = {
"AFL_INST_RATIO",
"AFL_KEEP_TIMEOUTS",
"AFL_KILL_SIGNAL",
+ "AFL_FORK_SERVER_KILL_SIGNAL",
"AFL_KEEP_TRACES",
"AFL_KEEP_ASSEMBLY",
"AFL_LD_HARD_FAIL",
@@ -120,12 +133,15 @@ static char *afl_environment_variables[] = {
"AFL_LLVM_ALLOWLIST",
"AFL_LLVM_DENYLIST",
"AFL_LLVM_BLOCKLIST",
+ "AFL_CMPLOG",
"AFL_LLVM_CMPLOG",
+ "AFL_GCC_CMPLOG",
"AFL_LLVM_INSTRIM",
"AFL_LLVM_CALLER",
"AFL_LLVM_CTX",
"AFL_LLVM_CTX_K",
"AFL_LLVM_DICT2FILE",
+ "AFL_LLVM_DICT2FILE_NO_MAIN",
"AFL_LLVM_DOCUMENT_IDS",
"AFL_LLVM_INSTRIM_LOOPHEAD",
"AFL_LLVM_INSTRUMENT",
@@ -149,8 +165,9 @@ static char *afl_environment_variables[] = {
"AFL_LLVM_SKIP_NEVERZERO",
"AFL_NO_AFFINITY",
"AFL_TRY_AFFINITY",
- "AFL_LLVM_LTO_STARTID",
"AFL_LLVM_LTO_DONTWRITEID",
+ "AFL_LLVM_LTO_SKIPINIT"
+ "AFL_LLVM_LTO_STARTID",
"AFL_NO_ARITH",
"AFL_NO_AUTODICT",
"AFL_NO_BUILTIN",
@@ -159,9 +176,12 @@ static char *afl_environment_variables[] = {
"AFL_NO_COLOUR",
#endif
"AFL_NO_CPU_RED",
+ "AFL_NO_CRASH_README",
"AFL_NO_FORKSRV",
"AFL_NO_UI",
"AFL_NO_PYTHON",
+ "AFL_NO_STARTUP_CALIBRATION",
+ "AFL_NO_WARN_INSTABILITY",
"AFL_UNTRACER_FILE",
"AFL_LLVM_USE_TRACE_PC",
"AFL_MAP_SIZE",
@@ -173,6 +193,7 @@ static char *afl_environment_variables[] = {
"AFL_PATH",
"AFL_PERFORMANCE_FILE",
"AFL_PERSISTENT_RECORD",
+ "AFL_POST_PROCESS_KEEP_ORIGINAL",
"AFL_PRELOAD",
"AFL_TARGET_ENV",
"AFL_PYTHON_MODULE",
@@ -194,6 +215,7 @@ static char *afl_environment_variables[] = {
"AFL_QEMU_INST_RANGES",
"AFL_QEMU_EXCLUDE_RANGES",
"AFL_QEMU_SNAPSHOT",
+ "AFL_QEMU_TRACK_UNSTABLE",
"AFL_QUIET",
"AFL_RANDOM_ALLOC_CANARY",
"AFL_REAL_PATH",
@@ -206,6 +228,7 @@ static char *afl_environment_variables[] = {
"AFL_STATSD_HOST",
"AFL_STATSD_PORT",
"AFL_STATSD_TAGS_FLAVOR",
+ "AFL_SYNC_TIME",
"AFL_TESTCACHE_SIZE",
"AFL_TESTCACHE_ENTRIES",
"AFL_TMIN_EXACT",
diff --git a/include/forkserver.h b/include/forkserver.h
index 5b66e7ec..f5069ce2 100644
--- a/include/forkserver.h
+++ b/include/forkserver.h
@@ -12,7 +12,7 @@
Dominik Maier <mail@dmnk.co>>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -43,7 +43,7 @@ typedef enum NyxReturnValue {
Normal,
Crash,
Asan,
- Timout,
+ Timeout,
InvalidWriteToPayload,
Error,
IoError,
@@ -51,16 +51,28 @@ typedef enum NyxReturnValue {
} NyxReturnValue;
+typedef enum NyxProcessRole {
+
+ StandAlone,
+ Parent,
+ Child,
+
+} NyxProcessRole;
+
typedef struct {
- void *(*nyx_new)(const char *sharedir, const char *workdir, uint32_t cpu_id,
- uint32_t input_buffer_size,
- bool input_buffer_write_protection);
- void *(*nyx_new_parent)(const char *sharedir, const char *workdir,
- uint32_t cpu_id, uint32_t input_buffer_size,
- bool input_buffer_write_protection);
- void *(*nyx_new_child)(const char *sharedir, const char *workdir,
- uint32_t cpu_id, uint32_t worker_id);
+ void *(*nyx_config_load)(const char *sharedir);
+ void (*nyx_config_set_workdir_path)(void *config, const char *workdir);
+ void (*nyx_config_set_input_buffer_size)(void *config,
+ uint32_t input_buffer_size);
+ void (*nyx_config_set_input_buffer_write_protection)(
+ void *config, bool input_buffer_write_protection);
+ void (*nyx_config_set_hprintf_fd)(void *config, int32_t hprintf_fd);
+ void (*nyx_config_set_process_role)(void *config, enum NyxProcessRole role);
+ void (*nyx_config_set_reuse_snapshot_path)(void *config,
+ const char *reuse_snapshot_path);
+
+ void *(*nyx_new)(void *config, uint32_t worker_id);
void (*nyx_shutdown)(void *qemu_process);
void (*nyx_option_set_reload_mode)(void *qemu_process, bool enable);
void (*nyx_option_set_timeout)(void *qemu_process, uint8_t timeout_sec,
@@ -73,8 +85,13 @@ typedef struct {
uint32_t (*nyx_get_aux_string)(void *nyx_process, uint8_t *buffer,
uint32_t size);
+ bool (*nyx_remove_work_dir)(const char *workdir);
+
} nyx_plugin_handler_t;
+/* Imports helper functions to enable Nyx mode (Linux only )*/
+nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary);
+
#endif
typedef struct afl_forkserver {
@@ -150,7 +167,7 @@ typedef struct afl_forkserver {
#ifdef AFL_PERSISTENT_RECORD
u32 persistent_record_idx; /* persistent replay cache ptr */
u32 persistent_record_cnt; /* persistent replay counter */
- u8 * persistent_record_dir;
+ u8 *persistent_record_dir;
u8 **persistent_record_data;
u32 *persistent_record_len;
s32 persistent_record_pid;
@@ -163,19 +180,23 @@ typedef struct afl_forkserver {
void (*add_extra_func)(void *afl_ptr, u8 *mem, u32 len);
- u8 kill_signal;
+ u8 child_kill_signal;
+ u8 fsrv_kill_signal;
+
u8 persistent_mode;
#ifdef __linux__
nyx_plugin_handler_t *nyx_handlers;
- char * out_dir_path; /* path to the output directory */
+ char *out_dir_path; /* path to the output directory */
u8 nyx_mode; /* if running in nyx mode or not */
bool nyx_parent; /* create initial snapshot */
bool nyx_standalone; /* don't serialize the snapshot */
- void * nyx_runner; /* nyx runner object */
+ void *nyx_runner; /* nyx runner object */
u32 nyx_id; /* nyx runner id (0 -> master) */
u32 nyx_bind_cpu_id; /* nyx runner cpu id */
- char * nyx_aux_string;
+ char *nyx_aux_string;
+ bool nyx_use_tmp_workdir;
+ char *nyx_tmp_workdir_path;
#endif
} afl_forkserver_t;
diff --git a/include/hash.h b/include/hash.h
index d8fef70c..0243c5b7 100644
--- a/include/hash.h
+++ b/include/hash.h
@@ -15,7 +15,7 @@
Other code written by Michal Zalewski
Copyright 2016 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
diff --git a/include/list.h b/include/list.h
index a6223564..283bf035 100644
--- a/include/list.h
+++ b/include/list.h
@@ -10,7 +10,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -43,7 +43,7 @@ typedef struct list_element {
struct list_element *prev;
struct list_element *next;
- void * data;
+ void *data;
} element_t;
@@ -102,7 +102,7 @@ static inline void list_append(list_t *list, void *el) {
#define LIST_FOREACH(list, type, block) \
do { \
\
- list_t * li = (list); \
+ list_t *li = (list); \
element_t *head = get_head((li)); \
element_t *el_box = (head)->next; \
if (!el_box) FATAL("foreach over uninitialized list"); \
diff --git a/include/sharedmem.h b/include/sharedmem.h
index e646b73f..d32bd845 100644
--- a/include/sharedmem.h
+++ b/include/sharedmem.h
@@ -12,7 +12,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -56,7 +56,7 @@ typedef struct sharedmem {
} sharedmem_t;
-u8 * afl_shm_init(sharedmem_t *, size_t, unsigned char non_instrumented_mode);
+u8 *afl_shm_init(sharedmem_t *, size_t, unsigned char non_instrumented_mode);
void afl_shm_deinit(sharedmem_t *);
#endif
diff --git a/include/snapshot-inl.h b/include/snapshot-inl.h
index 8d2f41ff..3864e473 100644
--- a/include/snapshot-inl.h
+++ b/include/snapshot-inl.h
@@ -12,7 +12,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
diff --git a/include/types.h b/include/types.h
index 4a68b1b0..d6476d82 100644
--- a/include/types.h
+++ b/include/types.h
@@ -10,7 +10,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -57,7 +57,7 @@ typedef uint128_t u128;
#define FS_OPT_SHDMEM_FUZZ 0x01000000
#define FS_OPT_NEWCMPLOG 0x02000000
#define FS_OPT_OLD_AFLPP_WORKAROUND 0x0f000000
-// FS_OPT_MAX_MAPSIZE is 8388608 = 0x800000 = 2^23 = 1 << 22
+// FS_OPT_MAX_MAPSIZE is 8388608 = 0x800000 = 2^23 = 1 << 23
#define FS_OPT_MAX_MAPSIZE ((0x00fffffeU >> 1) + 1)
#define FS_OPT_GET_MAPSIZE(x) (((x & 0x00fffffe) >> 1) + 1)
#define FS_OPT_SET_MAPSIZE(x) \
diff --git a/include/xxhash.h b/include/xxhash.h
index 4f101003..7bc0a14e 100644
--- a/include/xxhash.h
+++ b/include/xxhash.h
@@ -1,7 +1,7 @@
/*
* xxHash - Extremely Fast Hash algorithm
* Header File
- * Copyright (C) 2012-2022 Yann Collet
+ * Copyright (C) 2012-2023 Yann Collet
*
* BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
*
@@ -510,7 +510,7 @@ XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t *statePtr);
* @pre
* @p dst_state and @p src_state must not be `NULL` and must not overlap.
*/
-XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t * dst_state,
+XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t *dst_state,
const XXH32_state_t *src_state);
/*!
@@ -742,10 +742,10 @@ XXH_PUBLIC_API XXH64_hash_t XXH64(const void *input, size_t length,
*
* @see XXH64_state_s for details.
*/
-typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */
+typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */
XXH_PUBLIC_API XXH64_state_t *XXH64_createState(void);
XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t *statePtr);
-XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t * dst_state,
+XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t *dst_state,
const XXH64_state_t *src_state);
XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t *statePtr,
@@ -870,10 +870,10 @@ XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSecret(const void *data, size_t len,
*
* @see XXH3_state_s for details.
*/
-typedef struct XXH3_state_s XXH3_state_t;
+typedef struct XXH3_state_s XXH3_state_t;
XXH_PUBLIC_API XXH3_state_t *XXH3_createState(void);
XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t *statePtr);
-XXH_PUBLIC_API void XXH3_copyState(XXH3_state_t * dst_state,
+XXH_PUBLIC_API void XXH3_copyState(XXH3_state_t *dst_state,
const XXH3_state_t *src_state);
/*
@@ -902,7 +902,7 @@ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecret(
XXH3_state_t *statePtr, const void *secret, size_t secretSize);
XXH_PUBLIC_API XXH_errorcode XXH3_64bits_update(XXH3_state_t *statePtr,
- const void * input,
+ const void *input,
size_t length);
XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest(const XXH3_state_t *statePtr);
@@ -955,7 +955,7 @@ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecret(
XXH3_state_t *statePtr, const void *secret, size_t secretSize);
XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update(XXH3_state_t *statePtr,
- const void * input,
+ const void *input,
size_t length);
XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest(const XXH3_state_t *statePtr);
@@ -1229,7 +1229,7 @@ struct XXH3_state_s {
* `secretBuffer`. When customSeedSize > 0, supplying NULL as customSeed is
* undefined behavior.
*/
-XXH_PUBLIC_API void XXH3_generateSecret(void * secretBuffer,
+XXH_PUBLIC_API void XXH3_generateSecret(void *secretBuffer,
const void *customSeed,
size_t customSeedSize);
@@ -1951,7 +1951,7 @@ static xxh_u32 XXH_readBE32(const void *ptr) {
#endif
-XXH_FORCE_INLINE xxh_u32 XXH_readLE32_align(const void * ptr,
+XXH_FORCE_INLINE xxh_u32 XXH_readLE32_align(const void *ptr,
XXH_alignment align) {
if (align == XXH_unaligned) {
@@ -2317,7 +2317,7 @@ XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t *statePtr) {
}
/*! @ingroup xxh32_family */
-XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t * dstState,
+XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t *dstState,
const XXH32_state_t *srcState) {
memcpy(dstState, srcState, sizeof(*dstState));
@@ -2355,7 +2355,7 @@ XXH_PUBLIC_API XXH_errorcode XXH32_update(XXH32_state_t *state,
{
- const xxh_u8 * p = (const xxh_u8 *)input;
+ const xxh_u8 *p = (const xxh_u8 *)input;
const xxh_u8 *const bEnd = p + len;
state->total_len_32 += (XXH32_hash_t)len;
@@ -2625,7 +2625,7 @@ static xxh_u64 XXH_readBE64(const void *ptr) {
#endif
-XXH_FORCE_INLINE xxh_u64 XXH_readLE64_align(const void * ptr,
+XXH_FORCE_INLINE xxh_u64 XXH_readLE64_align(const void *ptr,
XXH_alignment align) {
if (align == XXH_unaligned)
@@ -2852,7 +2852,7 @@ XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t *statePtr) {
}
/*! @ingroup xxh64_family */
-XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t * dstState,
+XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t *dstState,
const XXH64_state_t *srcState) {
memcpy(dstState, srcState, sizeof(*dstState));
@@ -2890,7 +2890,7 @@ XXH_PUBLIC_API XXH_errorcode XXH64_update(XXH64_state_t *state,
{
- const xxh_u8 * p = (const xxh_u8 *)input;
+ const xxh_u8 *p = (const xxh_u8 *)input;
const xxh_u8 *const bEnd = p + len;
state->total_len += len;
@@ -4268,7 +4268,7 @@ XXH_FORCE_INLINE XXH_TARGET_AVX512 void XXH3_initCustomSecret_avx512(
union {
const __m512i *cp;
- void * p;
+ void *p;
} remote_const_void;
@@ -4385,7 +4385,7 @@ XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_initCustomSecret_avx2(
(xxh_i64)(0U - seed64), (xxh_i64)seed64);
const __m256i *const src = (const __m256i *)((const void *)XXH3_kSecret);
- __m256i * dest = (__m256i *)customSecret;
+ __m256i *dest = (__m256i *)customSecret;
#if defined(__GNUC__) || defined(__clang__)
/*
@@ -4519,7 +4519,7 @@ XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_initCustomSecret_sse2(
int i;
const void *const src16 = XXH3_kSecret;
- __m128i * dst16 = (__m128i *)customSecret;
+ __m128i *dst16 = (__m128i *)customSecret;
#if defined(__GNUC__) || defined(__clang__)
/*
* On GCC & Clang, marking 'dest' as modified will cause the compiler:
@@ -4594,7 +4594,7 @@ XXH_FORCE_INLINE void XXH3_scrambleAcc_neon(void *XXH_RESTRICT acc,
{
- uint64x2_t * xacc = (uint64x2_t *)acc;
+ uint64x2_t *xacc = (uint64x2_t *)acc;
uint8_t const *xsecret = (uint8_t const *)secret;
uint32x2_t prime = vdup_n_u32(XXH_PRIME32_1);
@@ -5106,7 +5106,7 @@ XXH_FORCE_INLINE XXH64_hash_t XXH3_hashLong_64b_withSeed_internal(
/*
* It's important for performance that XXH3_hashLong is not inlined.
*/
-XXH_NO_INLINE XXH64_hash_t XXH3_hashLong_64b_withSeed(const void * input,
+XXH_NO_INLINE XXH64_hash_t XXH3_hashLong_64b_withSeed(const void *input,
size_t len,
XXH64_hash_t seed,
const xxh_u8 *secret,
@@ -5277,7 +5277,7 @@ XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t *statePtr) {
}
/*! @ingroup xxh3_family */
-XXH_PUBLIC_API void XXH3_copyState(XXH3_state_t * dst_state,
+XXH_PUBLIC_API void XXH3_copyState(XXH3_state_t *dst_state,
const XXH3_state_t *src_state) {
memcpy(dst_state, src_state, sizeof(*dst_state));
@@ -5482,8 +5482,8 @@ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_update(XXH3_state_t *state,
}
-XXH_FORCE_INLINE void XXH3_digest_long(XXH64_hash_t * acc,
- const XXH3_state_t * state,
+XXH_FORCE_INLINE void XXH3_digest_long(XXH64_hash_t *acc,
+ const XXH3_state_t *state,
const unsigned char *secret) {
/*
@@ -5545,7 +5545,7 @@ XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest(const XXH3_state_t *state) {
#define XXH_MIN(x, y) (((x) > (y)) ? (y) : (x))
/*! @ingroup xxh3_family */
-XXH_PUBLIC_API void XXH3_generateSecret(void * secretBuffer,
+XXH_PUBLIC_API void XXH3_generateSecret(void *secretBuffer,
const void *customSeed,
size_t customSeedSize) {
@@ -6081,7 +6081,7 @@ XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSecret(const void *input,
}
/*! @ingroup xxh3_family */
-XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSeed(const void * input,
+XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSeed(const void *input,
size_t len,
XXH64_hash_t seed) {
@@ -6142,7 +6142,7 @@ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSeed(XXH3_state_t *statePtr,
/*! @ingroup xxh3_family */
XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update(XXH3_state_t *state,
- const void * input,
+ const void *input,
size_t len) {
return XXH3_update(state, (const xxh_u8 *)input, len, XXH3_accumulate_512,
diff --git a/instrumentation/README.gcc_plugin.md b/instrumentation/README.gcc_plugin.md
index ed39af9d..011a574a 100644
--- a/instrumentation/README.gcc_plugin.md
+++ b/instrumentation/README.gcc_plugin.md
@@ -99,4 +99,11 @@ See
## 6) Bonus feature #3: selective instrumentation
It can be more effective to fuzzing to only instrument parts of the code. For
-details, see [README.instrument_list.md](README.instrument_list.md). \ No newline at end of file
+details, see [README.instrument_list.md](README.instrument_list.md).
+
+## 7) Bonus feature #4: CMPLOG
+
+The gcc_plugin also support CMPLOG/Redqueen, just set `AFL_GCC_CMPLOG` before
+instrumenting the target.
+Read more about this in the llvm document.
+
diff --git a/instrumentation/README.llvm.md b/instrumentation/README.llvm.md
index 7855a987..126cf1a2 100644
--- a/instrumentation/README.llvm.md
+++ b/instrumentation/README.llvm.md
@@ -116,7 +116,7 @@ PCGUARD analysis.
Several options are present to make llvm_mode faster or help it rearrange the
code to make afl-fuzz path discovery easier.
-If you need just to instrument specific parts of the code, you can the
+If you need just to instrument specific parts of the code, you can create the
instrument file list which C/C++ files to actually instrument. See
[README.instrument_list.md](README.instrument_list.md)
@@ -167,6 +167,10 @@ Just specify `AFL_LLVM_DICT2FILE=/absolute/path/file.txt` and during compilation
all constant string compare parameters will be written to this file to be used
with afl-fuzz' `-x` option.
+Adding `AFL_LLVM_DICT2FILE_NO_MAIN=1` will skip parsing `main()` which often
+does command line parsing which has string comparisons that are not helpful
+for fuzzing.
+
## 6) AFL++ Context Sensitive Branch Coverage
### What is this?
@@ -275,4 +279,28 @@ then this can give a small performance boost.
Please note that the default counter implementations are not thread safe!
Support for thread safe counters in mode LLVM CLASSIC can be activated with
-setting `AFL_LLVM_THREADSAFE_INST=1`. \ No newline at end of file
+setting `AFL_LLVM_THREADSAFE_INST=1`.
+
+## 8) Source code coverage through instrumentation
+
+Measuring source code coverage is a common task in fuzzing, but it is very
+difficut to do in some situations (e.g. when using snapshot fuzzing).
+
+When using the `AFL_LLVM_INSTRUMENT=llvm-codecov` option, afl-cc will use
+native trace-pc-guard instrumentation but additionally select options that
+are required to utilize the instrumentation for source code coverage.
+
+In particular, it will switch the instrumentation to be per basic block
+instead of instrumenting edges, disable all guard pruning and enable the
+experimental pc-table support that allows the runtime to gather 100% of
+instrumented basic blocks at start, including their locations.
+
+Note: You must compile AFL with the `CODE_COVERAGE=1` option to enable the
+respective parts in the AFL compiler runtime. Support is currently only
+implemented for Nyx, but can in theory also work without Nyx.
+
+Note: You might have to adjust `MAP_SIZE_POW2` in include/config.h to ensure
+that your coverage map is large enough to hold all basic blocks of your
+target program without any collisions.
+
+More documentation on how to utilize this with Nyx will follow.
diff --git a/instrumentation/README.lto.md b/instrumentation/README.lto.md
index a20175b1..df59cc2a 100644
--- a/instrumentation/README.lto.md
+++ b/instrumentation/README.lto.md
@@ -2,52 +2,53 @@
## TL;DR:
-This version requires a current llvm 11+ compiled from the GitHub master.
+This version requires a LLVM 11 or newer.
-1. Use afl-clang-lto/afl-clang-lto++ because it is faster and gives better
- coverage than anything else that is out there in the AFL world.
+1. Use afl-clang-lto/afl-clang-lto++ because the resulting binaries run
+ slightly faster and give better coverage.
-2. You can use it together with llvm_mode: laf-intel and the instrument file
- listing features and can be combined with cmplog/Redqueen.
+2. You can use it together with COMPCOV, COMPLOG and the instrument file
+ listing features.
-3. It only works with llvm 11+.
+3. It only works with LLVM 11 or newer.
-4. AUTODICTIONARY feature (see below)!
+4. AUTODICTIONARY feature (see below)
-5. If any problems arise, be sure to set `AR=llvm-ar RANLIB=llvm-ranlib`. Some
- targets might need `LD=afl-clang-lto` and others `LD=afl-ld-lto`.
+5. If any problems arise, be sure to set `AR=llvm-ar RANLIB=llvm-ranlib AS=llvm-as`.
+ Some targets might need `LD=afl-clang-lto` and others `LD=afl-ld-lto`.
## Introduction and problem description
-A big issue with how AFL++ works is that the basic block IDs that are set during
-compilation are random - and hence naturally the larger the number of
-instrumented locations, the higher the number of edge collisions are in the map.
-This can result in not discovering new paths and therefore degrade the
+A big issue with how vanilla AFL worked was that the basic block IDs that are
+set during compilation are random - and hence naturally the larger the number
+of instrumented locations, the higher the number of edge collisions are in the
+map. This can result in not discovering new paths and therefore degrade the
efficiency of the fuzzing process.
-*This issue is underestimated in the fuzzing community!* With a 2^16 = 64kb
+*This issue is underestimated in the fuzzing community* With a 2^16 = 64kb
standard map at already 256 instrumented blocks, there is on average one
collision. On average, a target has 10.000 to 50.000 instrumented blocks, hence
the real collisions are between 750-18.000!
-To reach a solution that prevents any collisions took several approaches and
-many dead ends until we got to this:
+Note that PCGUARD (our own modified implementation and the SANCOV PCGUARD
+implementation from libfuzzer) also provides collision free coverage.
+It is a bit slower though and can a few targets with very early constructors.
* We instrument at link time when we have all files pre-compiled.
* To instrument at link time, we compile in LTO (link time optimization) mode.
* Our compiler (afl-clang-lto/afl-clang-lto++) takes care of setting the correct
LTO options and runs our own afl-ld linker instead of the system linker.
* The LLVM linker collects all LTO files to link and instruments them so that we
- have non-colliding edge overage.
+ have non-colliding edge coverage.
* We use a new (for afl) edge coverage - which is the same as in llvm
-fsanitize=coverage edge coverage mode. :)
The result:
* 10-25% speed gain compared to llvm_mode
-* guaranteed non-colliding edge coverage :-)
+* guaranteed non-colliding edge coverage
* The compile time, especially for binaries to an instrumented library, can be
- much longer.
+ much (and sometimes much much) longer.
Example build output from a libtiff build:
@@ -59,70 +60,30 @@ AUTODICTIONARY: 11 strings found
[+] Instrumented 12071 locations with no collisions (on average 1046 collisions would be in afl-gcc/afl-clang-fast) (non-hardened mode).
```
-## Getting llvm 11+
+## Getting LLVM 11+
-### Installing llvm version 11 or 12
+### Installing llvm
-llvm 11 or even 12 should be available in all current Linux repositories. If you
-use an outdated Linux distribution, read the next section.
-
-### Installing llvm from the llvm repository (version 12+)
-
-Installing the llvm snapshot builds is easy and mostly painless:
-
-In the following line, change `NAME` for your Debian or Ubuntu release name
-(e.g., buster, focal, eon, etc.):
+The best way to install LLVM is to follow [https://apt.llvm.org/](https://apt.llvm.org/)
+e.g. for LLVM 15:
```
-echo deb http://apt.llvm.org/NAME/ llvm-toolchain-NAME NAME >> /etc/apt/sources.list
+wget https://apt.llvm.org/llvm.sh
+chmod +x llvm.sh
+sudo ./llvm.sh 15 all
```
-Then add the pgp key of llvm and install the packages:
+LLVM 11 to 16 should be available in all current Linux repositories.
-```
-wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
-apt-get update && apt-get upgrade -y
-apt-get install -y clang-12 clang-tools-12 libc++1-12 libc++-12-dev \
- libc++abi1-12 libc++abi-12-dev libclang1-12 libclang-12-dev \
- libclang-common-12-dev libclang-cpp12 libclang-cpp12-dev liblld-12 \
- liblld-12-dev liblldb-12 liblldb-12-dev libllvm12 libomp-12-dev \
- libomp5-12 lld-12 lldb-12 llvm-12 llvm-12-dev llvm-12-runtime llvm-12-tools
-```
+## How to build afl-clang-lto
+
+That part is easy.
+Just set `LLVM_CONFIG` to the llvm-config-VERSION and build AFL++, e.g. for
+LLVM 15:
-### Building llvm yourself (version 12+)
-
-Building llvm from GitHub takes quite some time and is not painless:
-
-```sh
-sudo apt install binutils-dev # this is *essential*!
-git clone --depth=1 https://github.com/llvm/llvm-project
-cd llvm-project
-mkdir build
-cd build
-
-# Add -G Ninja if ninja-build installed
-# "Building with ninja significantly improves your build time, especially with
-# incremental builds, and improves your memory usage."
-cmake \
- -DCLANG_INCLUDE_DOCS="OFF" \
- -DCMAKE_BUILD_TYPE=Release \
- -DLLVM_BINUTILS_INCDIR=/usr/include/ \
- -DLLVM_BUILD_LLVM_DYLIB="ON" \
- -DLLVM_ENABLE_BINDINGS="OFF" \
- -DLLVM_ENABLE_PROJECTS='clang;compiler-rt;libcxx;libcxxabi;libunwind;lld' \
- -DLLVM_ENABLE_WARNINGS="OFF" \
- -DLLVM_INCLUDE_BENCHMARKS="OFF" \
- -DLLVM_INCLUDE_DOCS="OFF" \
- -DLLVM_INCLUDE_EXAMPLES="OFF" \
- -DLLVM_INCLUDE_TESTS="OFF" \
- -DLLVM_LINK_LLVM_DYLIB="ON" \
- -DLLVM_TARGETS_TO_BUILD="host" \
- ../llvm/
-cmake --build . -j4
-export PATH="$(pwd)/bin:$PATH"
-export LLVM_CONFIG="$(pwd)/bin/llvm-config"
-export LD_LIBRARY_PATH="$(llvm-config --libdir)${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
-cd /path/to/AFLplusplus/
+```
+cd ~/AFLplusplus
+export LLVM_CONFIG=llvm-config-15
make
sudo make install
```
@@ -135,10 +96,10 @@ Also, the instrument file listing (AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST ->
[README.instrument_list.md](README.instrument_list.md)) and laf-intel/compcov
(AFL_LLVM_LAF_* -> [README.laf-intel.md](README.laf-intel.md)) work.
-Example:
+Example (note that you might need to add the version, e.g. `llvm-ar-15`:
```
-CC=afl-clang-lto CXX=afl-clang-lto++ RANLIB=llvm-ranlib AR=llvm-ar ./configure
+CC=afl-clang-lto CXX=afl-clang-lto++ RANLIB=llvm-ranlib AR=llvm-ar AS=llvm-as ./configure
make
```
@@ -316,13 +277,13 @@ AS=llvm-as ...
afl-clang-lto is still work in progress.
Known issues:
-* Anything that llvm 11+ cannot compile, afl-clang-lto cannot compile either -
+* Anything that LLVM 11+ cannot compile, afl-clang-lto cannot compile either -
obviously.
* Anything that does not compile with LTO, afl-clang-lto cannot compile either -
obviously.
Hence, if building a target with afl-clang-lto fails, try to build it with
-llvm12 and LTO enabled (`CC=clang-12`, `CXX=clang++-12`, `CFLAGS=-flto=full`,
+LLVM 12 and LTO enabled (`CC=clang-12`, `CXX=clang++-12`, `CFLAGS=-flto=full`,
and `CXXFLAGS=-flto=full`).
If this succeeds, then there is an issue with afl-clang-lto. Please report at
@@ -340,7 +301,7 @@ knows what this is doing. And the developer who implemented this didn't respond
to emails.)
In December then came the idea to implement this as a pass that is run via the
-llvm "opt" program, which is performed via an own linker that afterwards calls
+LLVM "opt" program, which is performed via an own linker that afterwards calls
the real linker. This was first implemented in January and work ... kinda. The
LTO time instrumentation worked, however, "how" the basic blocks were
instrumented was a problem, as reducing duplicates turned out to be very, very
@@ -352,13 +313,13 @@ dead-end too.
The final idea to solve this came from domenukk who proposed to insert a block
into an edge and then just use incremental counters ... and this worked! After
some trials and errors to implement this vanhauser-thc found out that there is
-actually an llvm function for this: SplitEdge() :-)
+actually an LLVM function for this: SplitEdge() :-)
-Still more problems came up though as this only works without bugs from llvm 9
+Still more problems came up though as this only works without bugs from LLVM 9
onwards, and with high optimization the link optimization ruins the instrumented
control flow graph.
-This is all now fixed with llvm 11+. The llvm's own linker is now able to load
+This is all now fixed with LLVM 11+. The llvm's own linker is now able to load
passes and this bypasses all problems we had.
-Happy end :) \ No newline at end of file
+Happy end :)
diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc
index 9a48ae6d..2d17ffd4 100644
--- a/instrumentation/SanitizerCoverageLTO.so.cc
+++ b/instrumentation/SanitizerCoverageLTO.so.cc
@@ -1,4 +1,4 @@
-/* SanitizeCoverage.cpp ported to afl++ LTO :-) */
+/* SanitizeCoverage.cpp ported to AFL++ LTO :-) */
#define AFL_LLVM_PASS
@@ -17,8 +17,12 @@
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/Analysis/EHPersonalities.h"
+#if LLVM_VERSION_MAJOR < 17
+ #include "llvm/ADT/Triple.h"
+ #include "llvm/Analysis/EHPersonalities.h"
+#else
+ #include "llvm/IR/EHPersonalities.h"
+#endif
#include "llvm/Analysis/PostDominators.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/BasicBlock.h"
@@ -47,7 +51,9 @@
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Instrumentation.h"
-#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#if LLVM_VERSION_MAJOR < 17
+ #include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#endif
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
@@ -111,6 +117,12 @@ static cl::opt<bool> ClPruneBlocks(
cl::desc("Reduce the number of instrumented blocks"), cl::Hidden,
cl::init(true));
+namespace llvm {
+
+void initializeModuleSanitizerCoverageLTOLegacyPassPass(PassRegistry &PB);
+
+}
+
namespace {
SanitizerCoverageOptions getOptions(int LegacyCoverageLevel) {
@@ -182,7 +194,7 @@ class ModuleSanitizerCoverageLTO
private:
void instrumentFunction(Function &F, DomTreeCallback DTCallback,
PostDomTreeCallback PDTCallback);
- void InjectCoverageForIndirectCalls(Function & F,
+ void InjectCoverageForIndirectCalls(Function &F,
ArrayRef<Instruction *> IndirCalls);
bool InjectCoverage(Function &F, ArrayRef<BasicBlock *> AllBlocks,
bool IsLeafFunc = true);
@@ -211,10 +223,10 @@ class ModuleSanitizerCoverageLTO
FunctionCallee SanCovTracePC /*, SanCovTracePCGuard*/;
Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy, *Int32Ty, *Int32PtrTy,
*Int16Ty, *Int8Ty, *Int8PtrTy, *Int1Ty, *Int1PtrTy;
- Module * CurModule;
+ Module *CurModule;
std::string CurModuleUniqueId;
Triple TargetTriple;
- LLVMContext * C;
+ LLVMContext *C;
const DataLayout *DL;
GlobalVariable *FunctionGuardArray; // for trace-pc-guard.
@@ -226,42 +238,43 @@ class ModuleSanitizerCoverageLTO
SanitizerCoverageOptions Options;
- // afl++ START
+ // AFL++ START
// const SpecialCaseList * Allowlist;
// const SpecialCaseList * Blocklist;
uint32_t autodictionary = 1;
+ uint32_t autodictionary_no_main = 0;
uint32_t inst = 0;
uint32_t afl_global_id = 0;
uint32_t unhandled = 0;
uint32_t select_cnt = 0;
uint64_t map_addr = 0;
- const char * skip_nozero = NULL;
- const char * use_threadsafe_counters = nullptr;
+ const char *skip_nozero = NULL;
+ const char *use_threadsafe_counters = nullptr;
std::vector<BasicBlock *> BlockList;
DenseMap<Value *, std::string *> valueMap;
std::vector<std::string> dictionary;
- IntegerType * Int8Tyi = NULL;
- IntegerType * Int32Tyi = NULL;
- IntegerType * Int64Tyi = NULL;
- ConstantInt * Zero = NULL;
- ConstantInt * One = NULL;
- LLVMContext * Ct = NULL;
- Module * Mo = NULL;
- GlobalVariable * AFLMapPtr = NULL;
- Value * MapPtrFixed = NULL;
+ IntegerType *Int8Tyi = NULL;
+ IntegerType *Int32Tyi = NULL;
+ IntegerType *Int64Tyi = NULL;
+ ConstantInt *Zero = NULL;
+ ConstantInt *One = NULL;
+ LLVMContext *Ct = NULL;
+ Module *Mo = NULL;
+ GlobalVariable *AFLMapPtr = NULL;
+ Value *MapPtrFixed = NULL;
std::ofstream dFile;
size_t found = 0;
- // afl++ END
+ // AFL++ END
};
-class ModuleSanitizerCoverageLegacyPass : public ModulePass {
+class ModuleSanitizerCoverageLTOLegacyPass : public ModulePass {
public:
static char ID;
StringRef getPassName() const override {
- return "sancov";
+ return "sancov-lto";
}
@@ -272,11 +285,11 @@ class ModuleSanitizerCoverageLegacyPass : public ModulePass {
}
- ModuleSanitizerCoverageLegacyPass(
+ ModuleSanitizerCoverageLTOLegacyPass(
const SanitizerCoverageOptions &Options = SanitizerCoverageOptions())
: ModulePass(ID), Options(Options) {
- initializeModuleSanitizerCoverageLegacyPassPass(
+ initializeModuleSanitizerCoverageLTOLegacyPassPass(
*PassRegistry::getPassRegistry());
}
@@ -318,8 +331,11 @@ llvmGetPassPluginInfo() {
#if LLVM_VERSION_MAJOR <= 13
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
#endif
- // PB.registerFullLinkTimeOptimizationLastEPCallback(
+#if LLVM_VERSION_MAJOR >= 16
+ PB.registerFullLinkTimeOptimizationLastEPCallback(
+#else
PB.registerOptimizerLastEPCallback(
+#endif
[](ModulePassManager &MPM, OptimizationLevel OL) {
MPM.addPass(ModuleSanitizerCoverageLTO());
@@ -330,12 +346,12 @@ llvmGetPassPluginInfo() {
}
-PreservedAnalyses ModuleSanitizerCoverageLTO::run(Module & M,
+PreservedAnalyses ModuleSanitizerCoverageLTO::run(Module &M,
ModuleAnalysisManager &MAM) {
ModuleSanitizerCoverageLTO ModuleSancov(Options);
auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
- auto DTCallback = [&FAM](Function &F) -> const DominatorTree * {
+ auto DTCallback = [&FAM](Function &F) -> const DominatorTree *{
return &FAM.getResult<DominatorTreeAnalysis>(F);
@@ -380,7 +396,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
FunctionPCsArray = nullptr;
IntptrTy = Type::getIntNTy(*C, DL->getPointerSizeInBits());
IntptrPtrTy = PointerType::getUnqual(IntptrTy);
- Type * VoidTy = Type::getVoidTy(*C);
+ Type *VoidTy = Type::getVoidTy(*C);
IRBuilder<> IRB(*C);
Int64PtrTy = PointerType::getUnqual(IRB.getInt64Ty());
Int32PtrTy = PointerType::getUnqual(IRB.getInt32Ty());
@@ -392,8 +408,8 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
Int8Ty = IRB.getInt8Ty();
Int1Ty = IRB.getInt1Ty();
- /* afl++ START */
- char * ptr;
+ /* AFL++ START */
+ char *ptr;
LLVMContext &Ctx = M.getContext();
Ct = &Ctx;
Int8Tyi = IntegerType::getInt8Ty(Ctx);
@@ -402,7 +418,8 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
/* Show a banner */
setvbuf(stdout, NULL, _IONBF, 0);
- if (getenv("AFL_DEBUG")) debug = 1;
+ if (getenv("AFL_DEBUG")) { debug = 1; }
+ if (getenv("AFL_LLVM_DICT2FILE_NO_MAIN")) { autodictionary_no_main = 1; }
if ((isatty(2) && !getenv("AFL_QUIET")) || debug) {
@@ -420,6 +437,8 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
if ((afl_global_id = atoi(ptr)) < 0)
FATAL("AFL_LLVM_LTO_STARTID value of \"%s\" is negative\n", ptr);
+ if (afl_global_id < 4) { afl_global_id = 4; }
+
if ((ptr = getenv("AFL_LLVM_DOCUMENT_IDS")) != NULL) {
dFile.open(ptr, std::ofstream::out | std::ofstream::app);
@@ -494,16 +513,23 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
if (!isInInstrumentList(&F, MNAME) || !F.size()) { continue; }
+ if (autodictionary_no_main &&
+ (!F.getName().compare("main") || !F.getName().compare("_main"))) {
+
+ continue;
+
+ }
+
for (auto &BB : F) {
for (auto &IN : BB) {
CallInst *callInst = nullptr;
- CmpInst * cmpInst = nullptr;
+ CmpInst *cmpInst = nullptr;
if ((cmpInst = dyn_cast<CmpInst>(&IN))) {
- Value * op = cmpInst->getOperand(1);
+ Value *op = cmpInst->getOperand(1);
ConstantInt *ilen = dyn_cast<ConstantInt>(op);
if (ilen && ilen->uge(0xffffffffffffffff) == false) {
@@ -759,7 +785,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
if (HasStr2 == true) {
- Value * op2 = callInst->getArgOperand(2);
+ Value *op2 = callInst->getArgOperand(2);
ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
if (ilen) {
@@ -866,7 +892,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
if (isMemcmp || isStrncmp || isStrncasecmp) {
- Value * op2 = callInst->getArgOperand(2);
+ Value *op2 = callInst->getArgOperand(2);
ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
if (ilen) {
@@ -921,7 +947,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
std::string outstring;
fprintf(stderr, "%s: length %zu/%zu \"", FuncName.c_str(), optLen,
thestring.length());
- for (uint8_t i = 0; i < thestring.length(); i++) {
+ for (uint16_t i = 0; i < (uint16_t)thestring.length(); i++) {
uint8_t c = thestring[i];
if (c <= 32 || c >= 127)
@@ -956,7 +982,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
}
- // afl++ END
+ // AFL++ END
SanCovTracePCIndir =
M.getOrInsertFunction(SanCovTracePCIndirName, VoidTy, IntptrTy);
@@ -980,10 +1006,11 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
for (auto &F : M)
instrumentFunction(F, DTCallback, PDTCallback);
- // afl++ START
+ // AFL++ START
if (dFile.is_open()) dFile.close();
- if (!getenv("AFL_LLVM_LTO_DONTWRITEID") || dictionary.size() || map_addr) {
+ if (!getenv("AFL_LLVM_LTO_SKIPINIT") &&
+ (!getenv("AFL_LLVM_LTO_DONTWRITEID") || dictionary.size() || map_addr)) {
// yes we could create our own function, insert it into ctors ...
// but this would be a pain in the butt ... so we use afl-llvm-rt-lto.o
@@ -1017,7 +1044,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
GlobalVariable *AFLMapAddrFixed = new GlobalVariable(
M, Int64Tyi, true, GlobalValue::ExternalLinkage, 0, "__afl_map_addr");
ConstantInt *MapAddr = ConstantInt::get(Int64Tyi, map_addr);
- StoreInst * StoreMapAddr = IRB.CreateStore(MapAddr, AFLMapAddrFixed);
+ StoreInst *StoreMapAddr = IRB.CreateStore(MapAddr, AFLMapAddrFixed);
ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(StoreMapAddr);
}
@@ -1032,7 +1059,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
new GlobalVariable(M, Int32Tyi, true, GlobalValue::ExternalLinkage, 0,
"__afl_final_loc");
ConstantInt *const_loc = ConstantInt::get(Int32Tyi, write_loc);
- StoreInst * StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc);
+ StoreInst *StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc);
ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(StoreFinalLoc);
}
@@ -1133,7 +1160,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
}
- // afl++ END
+ // AFL++ END
// We don't reference these arrays directly in any of our runtime functions,
// so we need to prevent them from being dead stripped.
@@ -1159,7 +1186,7 @@ static bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) {
}
// True if block has predecessors and it postdominates all of them.
-static bool isFullPostDominator(const BasicBlock * BB,
+static bool isFullPostDominator(const BasicBlock *BB,
const PostDominatorTree *PDT) {
if (pred_begin(BB) == pred_end(BB)) return false;
@@ -1175,8 +1202,8 @@ static bool isFullPostDominator(const BasicBlock * BB,
}
static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
- const DominatorTree * DT,
- const PostDominatorTree * PDT,
+ const DominatorTree *DT,
+ const PostDominatorTree *PDT,
const SanitizerCoverageOptions &Options) {
// Don't insert coverage for blocks containing nothing but unreachable: we
@@ -1190,10 +1217,10 @@ static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
// (catchswitch blocks).
if (BB->getFirstInsertionPt() == BB->end()) return false;
- // afl++ START
+ // AFL++ START
if (!Options.NoPrune && &F.getEntryBlock() == BB && F.size() > 1)
return false;
- // afl++ END
+ // AFL++ END
if (Options.NoPrune || &F.getEntryBlock() == BB) return true;
@@ -1235,10 +1262,10 @@ void ModuleSanitizerCoverageLTO::instrumentFunction(
// if (Blocklist && Blocklist->inSection("coverage", "fun", F.getName()))
// return;
- // afl++ START
+ // AFL++ START
if (!F.size()) return;
if (!isInInstrumentList(&F, FMNAME)) return;
- // afl++ END
+ // AFL++ END
if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge)
SplitAllCriticalEdges(
@@ -1246,7 +1273,7 @@ void ModuleSanitizerCoverageLTO::instrumentFunction(
SmallVector<Instruction *, 8> IndirCalls;
SmallVector<BasicBlock *, 16> BlocksToInstrument;
- const DominatorTree * DT = DTCallback(F);
+ const DominatorTree *DT = DTCallback(F);
const PostDominatorTree *PDT = PDTCallback(F);
bool IsLeafFunc = true;
uint32_t skip_next = 0;
@@ -1294,8 +1321,8 @@ void ModuleSanitizerCoverageLTO::instrumentFunction(
if (!skip_next && (selectInst = dyn_cast<SelectInst>(&IN))) {
uint32_t vector_cnt = 0;
- Value * condition = selectInst->getCondition();
- Value * result;
+ Value *condition = selectInst->getCondition();
+ Value *result;
auto t = condition->getType();
IRBuilder<> IRB(selectInst->getNextNode());
@@ -1536,7 +1563,7 @@ bool ModuleSanitizerCoverageLTO::InjectCoverage(
for (size_t i = 0, N = AllBlocks.size(); i < N; i++) {
- // afl++ START
+ // AFL++ START
if (BlockList.size()) {
int skip = 0;
@@ -1558,7 +1585,7 @@ bool ModuleSanitizerCoverageLTO::InjectCoverage(
}
- // afl++ END
+ // AFL++ END
InjectCoverageAtBlock(F, *AllBlocks[i], i, IsLeafFunc);
@@ -1584,8 +1611,8 @@ void ModuleSanitizerCoverageLTO::InjectCoverageForIndirectCalls(
for (auto I : IndirCalls) {
IRBuilder<> IRB(I);
- CallBase & CB = cast<CallBase>(*I);
- Value * Callee = CB.getCalledOperand();
+ CallBase &CB = cast<CallBase>(*I);
+ Value *Callee = CB.getCalledOperand();
if (isa<InlineAsm>(Callee)) continue;
IRB.CreateCall(SanCovTracePCIndir, IRB.CreatePointerCast(Callee, IntptrTy));
@@ -1593,7 +1620,7 @@ void ModuleSanitizerCoverageLTO::InjectCoverageForIndirectCalls(
}
-void ModuleSanitizerCoverageLTO::InjectCoverageAtBlock(Function & F,
+void ModuleSanitizerCoverageLTO::InjectCoverageAtBlock(Function &F,
BasicBlock &BB,
size_t Idx,
bool IsLeafFunc) {
@@ -1624,7 +1651,7 @@ void ModuleSanitizerCoverageLTO::InjectCoverageAtBlock(Function & F,
if (Options.TracePCGuard) {
- // afl++ START
+ // AFL++ START
++afl_global_id;
if (dFile.is_open()) {
@@ -1688,7 +1715,7 @@ void ModuleSanitizerCoverageLTO::InjectCoverageAtBlock(Function & F,
// done :)
inst++;
- // afl++ END
+ // AFL++ END
/*
XXXXXXXXXXXXXXXXXXX
@@ -1750,30 +1777,22 @@ std::string ModuleSanitizerCoverageLTO::getSectionName(
}
-char ModuleSanitizerCoverageLegacyPass::ID = 0;
+char ModuleSanitizerCoverageLTOLegacyPass::ID = 0;
-INITIALIZE_PASS_BEGIN(ModuleSanitizerCoverageLegacyPass, "sancov",
+INITIALIZE_PASS_BEGIN(ModuleSanitizerCoverageLTOLegacyPass, "sancov-lto",
"Pass for instrumenting coverage on functions", false,
false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass)
-INITIALIZE_PASS_END(ModuleSanitizerCoverageLegacyPass, "sancov",
+INITIALIZE_PASS_END(ModuleSanitizerCoverageLTOLegacyPass, "sancov-lto",
"Pass for instrumenting coverage on functions", false,
false)
-ModulePass *llvm::createModuleSanitizerCoverageLegacyPassPass(
- const SanitizerCoverageOptions &Options,
- const std::vector<std::string> &AllowlistFiles,
- const std::vector<std::string> &BlocklistFiles) {
-
- return new ModuleSanitizerCoverageLegacyPass(Options);
-
-}
-
+#if LLVM_VERSION_MAJOR < 16
static void registerLTOPass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) {
- auto p = new ModuleSanitizerCoverageLegacyPass();
+ auto p = new ModuleSanitizerCoverageLTOLegacyPass();
PM.add(p);
}
@@ -1784,8 +1803,9 @@ static RegisterStandardPasses RegisterCompTransPass(
static RegisterStandardPasses RegisterCompTransPass0(
PassManagerBuilder::EP_EnabledOnOptLevel0, registerLTOPass);
-#if LLVM_VERSION_MAJOR >= 11
+ #if LLVM_VERSION_MAJOR >= 11
static RegisterStandardPasses RegisterCompTransPassLTO(
PassManagerBuilder::EP_FullLinkTimeOptimizationLast, registerLTOPass);
+ #endif
#endif
diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc
index 408353b3..7171e7aa 100644
--- a/instrumentation/SanitizerCoveragePCGUARD.so.cc
+++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc
@@ -13,38 +13,63 @@
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/Analysis/EHPersonalities.h"
+#if LLVM_VERSION_MAJOR >= 15
+ #if LLVM_VERSION_MAJOR < 17
+ #include "llvm/ADT/Triple.h"
+ #endif
+#endif
#include "llvm/Analysis/PostDominators.h"
-#include "llvm/IR/CFG.h"
+#if LLVM_VERSION_MAJOR < 15
+ #include "llvm/IR/CFG.h"
+#endif
#include "llvm/IR/Constant.h"
#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/DebugInfo.h"
+#if LLVM_VERSION_MAJOR < 15
+ #include "llvm/IR/DebugInfo.h"
+#endif
#include "llvm/IR/Dominators.h"
+#if LLVM_VERSION_MAJOR >= 17
+ #include "llvm/IR/EHPersonalities.h"
+#else
+ #include "llvm/Analysis/EHPersonalities.h"
+#endif
#include "llvm/IR/Function.h"
-#include "llvm/IR/GlobalVariable.h"
+#if LLVM_VERSION_MAJOR >= 16
+ #include "llvm/IR/GlobalVariable.h"
+#endif
#include "llvm/IR/IRBuilder.h"
-#include "llvm/IR/InlineAsm.h"
+#if LLVM_VERSION_MAJOR < 15
+ #include "llvm/IR/InlineAsm.h"
+#endif
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/MDBuilder.h"
-#include "llvm/IR/Mangler.h"
+#if LLVM_VERSION_MAJOR < 15
+ #include "llvm/IR/MDBuilder.h"
+ #include "llvm/IR/Mangler.h"
+#endif
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
+#include "llvm/Passes/PassBuilder.h"
+#include "llvm/Passes/PassPlugin.h"
#include "llvm/IR/Type.h"
-#include "llvm/InitializePasses.h"
+#if LLVM_VERSION_MAJOR < 17
+ #include "llvm/InitializePasses.h"
+#endif
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/SpecialCaseList.h"
#include "llvm/Support/VirtualFileSystem.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Transforms/Instrumentation.h"
+#if LLVM_VERSION_MAJOR < 15
+ #include "llvm/Support/raw_ostream.h"
+#endif
+#if LLVM_VERSION_MAJOR < 17
+ #include "llvm/Transforms/Instrumentation.h"
+#else
+ #include "llvm/TargetParser/Triple.h"
+#endif
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
-#include "llvm/Passes/PassPlugin.h"
-#include "llvm/Passes/PassBuilder.h"
-#include "llvm/IR/PassManager.h"
#include "config.h"
#include "debug.h"
@@ -54,7 +79,8 @@ using namespace llvm;
#define DEBUG_TYPE "sancov"
-const char SanCovTracePCIndirName[] = "__sanitizer_cov_trace_pc_indir";
+static const uint64_t SanCtorAndDtorPriority = 2;
+
const char SanCovTracePCName[] = "__sanitizer_cov_trace_pc";
const char SanCovTraceCmp1[] = "__sanitizer_cov_trace_cmp1";
const char SanCovTraceCmp2[] = "__sanitizer_cov_trace_cmp2";
@@ -64,22 +90,13 @@ const char SanCovTraceConstCmp1[] = "__sanitizer_cov_trace_const_cmp1";
const char SanCovTraceConstCmp2[] = "__sanitizer_cov_trace_const_cmp2";
const char SanCovTraceConstCmp4[] = "__sanitizer_cov_trace_const_cmp4";
const char SanCovTraceConstCmp8[] = "__sanitizer_cov_trace_const_cmp8";
-const char SanCovTraceDiv4[] = "__sanitizer_cov_trace_div4";
-const char SanCovTraceDiv8[] = "__sanitizer_cov_trace_div8";
-const char SanCovTraceGep[] = "__sanitizer_cov_trace_gep";
const char SanCovTraceSwitchName[] = "__sanitizer_cov_trace_switch";
+
const char SanCovModuleCtorTracePcGuardName[] =
"sancov.module_ctor_trace_pc_guard";
-const char SanCovModuleCtor8bitCountersName[] =
- "sancov.module_ctor_8bit_counters";
-const char SanCovModuleCtorBoolFlagName[] = "sancov.module_ctor_bool_flag";
-static const uint64_t SanCtorAndDtorPriority = 2;
+const char SanCovTracePCGuardInitName[] = "__sanitizer_cov_trace_pc_guard_init";
const char SanCovTracePCGuardName[] = "__sanitizer_cov_trace_pc_guard";
-const char SanCovTracePCGuardInitName[] = "__sanitizer_cov_trace_pc_guard_init";
-const char SanCov8bitCountersInitName[] = "__sanitizer_cov_8bit_counters_init";
-const char SanCovBoolFlagInitName[] = "__sanitizer_cov_bool_flag_init";
-const char SanCovPCsInitName[] = "__sanitizer_cov_pcs_init";
const char SanCovGuardsSectionName[] = "sancov_guards";
const char SanCovCountersSectionName[] = "sancov_cntrs";
@@ -95,27 +112,9 @@ namespace {
SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) {
- // Sets CoverageType and IndirectCalls.
- // SanitizerCoverageOptions CLOpts = getOptions(ClCoverageLevel);
- Options.CoverageType =
- SanitizerCoverageOptions::SCK_Edge; // std::max(Options.CoverageType,
- // CLOpts.CoverageType);
- Options.IndirectCalls = false; // CLOpts.IndirectCalls;
- Options.TraceCmp = false; //|= ClCMPTracing;
- Options.TraceDiv = false; //|= ClDIVTracing;
- Options.TraceGep = false; //|= ClGEPTracing;
- Options.TracePC = false; //|= ClTracePC;
- Options.TracePCGuard = true; // |= ClTracePCGuard;
- Options.Inline8bitCounters = 0; //|= ClInline8bitCounters;
- // Options.InlineBoolFlag = 0; //|= ClInlineBoolFlag;
- Options.PCTable = false; //|= ClCreatePCTable;
- Options.NoPrune = false; //|= !ClPruneBlocks;
- Options.StackDepth = false; //|= ClStackDepth;
- if (!Options.TracePCGuard && !Options.TracePC &&
- !Options.Inline8bitCounters && !Options.StackDepth /*&&
- !Options.InlineBoolFlag*/)
- Options.TracePCGuard = true; // TracePCGuard is default.
-
+ Options.CoverageType = SanitizerCoverageOptions::SCK_Edge;
+ // Options.NoPrune = true;
+ Options.TracePCGuard = true; // TracePCGuard is default.
return Options;
}
@@ -135,21 +134,14 @@ class ModuleSanitizerCoverageAFL
}
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
-
- bool instrumentModule(Module &M, DomTreeCallback DTCallback,
- PostDomTreeCallback PDTCallback);
+ bool instrumentModule(Module &M, DomTreeCallback DTCallback,
+ PostDomTreeCallback PDTCallback);
private:
void instrumentFunction(Function &F, DomTreeCallback DTCallback,
PostDomTreeCallback PDTCallback);
- void InjectCoverageForIndirectCalls(Function & F,
- ArrayRef<Instruction *> IndirCalls);
void InjectTraceForCmp(Function &F, ArrayRef<Instruction *> CmpTraceTargets);
- void InjectTraceForDiv(Function & F,
- ArrayRef<BinaryOperator *> DivTraceTargets);
- void InjectTraceForGep(Function & F,
- ArrayRef<GetElementPtrInst *> GepTraceTargets);
- void InjectTraceForSwitch(Function & F,
+ void InjectTraceForSwitch(Function &F,
ArrayRef<Instruction *> SwitchTraceTargets);
bool InjectCoverage(Function &F, ArrayRef<BasicBlock *> AllBlocks,
bool IsLeafFunc = true);
@@ -169,28 +161,29 @@ class ModuleSanitizerCoverageAFL
void SetNoSanitizeMetadata(Instruction *I) {
+#if LLVM_VERSION_MAJOR >= 16
+ I->setMetadata(LLVMContext::MD_nosanitize, MDNode::get(*C, std::nullopt));
+#else
I->setMetadata(I->getModule()->getMDKindID("nosanitize"),
MDNode::get(*C, None));
+#endif
}
std::string getSectionName(const std::string &Section) const;
std::string getSectionStart(const std::string &Section) const;
std::string getSectionEnd(const std::string &Section) const;
- FunctionCallee SanCovTracePCIndir;
FunctionCallee SanCovTracePC, SanCovTracePCGuard;
FunctionCallee SanCovTraceCmpFunction[4];
FunctionCallee SanCovTraceConstCmpFunction[4];
- FunctionCallee SanCovTraceDivFunction[2];
- FunctionCallee SanCovTraceGepFunction;
FunctionCallee SanCovTraceSwitchFunction;
GlobalVariable *SanCovLowestStack;
Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy, *Int32Ty, *Int32PtrTy,
*Int16Ty, *Int8Ty, *Int8PtrTy, *Int1Ty, *Int1PtrTy;
- Module * CurModule;
+ Module *CurModule;
std::string CurModuleUniqueId;
Triple TargetTriple;
- LLVMContext * C;
+ LLVMContext *C;
const DataLayout *DL;
GlobalVariable *FunctionGuardArray; // for trace-pc-guard.
@@ -204,76 +197,23 @@ class ModuleSanitizerCoverageAFL
uint32_t instr = 0, selects = 0, unhandled = 0;
GlobalVariable *AFLMapPtr = NULL;
- ConstantInt * One = NULL;
- ConstantInt * Zero = NULL;
-
-};
-
-class ModuleSanitizerCoverageLegacyPass : public ModulePass {
-
- public:
- ModuleSanitizerCoverageLegacyPass(
- const SanitizerCoverageOptions &Options = SanitizerCoverageOptions())
- : ModulePass(ID), Options(Options) {
-
- initializeModuleSanitizerCoverageLegacyPassPass(
- *PassRegistry::getPassRegistry());
-
- }
-
- bool runOnModule(Module &M) override {
-
- ModuleSanitizerCoverageAFL ModuleSancov(Options);
- auto DTCallback = [this](Function &F) -> const DominatorTree * {
-
- return &this->getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
-
- };
-
- auto PDTCallback = [this](Function &F) -> const PostDominatorTree * {
-
- return &this->getAnalysis<PostDominatorTreeWrapperPass>(F)
- .getPostDomTree();
-
- };
-
- return ModuleSancov.instrumentModule(M, DTCallback, PDTCallback);
-
- }
-
- /*static*/ char ID; // Pass identification, replacement for typeid
- StringRef getPassName() const override {
-
- return "ModuleSanitizerCoverage";
-
- }
-
- void getAnalysisUsage(AnalysisUsage &AU) const override {
-
- AU.addRequired<DominatorTreeWrapperPass>();
- AU.addRequired<PostDominatorTreeWrapperPass>();
-
- }
-
- private:
- SanitizerCoverageOptions Options;
+ ConstantInt *One = NULL;
+ ConstantInt *Zero = NULL;
};
} // namespace
-#if 1
-
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
llvmGetPassPluginInfo() {
- return {LLVM_PLUGIN_API_VERSION, "SanitizerCoveragePCGUARD", "v0.1",
+ return {LLVM_PLUGIN_API_VERSION, "SanitizerCoveragePCGUARD", "v0.2",
/* 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) {
@@ -285,14 +225,49 @@ llvmGetPassPluginInfo() {
}
-#endif
+#if LLVM_VERSION_MAJOR == 1
+PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M,
+ ModuleAnalysisManager &MAM) {
+
+ ModuleSanitizerCoverageAFL ModuleSancov(Options);
+ auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
+ auto DTCallback = [&FAM](Function &F) -> const DominatorTree *{
+
+ return &FAM.getResult<DominatorTreeAnalysis>(F);
+
+ };
+
+ auto PDTCallback = [&FAM](Function &F) -> const PostDominatorTree * {
+
+ return &FAM.getResult<PostDominatorTreeAnalysis>(F);
+
+ };
-PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module & M,
+ if (!ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
+ return PreservedAnalyses::all();
+
+ PreservedAnalyses PA = PreservedAnalyses::none();
+ // GlobalsAA is considered stateless and does not get invalidated unless
+ // explicitly invalidated; PreservedAnalyses::none() is not enough. Sanitizers
+ // make changes that require GlobalsAA to be invalidated.
+ PA.abandon<GlobalsAA>();
+ return PA;
+
+}
+
+#else
+ #if LLVM_VERSION_MAJOR >= 16
+PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M,
+ ModuleAnalysisManager &MAM) {
+
+ #else
+PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M,
ModuleAnalysisManager &MAM) {
+ #endif
ModuleSanitizerCoverageAFL ModuleSancov(Options);
auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
- auto DTCallback = [&FAM](Function &F) -> const DominatorTree * {
+ auto DTCallback = [&FAM](Function &F) -> const DominatorTree * {
return &FAM.getResult<DominatorTreeAnalysis>(F);
@@ -310,28 +285,23 @@ PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module & M,
}
+#endif
+
std::pair<Value *, Value *> ModuleSanitizerCoverageAFL::CreateSecStartEnd(
Module &M, const char *Section, Type *Ty) {
- GlobalVariable *SecStart =
- new GlobalVariable(M,
-#if LLVM_VERSION_MAJOR >= 15
- Ty,
-#else
- Ty->getPointerElementType(),
-#endif
- false, GlobalVariable::ExternalWeakLinkage, nullptr,
- getSectionStart(Section));
+ // Use ExternalWeak so that if all sections are discarded due to section
+ // garbage collection, the linker will not report undefined symbol errors.
+ // Windows defines the start/stop symbols in compiler-rt so no need for
+ // ExternalWeak.
+ GlobalValue::LinkageTypes Linkage = TargetTriple.isOSBinFormatCOFF()
+ ? GlobalVariable::ExternalLinkage
+ : GlobalVariable::ExternalWeakLinkage;
+ GlobalVariable *SecStart = new GlobalVariable(M, Ty, false, Linkage, nullptr,
+ getSectionStart(Section));
SecStart->setVisibility(GlobalValue::HiddenVisibility);
- GlobalVariable *SecEnd =
- new GlobalVariable(M,
-#if LLVM_VERSION_MAJOR >= 15
- Ty,
-#else
- Ty->getPointerElementType(),
-#endif
- false, GlobalVariable::ExternalWeakLinkage, nullptr,
- getSectionEnd(Section));
+ GlobalVariable *SecEnd = new GlobalVariable(M, Ty, false, Linkage, nullptr,
+ getSectionEnd(Section));
SecEnd->setVisibility(GlobalValue::HiddenVisibility);
IRBuilder<> IRB(M.getContext());
if (!TargetTriple.isOSBinFormatCOFF())
@@ -342,7 +312,8 @@ std::pair<Value *, Value *> ModuleSanitizerCoverageAFL::CreateSecStartEnd(
auto SecStartI8Ptr = IRB.CreatePointerCast(SecStart, Int8PtrTy);
auto GEP = IRB.CreateGEP(Int8Ty, SecStartI8Ptr,
ConstantInt::get(IntptrTy, sizeof(uint64_t)));
- return std::make_pair(IRB.CreatePointerCast(GEP, Ty), SecEnd);
+ return std::make_pair(IRB.CreatePointerCast(GEP, PointerType::getUnqual(Ty)),
+ SecEnd);
}
@@ -354,8 +325,9 @@ Function *ModuleSanitizerCoverageAFL::CreateInitCallsForSections(
auto SecStart = SecStartEnd.first;
auto SecEnd = SecStartEnd.second;
Function *CtorFunc;
+ Type *PtrTy = PointerType::getUnqual(Ty);
std::tie(CtorFunc, std::ignore) = createSanitizerCtorAndInitFunctions(
- M, CtorName, InitFunctionName, {Ty, Ty}, {SecStart, SecEnd});
+ M, CtorName, InitFunctionName, {PtrTy, PtrTy}, {SecStart, SecEnd});
assert(CtorFunc->getName() == CtorName);
if (TargetTriple.supportsCOMDAT()) {
@@ -379,7 +351,6 @@ Function *ModuleSanitizerCoverageAFL::CreateInitCallsForSections(
// to include the sancov constructor. This way the linker can deduplicate
// the constructors but always leave one copy.
CtorFunc->setLinkage(GlobalValue::WeakODRLinkage);
- appendToUsed(M, CtorFunc);
}
@@ -391,37 +362,25 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
Module &M, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) {
setvbuf(stdout, NULL, _IONBF, 0);
- if (getenv("AFL_DEBUG")) debug = 1;
+
+ if (getenv("AFL_DEBUG")) { debug = 1; }
if ((isatty(2) && !getenv("AFL_QUIET")) || debug) {
SAYF(cCYA "SanitizerCoveragePCGUARD" VERSION cRST "\n");
- } else
+ } else {
be_quiet = 1;
+ }
+
skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST");
initInstrumentList();
scanForDangerousFunctions(&M);
- if (debug) {
-
- fprintf(stderr,
- "SANCOV: covtype:%u indirect:%d stack:%d noprune:%d "
- "createtable:%d tracepcguard:%d tracepc:%d\n",
- Options.CoverageType, Options.IndirectCalls == true ? 1 : 0,
- Options.StackDepth == true ? 1 : 0, Options.NoPrune == true ? 1 : 0,
- // Options.InlineBoolFlag == true ? 1 : 0,
- Options.PCTable == true ? 1 : 0,
- Options.TracePCGuard == true ? 1 : 0,
- Options.TracePC == true ? 1 : 0);
-
- }
-
- if (Options.CoverageType == SanitizerCoverageOptions::SCK_None) return false;
C = &(M.getContext());
DL = &M.getDataLayout();
CurModule = &M;
@@ -433,7 +392,7 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
FunctionPCsArray = nullptr;
IntptrTy = Type::getIntNTy(*C, DL->getPointerSizeInBits());
IntptrPtrTy = PointerType::getUnqual(IntptrTy);
- Type * VoidTy = Type::getVoidTy(*C);
+ Type *VoidTy = Type::getVoidTy(*C);
IRBuilder<> IRB(*C);
Int64PtrTy = PointerType::getUnqual(IRB.getInt64Ty());
Int32PtrTy = PointerType::getUnqual(IRB.getInt32Ty());
@@ -444,16 +403,14 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
Int16Ty = IRB.getInt16Ty();
Int8Ty = IRB.getInt8Ty();
Int1Ty = IRB.getInt1Ty();
- LLVMContext &Ctx = M.getContext();
+ LLVMContext &Ctx = M.getContext();
AFLMapPtr =
new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,
GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
One = ConstantInt::get(IntegerType::getInt8Ty(Ctx), 1);
Zero = ConstantInt::get(IntegerType::getInt8Ty(Ctx), 0);
- SanCovTracePCIndir =
- M.getOrInsertFunction(SanCovTracePCIndirName, VoidTy, IntptrTy);
// Make sure smaller parameters are zero-extended to i64 if required by the
// target ABI.
AttributeList SanCovTraceCmpZeroExtAL;
@@ -483,26 +440,13 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
SanCovTraceConstCmpFunction[3] =
M.getOrInsertFunction(SanCovTraceConstCmp8, VoidTy, Int64Ty, Int64Ty);
- {
-
- AttributeList AL;
- AL = AL.addParamAttribute(*C, 0, Attribute::ZExt);
- SanCovTraceDivFunction[0] =
- M.getOrInsertFunction(SanCovTraceDiv4, AL, VoidTy, IRB.getInt32Ty());
-
- }
-
- SanCovTraceDivFunction[1] =
- M.getOrInsertFunction(SanCovTraceDiv8, VoidTy, Int64Ty);
- SanCovTraceGepFunction =
- M.getOrInsertFunction(SanCovTraceGep, VoidTy, IntptrTy);
SanCovTraceSwitchFunction =
M.getOrInsertFunction(SanCovTraceSwitchName, VoidTy, Int64Ty, Int64PtrTy);
Constant *SanCovLowestStackConstant =
M.getOrInsertGlobal(SanCovLowestStackName, IntptrTy);
SanCovLowestStack = dyn_cast<GlobalVariable>(SanCovLowestStackConstant);
- if (!SanCovLowestStack) {
+ if (!SanCovLowestStack || SanCovLowestStack->getValueType() != IntptrTy) {
C->emitError(StringRef("'") + SanCovLowestStackName +
"' should not be declared by the user");
@@ -512,8 +456,6 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
SanCovLowestStack->setThreadLocalMode(
GlobalValue::ThreadLocalMode::InitialExecTLSModel);
- if (Options.StackDepth && !SanCovLowestStack->isDeclaration())
- SanCovLowestStack->setInitializer(Constant::getAllOnesValue(IntptrTy));
SanCovTracePC = M.getOrInsertFunction(SanCovTracePCName, VoidTy);
SanCovTracePCGuard =
@@ -528,40 +470,25 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
Ctor = CreateInitCallsForSections(M, SanCovModuleCtorTracePcGuardName,
SanCovTracePCGuardInitName, Int32PtrTy,
SanCovGuardsSectionName);
- if (Function8bitCounterArray)
- Ctor = CreateInitCallsForSections(M, SanCovModuleCtor8bitCountersName,
- SanCov8bitCountersInitName, Int8PtrTy,
- SanCovCountersSectionName);
- if (FunctionBoolArray) {
-
- Ctor = CreateInitCallsForSections(M, SanCovModuleCtorBoolFlagName,
- SanCovBoolFlagInitName, Int1PtrTy,
- SanCovBoolFlagSectionName);
- }
+ if (Ctor && debug) {
- if (Ctor && Options.PCTable) {
-
- auto SecStartEnd = CreateSecStartEnd(M, SanCovPCsSectionName, IntptrPtrTy);
- FunctionCallee InitFunction = declareSanitizerInitFunction(
- M, SanCovPCsInitName, {IntptrPtrTy, IntptrPtrTy});
- IRBuilder<> IRBCtor(Ctor->getEntryBlock().getTerminator());
- IRBCtor.CreateCall(InitFunction, {SecStartEnd.first, SecStartEnd.second});
+ fprintf(stderr, "SANCOV: installed pcguard_init in ctor\n");
}
- // We don't reference these arrays directly in any of our runtime functions,
- // so we need to prevent them from being dead stripped.
- if (TargetTriple.isOSBinFormatMachO()) appendToUsed(M, GlobalsToAppendToUsed);
+ appendToUsed(M, GlobalsToAppendToUsed);
appendToCompilerUsed(M, GlobalsToAppendToCompilerUsed);
if (!be_quiet) {
- if (!instr)
+ if (!instr) {
+
WARNF("No instrumentation targets found.");
- else {
- char modeline[100];
+ } else {
+
+ char modeline[128];
snprintf(modeline, sizeof(modeline), "%s%s%s%s%s%s",
getenv("AFL_HARDEN") ? "hardened" : "non-hardened",
getenv("AFL_USE_ASAN") ? ", ASAN" : "",
@@ -582,39 +509,36 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
}
// True if block has successors and it dominates all of them.
-bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) {
-
- if (succ_begin(BB) == succ_end(BB)) return false;
+static bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) {
- for (const BasicBlock *SUCC : make_range(succ_begin(BB), succ_end(BB))) {
+ if (succ_empty(BB)) return false;
- if (!DT->dominates(BB, SUCC)) return false;
+ return llvm::all_of(successors(BB), [&](const BasicBlock *SUCC) {
- }
+ return DT->dominates(BB, SUCC);
- return true;
+ });
}
// True if block has predecessors and it postdominates all of them.
-bool isFullPostDominator(const BasicBlock *BB, const PostDominatorTree *PDT) {
-
- if (pred_begin(BB) == pred_end(BB)) return false;
+static bool isFullPostDominator(const BasicBlock *BB,
+ const PostDominatorTree *PDT) {
- for (const BasicBlock *PRED : make_range(pred_begin(BB), pred_end(BB))) {
+ if (pred_empty(BB)) return false;
- if (!PDT->dominates(BB, PRED)) return false;
+ return llvm::all_of(predecessors(BB), [&](const BasicBlock *PRED) {
- }
+ return PDT->dominates(BB, PRED);
- return true;
+ });
}
-bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
- const DominatorTree * DT,
- const PostDominatorTree * PDT,
- const SanitizerCoverageOptions &Options) {
+static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
+ const DominatorTree *DT,
+ const PostDominatorTree *PDT,
+ const SanitizerCoverageOptions &Options) {
// Don't insert coverage for blocks containing nothing but unreachable: we
// will never call __sanitizer_cov() for them, so counting them in
@@ -629,10 +553,6 @@ bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
if (Options.NoPrune || &F.getEntryBlock() == BB) return true;
- if (Options.CoverageType == SanitizerCoverageOptions::SCK_Function &&
- &F.getEntryBlock() != BB)
- return false;
-
// Do not instrument full dominators, or full post-dominators with multiple
// predecessors.
return !isFullDominator(BB, DT) &&
@@ -644,38 +564,47 @@ bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
// A twist here is that we treat From->To as a backedge if
// * To dominates From or
// * To->UniqueSuccessor dominates From
-bool IsBackEdge(BasicBlock *From, BasicBlock *To, const DominatorTree *DT) {
+#if 0
+static bool IsBackEdge(BasicBlock *From, BasicBlock *To,
+ const DominatorTree *DT) {
- if (DT->dominates(To, From)) return true;
+ if (DT->dominates(To, From))
+ return true;
if (auto Next = To->getUniqueSuccessor())
- if (DT->dominates(Next, From)) return true;
+ if (DT->dominates(Next, From))
+ return true;
return false;
}
+#endif
+
// Prunes uninteresting Cmp instrumentation:
// * CMP instructions that feed into loop backedge branch.
//
// Note that Cmp pruning is controlled by the same flag as the
// BB pruning.
-bool IsInterestingCmp(ICmpInst *CMP, const DominatorTree *DT,
- const SanitizerCoverageOptions &Options) {
+#if 0
+static bool IsInterestingCmp(ICmpInst *CMP, const DominatorTree *DT,
+ const SanitizerCoverageOptions &Options) {
if (!Options.NoPrune)
if (CMP->hasOneUse())
if (auto BR = dyn_cast<BranchInst>(CMP->user_back()))
for (BasicBlock *B : BR->successors())
- if (IsBackEdge(BR->getParent(), B, DT)) return false;
+ if (IsBackEdge(BR->getParent(), B, DT))
+ return false;
return true;
}
+#endif
+
void ModuleSanitizerCoverageAFL::instrumentFunction(
Function &F, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) {
if (F.empty()) return;
if (!isInInstrumentList(&F, FMNAME)) return;
-
if (F.getName().find(".module_ctor") != std::string::npos)
return; // Should not instrument sanitizer init functions.
if (F.getName().startswith("__sanitizer_"))
@@ -694,17 +623,15 @@ void ModuleSanitizerCoverageAFL::instrumentFunction(
if (F.hasPersonalityFn() &&
isAsynchronousEHPersonality(classifyEHPersonality(F.getPersonalityFn())))
return;
+ if (F.hasFnAttribute(Attribute::NoSanitizeCoverage)) return;
if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge)
SplitAllCriticalEdges(
F, CriticalEdgeSplittingOptions().setIgnoreUnreachableDests());
- SmallVector<Instruction *, 8> IndirCalls;
- SmallVector<BasicBlock *, 16> BlocksToInstrument;
- SmallVector<Instruction *, 8> CmpTraceTargets;
- SmallVector<Instruction *, 8> SwitchTraceTargets;
- SmallVector<BinaryOperator *, 8> DivTraceTargets;
- SmallVector<GetElementPtrInst *, 8> GepTraceTargets;
-
- const DominatorTree * DT = DTCallback(F);
+ SmallVector<BasicBlock *, 16> BlocksToInstrument;
+ SmallVector<Instruction *, 8> CmpTraceTargets;
+ SmallVector<Instruction *, 8> SwitchTraceTargets;
+
+ const DominatorTree *DT = DTCallback(F);
const PostDominatorTree *PDT = PDTCallback(F);
bool IsLeafFunc = true;
@@ -712,47 +639,28 @@ void ModuleSanitizerCoverageAFL::instrumentFunction(
if (shouldInstrumentBlock(F, &BB, DT, PDT, Options))
BlocksToInstrument.push_back(&BB);
- for (auto &Inst : BB) {
-
- if (Options.IndirectCalls) {
+ /*
+ for (auto &Inst : BB) {
- CallBase *CB = dyn_cast<CallBase>(&Inst);
- if (CB && !CB->getCalledFunction()) IndirCalls.push_back(&Inst);
-
- }
+ if (Options.TraceCmp) {
- if (Options.TraceCmp) {
+ if (ICmpInst *CMP = dyn_cast<ICmpInst>(&Inst))
+ if (IsInterestingCmp(CMP, DT, Options))
+ CmpTraceTargets.push_back(&Inst);
+ if (isa<SwitchInst>(&Inst))
+ SwitchTraceTargets.push_back(&Inst);
- if (ICmpInst *CMP = dyn_cast<ICmpInst>(&Inst))
- if (IsInterestingCmp(CMP, DT, Options))
- CmpTraceTargets.push_back(&Inst);
- if (isa<SwitchInst>(&Inst)) SwitchTraceTargets.push_back(&Inst);
-
- }
+ }
- if (Options.TraceDiv)
- if (BinaryOperator *BO = dyn_cast<BinaryOperator>(&Inst))
- if (BO->getOpcode() == Instruction::SDiv ||
- BO->getOpcode() == Instruction::UDiv)
- DivTraceTargets.push_back(BO);
- if (Options.TraceGep)
- if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(&Inst))
- GepTraceTargets.push_back(GEP);
- if (Options.StackDepth)
- if (isa<InvokeInst>(Inst) ||
- (isa<CallInst>(Inst) && !isa<IntrinsicInst>(Inst)))
- IsLeafFunc = false;
+ }
- }
+ */
}
InjectCoverage(F, BlocksToInstrument, IsLeafFunc);
- InjectCoverageForIndirectCalls(F, IndirCalls);
- InjectTraceForCmp(F, CmpTraceTargets);
- InjectTraceForSwitch(F, SwitchTraceTargets);
- InjectTraceForDiv(F, DivTraceTargets);
- InjectTraceForGep(F, GepTraceTargets);
+ // InjectTraceForCmp(F, CmpTraceTargets);
+ // InjectTraceForSwitch(F, SwitchTraceTargets);
}
@@ -764,29 +672,30 @@ GlobalVariable *ModuleSanitizerCoverageAFL::CreateFunctionLocalArrayInSection(
*CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage,
Constant::getNullValue(ArrayTy), "__sancov_gen_");
-#if LLVM_VERSION_MAJOR >= 13
if (TargetTriple.supportsCOMDAT() &&
(TargetTriple.isOSBinFormatELF() || !F.isInterposable()))
if (auto Comdat = getOrCreateFunctionComdat(F, TargetTriple))
Array->setComdat(Comdat);
-#else
- if (TargetTriple.supportsCOMDAT() && !F.isInterposable())
- if (auto Comdat =
- GetOrCreateFunctionComdat(F, TargetTriple, CurModuleUniqueId))
- Array->setComdat(Comdat);
-#endif
-
Array->setSection(getSectionName(Section));
-#if (LLVM_VERSION_MAJOR >= 11) || \
- (LLVM_VERSION_MAJOR == 10 && LLVM_VERSION_MINOR >= 1)
- Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedSize()));
+#if LLVM_VERSION_MAJOR >= 16
+ Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedValue()));
#else
- Array->setAlignment(Align(4)); // cheating
+ Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedSize()));
#endif
- GlobalsToAppendToUsed.push_back(Array);
- GlobalsToAppendToCompilerUsed.push_back(Array);
- MDNode *MD = MDNode::get(F.getContext(), ValueAsMetadata::get(&F));
- Array->addMetadata(LLVMContext::MD_associated, *MD);
+
+ // sancov_pcs parallels the other metadata section(s). Optimizers (e.g.
+ // GlobalOpt/ConstantMerge) may not discard sancov_pcs and the other
+ // section(s) as a unit, so we conservatively retain all unconditionally in
+ // the compiler.
+ //
+ // With comdat (COFF/ELF), the linker can guarantee the associated sections
+ // will be retained or discarded as a unit, so llvm.compiler.used is
+ // sufficient. Otherwise, conservatively make all of them retained by the
+ // linker.
+ if (Array->hasComdat())
+ GlobalsToAppendToCompilerUsed.push_back(Array);
+ else
+ GlobalsToAppendToUsed.push_back(Array);
return Array;
@@ -811,8 +720,12 @@ GlobalVariable *ModuleSanitizerCoverageAFL::CreatePCArray(
PCs.push_back((Constant *)IRB.CreatePointerCast(
BlockAddress::get(AllBlocks[i]), IntptrPtrTy));
+#if LLVM_VERSION_MAJOR >= 16
+ PCs.push_back(Constant::getNullValue(IntptrPtrTy));
+#else
PCs.push_back((Constant *)IRB.CreateIntToPtr(
ConstantInt::get(IntptrTy, 0), IntptrPtrTy));
+#endif
}
@@ -835,22 +748,15 @@ void ModuleSanitizerCoverageAFL::CreateFunctionLocalArrays(
FunctionGuardArray = CreateFunctionLocalArrayInSection(
AllBlocks.size() + special, F, Int32Ty, SanCovGuardsSectionName);
- if (Options.Inline8bitCounters)
- Function8bitCounterArray = CreateFunctionLocalArrayInSection(
- AllBlocks.size(), F, Int8Ty, SanCovCountersSectionName);
- /*
- if (Options.InlineBoolFlag)
- FunctionBoolArray = CreateFunctionLocalArrayInSection(
- AllBlocks.size(), F, Int1Ty, SanCovBoolFlagSectionName);
- */
- if (Options.PCTable) FunctionPCsArray = CreatePCArray(F, AllBlocks);
-
}
bool ModuleSanitizerCoverageAFL::InjectCoverage(
Function &F, ArrayRef<BasicBlock *> AllBlocks, bool IsLeafFunc) {
- uint32_t cnt_cov = 0, cnt_sel = 0, cnt_sel_inc = 0;
+ if (AllBlocks.empty()) return false;
+
+ uint32_t cnt_cov = 0, cnt_sel = 0, cnt_sel_inc = 0;
+ static uint32_t first = 1;
for (auto &BB : F) {
@@ -876,9 +782,11 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
}
- if (FuncName.compare(StringRef("__afl_coverage_interesting"))) continue;
+ if (!FuncName.compare(StringRef("__afl_coverage_interesting"))) {
- cnt_cov++;
+ cnt_cov++;
+
+ }
}
@@ -895,29 +803,27 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
}
-#if (LLVM_VERSION_MAJOR >= 12)
else if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
if (tt) {
cnt_sel++;
- cnt_sel_inc += tt->getElementCount().getKnownMinValue();
+ cnt_sel_inc += (tt->getElementCount().getKnownMinValue() * 2);
}
}
-#endif
-
}
}
}
- /* Create PCGUARD array */
- CreateFunctionLocalArrays(F, AllBlocks, cnt_cov + cnt_sel_inc);
+ CreateFunctionLocalArrays(F, AllBlocks, first + cnt_cov + cnt_sel_inc);
+
+ if (first) { first = 0; }
selects += cnt_sel;
uint32_t special = 0, local_selects = 0, skip_next = 0;
@@ -928,12 +834,6 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
CallInst *callInst = nullptr;
- /*
- std::string errMsg;
- raw_string_ostream os(errMsg);
- IN.print(os);
- fprintf(stderr, "X: %s\n", os.str().c_str());
- */
if ((callInst = dyn_cast<CallInst>(&IN))) {
Function *Callee = callInst->getCalledFunction();
@@ -971,8 +871,8 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
if (!skip_next && (selectInst = dyn_cast<SelectInst>(&IN))) {
uint32_t vector_cnt = 0;
- Value * condition = selectInst->getCondition();
- Value * result;
+ Value *condition = selectInst->getCondition();
+ Value *result;
auto t = condition->getType();
IRBuilder<> IRB(selectInst->getNextNode());
@@ -1072,12 +972,6 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
}
- /*
- std::string errMsg;
- raw_string_ostream os(errMsg);
- x->print(os);
- fprintf(stderr, "X: %s\n", os.str().c_str());
- */
result = IRB.CreateSelect(condition, x, y);
}
@@ -1102,18 +996,11 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr);
ModuleSanitizerCoverageAFL::SetNoSanitizeMetadata(MapPtr);
- /*
- std::string errMsg;
- raw_string_ostream os(errMsg);
- result->print(os);
- fprintf(stderr, "X: %s\n", os.str().c_str());
- */
-
while (1) {
/* Get CurLoc */
LoadInst *CurLoc = nullptr;
- Value * MapPtrIdx = nullptr;
+ Value *MapPtrIdx = nullptr;
/* Load counter for CurLoc */
if (!vector_cnt) {
@@ -1198,29 +1085,6 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
}
-// On every indirect call we call a run-time function
-// __sanitizer_cov_indir_call* with two parameters:
-// - callee address,
-// - global cache array that contains CacheSize pointers (zero-initialized).
-// The cache is used to speed up recording the caller-callee pairs.
-// The address of the caller is passed implicitly via caller PC.
-// CacheSize is encoded in the name of the run-time function.
-void ModuleSanitizerCoverageAFL::InjectCoverageForIndirectCalls(
- Function &F, ArrayRef<Instruction *> IndirCalls) {
-
- if (IndirCalls.empty()) return;
- for (auto I : IndirCalls) {
-
- IRBuilder<> IRB(I);
- CallBase & CB = cast<CallBase>(*I);
- Value * Callee = CB.getCalledOperand();
- if (isa<InlineAsm>(Callee)) continue;
- IRB.CreateCall(SanCovTracePCIndir, IRB.CreatePointerCast(Callee, IntptrTy));
-
- }
-
-}
-
// For every switch statement we insert a call:
// __sanitizer_cov_trace_switch(CondValue,
// {NumCases, ValueSizeInBits, Case0Value, Case1Value, Case2Value, ... })
@@ -1234,7 +1098,7 @@ void ModuleSanitizerCoverageAFL::InjectTraceForSwitch(
IRBuilder<> IRB(I);
SmallVector<Constant *, 16> Initializers;
- Value * Cond = SI->getCondition();
+ Value *Cond = SI->getCondition();
if (Cond->getType()->getScalarSizeInBits() >
Int64Ty->getScalarSizeInBits())
continue;
@@ -1276,41 +1140,6 @@ void ModuleSanitizerCoverageAFL::InjectTraceForSwitch(
}
-void ModuleSanitizerCoverageAFL::InjectTraceForDiv(
- Function &, ArrayRef<BinaryOperator *> DivTraceTargets) {
-
- for (auto BO : DivTraceTargets) {
-
- IRBuilder<> IRB(BO);
- Value * A1 = BO->getOperand(1);
- if (isa<ConstantInt>(A1)) continue;
- if (!A1->getType()->isIntegerTy()) continue;
- uint64_t TypeSize = DL->getTypeStoreSizeInBits(A1->getType());
- int CallbackIdx = TypeSize == 32 ? 0 : TypeSize == 64 ? 1 : -1;
- if (CallbackIdx < 0) continue;
- auto Ty = Type::getIntNTy(*C, TypeSize);
- IRB.CreateCall(SanCovTraceDivFunction[CallbackIdx],
- {IRB.CreateIntCast(A1, Ty, true)});
-
- }
-
-}
-
-void ModuleSanitizerCoverageAFL::InjectTraceForGep(
- Function &, ArrayRef<GetElementPtrInst *> GepTraceTargets) {
-
- for (auto GEP : GepTraceTargets) {
-
- IRBuilder<> IRB(GEP);
- for (Use &Idx : GEP->indices())
- if (!isa<ConstantInt>(Idx) && Idx->getType()->isIntegerTy())
- IRB.CreateCall(SanCovTraceGepFunction,
- {IRB.CreateIntCast(Idx, IntptrTy, true)});
-
- }
-
-}
-
void ModuleSanitizerCoverageAFL::InjectTraceForCmp(
Function &, ArrayRef<Instruction *> CmpTraceTargets) {
@@ -1319,8 +1148,8 @@ void ModuleSanitizerCoverageAFL::InjectTraceForCmp(
if (ICmpInst *ICMP = dyn_cast<ICmpInst>(I)) {
IRBuilder<> IRB(ICMP);
- Value * A0 = ICMP->getOperand(0);
- Value * A1 = ICMP->getOperand(1);
+ Value *A0 = ICMP->getOperand(0);
+ Value *A1 = ICMP->getOperand(1);
if (!A0->getType()->isIntegerTy()) continue;
uint64_t TypeSize = DL->getTypeStoreSizeInBits(A0->getType());
int CallbackIdx = TypeSize == 8 ? 0
@@ -1353,34 +1182,51 @@ void ModuleSanitizerCoverageAFL::InjectTraceForCmp(
}
-void ModuleSanitizerCoverageAFL::InjectCoverageAtBlock(Function & F,
+void ModuleSanitizerCoverageAFL::InjectCoverageAtBlock(Function &F,
BasicBlock &BB,
size_t Idx,
bool IsLeafFunc) {
BasicBlock::iterator IP = BB.getFirstInsertionPt();
bool IsEntryBB = &BB == &F.getEntryBlock();
+ DebugLoc EntryLoc;
if (IsEntryBB) {
- // Keep allocas and llvm.localescape calls in the entry block. Even
+ if (auto SP = F.getSubprogram())
+ EntryLoc = DILocation::get(SP->getContext(), SP->getScopeLine(), 0, SP);
+ // Keep static allocas and llvm.localescape calls in the entry block. Even
// if we aren't splitting the block, it's nice for allocas to be before
// calls.
IP = PrepareToSplitEntryBlock(BB, IP);
+#if LLVM_VERSION_MAJOR < 15
- }
-
- IRBuilder<> IRB(&*IP);
-
- if (Options.TracePC) {
+ } else {
- IRB.CreateCall(SanCovTracePC);
- // ->setCannotMerge(); // gets the PC using GET_CALLER_PC.
+ EntryLoc = IP->getDebugLoc();
+ if (!EntryLoc)
+ if (auto *SP = F.getSubprogram())
+ EntryLoc = DILocation::get(SP->getContext(), 0, 0, SP);
+#endif
}
+#if LLVM_VERSION_MAJOR >= 16
+ InstrumentationIRBuilder IRB(&*IP);
+#else
+ IRBuilder<> IRB(&*IP);
+#endif
+ if (EntryLoc) IRB.SetCurrentDebugLocation(EntryLoc);
if (Options.TracePCGuard) {
+ /*
+ auto GuardPtr = IRB.CreateIntToPtr(
+ IRB.CreateAdd(IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
+ ConstantInt::get(IntptrTy, Idx * 4)),
+ Int32PtrTy);
+ IRB.CreateCall(SanCovTracePCGuard, GuardPtr)->setCannotMerge();
+ */
+
/* Get CurLoc */
Value *GuardPtr = IRB.CreateIntToPtr(
@@ -1438,57 +1284,6 @@ void ModuleSanitizerCoverageAFL::InjectCoverageAtBlock(Function & F,
}
- if (Options.Inline8bitCounters) {
-
- auto CounterPtr = IRB.CreateGEP(
- Function8bitCounterArray->getValueType(), Function8bitCounterArray,
- {ConstantInt::get(IntptrTy, 0), ConstantInt::get(IntptrTy, Idx)});
- auto Load = IRB.CreateLoad(Int8Ty, CounterPtr);
- auto Inc = IRB.CreateAdd(Load, ConstantInt::get(Int8Ty, 1));
- auto Store = IRB.CreateStore(Inc, CounterPtr);
- SetNoSanitizeMetadata(Load);
- SetNoSanitizeMetadata(Store);
-
- }
-
- /*
- if (Options.InlineBoolFlag) {
-
- auto FlagPtr = IRB.CreateGEP(
- FunctionBoolArray->getValueType(), FunctionBoolArray,
- {ConstantInt::get(IntptrTy, 0), ConstantInt::get(IntptrTy, Idx)});
- auto Load = IRB.CreateLoad(Int1Ty, FlagPtr);
- auto ThenTerm =
- SplitBlockAndInsertIfThen(IRB.CreateIsNull(Load), &*IP, false);
- IRBuilder<> ThenIRB(ThenTerm);
- auto Store = ThenIRB.CreateStore(ConstantInt::getTrue(Int1Ty), FlagPtr);
- SetNoSanitizeMetadata(Load);
- SetNoSanitizeMetadata(Store);
-
- }
-
- */
-
- if (Options.StackDepth && IsEntryBB && !IsLeafFunc) {
-
- // Check stack depth. If it's the deepest so far, record it.
- Module * M = F.getParent();
- Function *GetFrameAddr = Intrinsic::getDeclaration(
- M, Intrinsic::frameaddress,
- IRB.getInt8PtrTy(M->getDataLayout().getAllocaAddrSpace()));
- auto FrameAddrPtr =
- IRB.CreateCall(GetFrameAddr, {Constant::getNullValue(Int32Ty)});
- auto FrameAddrInt = IRB.CreatePtrToInt(FrameAddrPtr, IntptrTy);
- auto LowestStack = IRB.CreateLoad(IntptrTy, SanCovLowestStack);
- auto IsStackLower = IRB.CreateICmpULT(FrameAddrInt, LowestStack);
- auto ThenTerm = SplitBlockAndInsertIfThen(IsStackLower, &*IP, false);
- IRBuilder<> ThenIRB(ThenTerm);
- auto Store = ThenIRB.CreateStore(FrameAddrInt, SanCovLowestStack);
- SetNoSanitizeMetadata(LowestStack);
- SetNoSanitizeMetadata(Store);
-
- }
-
}
std::string ModuleSanitizerCoverageAFL::getSectionName(
@@ -1526,26 +1321,3 @@ std::string ModuleSanitizerCoverageAFL::getSectionEnd(
}
-#if 0
-
-char ModuleSanitizerCoverageLegacyPass::ID = 0;
-INITIALIZE_PASS_BEGIN(ModuleSanitizerCoverageLegacyPass, "sancov",
- "Pass for instrumenting coverage on functions", false,
- false)
-INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
-INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass)
-INITIALIZE_PASS_END(ModuleSanitizerCoverageLegacyPass, "sancov",
- "Pass for instrumenting coverage on functions", false,
- false)
-ModulePass *llvm::createModuleSanitizerCoverageLegacyPassPass(
- const SanitizerCoverageOptions &Options,
- const std::vector<std::string> &AllowlistFiles,
- const std::vector<std::string> &BlocklistFiles) {
-
- return new ModuleSanitizerCoverageLegacyPass(Options, AllowlistFiles,
- BlocklistFiles);
-
-}
-
-#endif
-
diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c
index db7ac7b0..3f8b519b 100644
--- a/instrumentation/afl-compiler-rt.o.c
+++ b/instrumentation/afl-compiler-rt.o.c
@@ -3,7 +3,7 @@
------------------------------------------------
Copyright 2015, 2016 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -14,6 +14,16 @@
*/
+#ifdef __AFL_CODE_COVERAGE
+ #ifndef _GNU_SOURCE
+ #define _GNU_SOURCE
+ #endif
+ #ifndef __USE_GNU
+ #define __USE_GNU
+ #endif
+ #include <dlfcn.h>
+#endif
+
#ifdef __ANDROID__
#include "android-ashmem.h"
#endif
@@ -92,23 +102,66 @@ static u8 __afl_area_initial[MAP_INITIAL_SIZE];
static u8 *__afl_area_ptr_dummy = __afl_area_initial;
static u8 *__afl_area_ptr_backup = __afl_area_initial;
-u8 * __afl_area_ptr = __afl_area_initial;
-u8 * __afl_dictionary;
-u8 * __afl_fuzz_ptr;
+u8 *__afl_area_ptr = __afl_area_initial;
+u8 *__afl_dictionary;
+u8 *__afl_fuzz_ptr;
static u32 __afl_fuzz_len_dummy;
-u32 * __afl_fuzz_len = &__afl_fuzz_len_dummy;
+u32 *__afl_fuzz_len = &__afl_fuzz_len_dummy;
+int __afl_sharedmem_fuzzing __attribute__((weak));
u32 __afl_final_loc;
u32 __afl_map_size = MAP_SIZE;
u32 __afl_dictionary_len;
u64 __afl_map_addr;
+u32 __afl_first_final_loc;
+
+#ifdef __AFL_CODE_COVERAGE
+typedef struct afl_module_info_t afl_module_info_t;
+
+struct afl_module_info_t {
+
+ // A unique id starting with 0
+ u32 id;
+
+ // Name and base address of the module
+ char *name;
+ uintptr_t base_address;
+
+ // PC Guard start/stop
+ u32 start;
+ u32 stop;
+
+ // PC Table begin/end
+ const uintptr_t *pcs_beg;
+ const uintptr_t *pcs_end;
+
+ u8 mapped;
+
+ afl_module_info_t *next;
+
+};
+
+typedef struct {
+
+ uintptr_t PC, PCFlags;
+
+} PCTableEntry;
+
+afl_module_info_t *__afl_module_info = NULL;
+
+u32 __afl_pcmap_size = 0;
+uintptr_t *__afl_pcmap_ptr = NULL;
+#endif // __AFL_CODE_COVERAGE
+
+/* 1 if we are running in afl, and the forkserver was started, else 0 */
+u32 __afl_connected = 0;
// for the __AFL_COVERAGE_ON/__AFL_COVERAGE_OFF features to work:
int __afl_selective_coverage __attribute__((weak));
int __afl_selective_coverage_start_off __attribute__((weak));
static int __afl_selective_coverage_temp = 1;
-#if defined(__ANDROID__) || defined(__HAIKU__)
+#if defined(__ANDROID__) || defined(__HAIKU__) || defined(NO_TLS)
PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX];
PREV_LOC_T __afl_prev_caller[CTX_MAX_K];
u32 __afl_prev_ctx;
@@ -118,8 +171,6 @@ __thread PREV_LOC_T __afl_prev_caller[CTX_MAX_K];
__thread u32 __afl_prev_ctx;
#endif
-int __afl_sharedmem_fuzzing __attribute__((weak));
-
struct cmp_map *__afl_cmp_map;
struct cmp_map *__afl_cmp_map_backup;
@@ -146,6 +197,7 @@ u32 __afl_already_initialized_shm;
u32 __afl_already_initialized_forkserver;
u32 __afl_already_initialized_first;
u32 __afl_already_initialized_second;
+u32 __afl_already_initialized_early;
u32 __afl_already_initialized_init;
/* Dummy pipe for area_is_valid() */
@@ -159,6 +211,7 @@ static void at_exit(int signal) {
if (unlikely(child_pid > 0)) {
kill(child_pid, SIGKILL);
+ waitpid(child_pid, NULL, 0);
child_pid = -1;
}
@@ -288,11 +341,18 @@ static void __afl_map_shm(void) {
__afl_map_size = ++__afl_final_loc; // as we count starting 0
+ if (getenv("AFL_DUMP_MAP_SIZE")) {
+
+ printf("%u\n", __afl_map_size);
+ exit(-1);
+
+ }
+
if (__afl_final_loc > MAP_SIZE) {
char *ptr;
u32 val = 0;
- if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) val = atoi(ptr);
+ if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) { val = atoi(ptr); }
if (val < __afl_final_loc) {
if (__afl_final_loc > FS_OPT_MAX_MAPSIZE) {
@@ -312,19 +372,88 @@ static void __afl_map_shm(void) {
} else {
- if (!getenv("AFL_QUIET"))
+ if (__afl_final_loc > MAP_INITIAL_SIZE && !getenv("AFL_QUIET")) {
+
fprintf(stderr,
"Warning: AFL++ tools might need to set AFL_MAP_SIZE to %u "
"to be able to run this instrumented program if this "
"crashes!\n",
__afl_final_loc);
+ }
+
}
}
}
+ } else {
+
+ if (getenv("AFL_DUMP_MAP_SIZE")) {
+
+ printf("%u\n", MAP_SIZE);
+ exit(-1);
+
+ }
+
+ }
+
+ if (__afl_sharedmem_fuzzing && (!id_str || !getenv(SHM_FUZZ_ENV_VAR) ||
+ fcntl(FORKSRV_FD, F_GETFD) == -1 ||
+ fcntl(FORKSRV_FD + 1, F_GETFD) == -1)) {
+
+ if (__afl_debug) {
+
+ fprintf(stderr,
+ "DEBUG: running not inside afl-fuzz, disabling shared memory "
+ "testcases\n");
+
+ }
+
+ __afl_sharedmem_fuzzing = 0;
+
+ }
+
+ if (!id_str) {
+
+ u32 val = 0;
+ u8 *ptr;
+
+ if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) { val = atoi(ptr); }
+
+ if (val > MAP_INITIAL_SIZE) {
+
+ __afl_map_size = val;
+
+ } else {
+
+ if (__afl_first_final_loc > MAP_INITIAL_SIZE) {
+
+ // done in second stage constructor
+ __afl_map_size = __afl_first_final_loc;
+
+ } else {
+
+ __afl_map_size = MAP_INITIAL_SIZE;
+
+ }
+
+ }
+
+ if (__afl_map_size > MAP_INITIAL_SIZE && __afl_final_loc < __afl_map_size) {
+
+ __afl_final_loc = __afl_map_size;
+
+ }
+
+ if (__afl_debug) {
+
+ fprintf(stderr, "DEBUG: (0) init map size is %u to %p\n", __afl_map_size,
+ __afl_area_ptr_dummy);
+
+ }
+
}
/* If we're running under AFL, attach to the appropriate region, replacing the
@@ -364,7 +493,7 @@ static void __afl_map_shm(void) {
}
#ifdef USEMMAP
- const char * shm_file_path = id_str;
+ const char *shm_file_path = id_str;
int shm_fd = -1;
unsigned char *shm_base = NULL;
@@ -418,6 +547,7 @@ static void __afl_map_shm(void) {
u8 *map_env = (u8 *)getenv("AFL_MAP_SIZE");
if (!map_env || atoi((char *)map_env) < MAP_SIZE) {
+ fprintf(stderr, "FS_ERROR_MAP_SIZE\n");
send_forkserver_error(FS_ERROR_MAP_SIZE);
_exit(1);
@@ -465,20 +595,30 @@ static void __afl_map_shm(void) {
}
- } else if (_is_sancov && __afl_area_ptr != __afl_area_initial) {
+ } else if (__afl_final_loc > MAP_INITIAL_SIZE &&
- free(__afl_area_ptr);
- __afl_area_ptr = NULL;
+ __afl_final_loc > __afl_first_final_loc) {
- if (__afl_final_loc > MAP_INITIAL_SIZE) {
+ if (__afl_area_initial != __afl_area_ptr_dummy) {
- __afl_area_ptr = (u8 *)malloc(__afl_final_loc);
+ free(__afl_area_ptr_dummy);
}
- if (!__afl_area_ptr) { __afl_area_ptr = __afl_area_ptr_dummy; }
+ __afl_area_ptr_dummy = (u8 *)malloc(__afl_final_loc);
+ __afl_area_ptr = __afl_area_ptr_dummy;
+ __afl_map_size = __afl_final_loc;
- }
+ if (!__afl_area_ptr_dummy) {
+
+ fprintf(stderr,
+ "Error: AFL++ could not acquire %u bytes of memory, exiting!\n",
+ __afl_final_loc);
+ exit(-1);
+
+ }
+
+ } // else: nothing to be done
__afl_area_ptr_backup = __afl_area_ptr;
@@ -487,7 +627,7 @@ static void __afl_map_shm(void) {
fprintf(stderr,
"DEBUG: (2) id_str %s, __afl_area_ptr %p, __afl_area_initial %p, "
"__afl_area_ptr_dummy %p, __afl_map_addr 0x%llx, MAP_SIZE "
- "%u, __afl_final_loc %u, __afl_map_size %u,"
+ "%u, __afl_final_loc %u, __afl_map_size %u, "
"max_size_forkserver %u/0x%x\n",
id_str == NULL ? "<null>" : id_str, __afl_area_ptr,
__afl_area_initial, __afl_area_ptr_dummy, __afl_map_addr, MAP_SIZE,
@@ -540,7 +680,7 @@ static void __afl_map_shm(void) {
}
#ifdef USEMMAP
- const char * shm_file_path = id_str;
+ const char *shm_file_path = id_str;
int shm_fd = -1;
struct cmp_map *shm_base = NULL;
@@ -587,6 +727,27 @@ static void __afl_map_shm(void) {
}
+#ifdef __AFL_CODE_COVERAGE
+ char *pcmap_id_str = getenv("__AFL_PCMAP_SHM_ID");
+
+ if (pcmap_id_str) {
+
+ __afl_pcmap_size = __afl_map_size * sizeof(void *);
+ u32 shm_id = atoi(pcmap_id_str);
+
+ __afl_pcmap_ptr = (uintptr_t *)shmat(shm_id, NULL, 0);
+
+ if (__afl_debug) {
+
+ fprintf(stderr, "DEBUG: Received %p via shmat for pcmap\n",
+ __afl_pcmap_ptr);
+
+ }
+
+ }
+
+#endif // __AFL_CODE_COVERAGE
+
}
/* unmap SHM. */
@@ -595,6 +756,17 @@ static void __afl_unmap_shm(void) {
if (!__afl_already_initialized_shm) return;
+#ifdef __AFL_CODE_COVERAGE
+ if (__afl_pcmap_size) {
+
+ shmdt((void *)__afl_pcmap_ptr);
+ __afl_pcmap_ptr = NULL;
+ __afl_pcmap_size = 0;
+
+ }
+
+#endif // __AFL_CODE_COVERAGE
+
char *id_str = getenv(SHM_ENV_VAR);
if (id_str) {
@@ -646,7 +818,7 @@ static void __afl_unmap_shm(void) {
void write_error_with_location(char *text, char *filename, int linenumber) {
- u8 * o = getenv("__AFL_OUT_DIR");
+ u8 *o = getenv("__AFL_OUT_DIR");
char *e = strerror(errno);
if (o) {
@@ -686,10 +858,10 @@ static void __afl_start_snapshots(void) {
assume we're not running in forkserver mode and just execute program. */
status |= (FS_OPT_ENABLED | FS_OPT_SNAPSHOT | FS_OPT_NEWCMPLOG);
- if (__afl_sharedmem_fuzzing != 0) status |= FS_OPT_SHDMEM_FUZZ;
+ if (__afl_sharedmem_fuzzing) { status |= FS_OPT_SHDMEM_FUZZ; }
if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
- if (__afl_dictionary_len && __afl_dictionary) status |= FS_OPT_AUTODICT;
+ if (__afl_dictionary_len && __afl_dictionary) { status |= FS_OPT_AUTODICT; }
memcpy(tmp, &status, 4);
if (write(FORKSRV_FD + 1, tmp, 4) != 4) { return; }
@@ -950,7 +1122,7 @@ static void __afl_start_forkserver(void) {
}
- if (__afl_sharedmem_fuzzing != 0) { status_for_fsrv |= FS_OPT_SHDMEM_FUZZ; }
+ if (__afl_sharedmem_fuzzing) { status_for_fsrv |= FS_OPT_SHDMEM_FUZZ; }
if (status_for_fsrv) {
status_for_fsrv |= (FS_OPT_ENABLED | FS_OPT_NEWCMPLOG);
@@ -964,6 +1136,8 @@ static void __afl_start_forkserver(void) {
if (write(FORKSRV_FD + 1, tmp, 4) != 4) { return; }
+ __afl_connected = 1;
+
if (__afl_sharedmem_fuzzing || (__afl_dictionary_len && __afl_dictionary)) {
if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
@@ -1174,13 +1348,9 @@ int __afl_persistent_loop(unsigned int max_cnt) {
iteration, it's our job to erase any trace of whatever happened
before the loop. */
- if (is_persistent) {
-
- memset(__afl_area_ptr, 0, __afl_map_size);
- __afl_area_ptr[0] = 1;
- memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));
-
- }
+ memset(__afl_area_ptr, 0, __afl_map_size);
+ __afl_area_ptr[0] = 1;
+ memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));
cycle_cnt = max_cnt;
first_pass = 0;
@@ -1188,34 +1358,28 @@ int __afl_persistent_loop(unsigned int max_cnt) {
return 1;
- }
-
- if (is_persistent) {
-
- if (--cycle_cnt) {
+ } else if (--cycle_cnt) {
- raise(SIGSTOP);
+ raise(SIGSTOP);
- __afl_area_ptr[0] = 1;
- memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));
- __afl_selective_coverage_temp = 1;
+ __afl_area_ptr[0] = 1;
+ memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));
+ __afl_selective_coverage_temp = 1;
- return 1;
+ return 1;
- } else {
+ } else {
- /* When exiting __AFL_LOOP(), make sure that the subsequent code that
- follows the loop is not traced. We do that by pivoting back to the
- dummy output region. */
+ /* When exiting __AFL_LOOP(), make sure that the subsequent code that
+ follows the loop is not traced. We do that by pivoting back to the
+ dummy output region. */
- __afl_area_ptr = __afl_area_ptr_dummy;
+ __afl_area_ptr = __afl_area_ptr_dummy;
- }
+ return 0;
}
- return 0;
-
}
/* This one can be called from user code when deferred forkserver mode
@@ -1291,6 +1455,9 @@ __attribute__((constructor(EARLY_FS_PRIO))) void __early_forkserver(void) {
__attribute__((constructor(CTOR_PRIO))) void __afl_auto_early(void) {
+ if (__afl_already_initialized_early) return;
+ __afl_already_initialized_early = 1;
+
is_persistent = !!getenv(PERSIST_ENV_VAR);
if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
@@ -1316,21 +1483,24 @@ __attribute__((constructor(1))) void __afl_auto_second(void) {
if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
u8 *ptr;
- if (__afl_final_loc) {
+ if (__afl_final_loc > MAP_INITIAL_SIZE) {
+
+ __afl_first_final_loc = __afl_final_loc + 1;
if (__afl_area_ptr && __afl_area_ptr != __afl_area_initial)
free(__afl_area_ptr);
if (__afl_map_addr)
- ptr = (u8 *)mmap((void *)__afl_map_addr, __afl_final_loc,
+ ptr = (u8 *)mmap((void *)__afl_map_addr, __afl_first_final_loc,
PROT_READ | PROT_WRITE,
MAP_FIXED_NOREPLACE | MAP_SHARED | MAP_ANONYMOUS, -1, 0);
else
- ptr = (u8 *)malloc(__afl_final_loc);
+ ptr = (u8 *)malloc(__afl_first_final_loc);
if (ptr && (ssize_t)ptr != -1) {
__afl_area_ptr = ptr;
+ __afl_area_ptr_dummy = __afl_area_ptr;
__afl_area_ptr_backup = __afl_area_ptr;
}
@@ -1348,14 +1518,18 @@ __attribute__((constructor(0))) void __afl_auto_first(void) {
__afl_already_initialized_first = 1;
if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return;
- u8 *ptr = (u8 *)malloc(MAP_INITIAL_SIZE);
- if (ptr && (ssize_t)ptr != -1) {
+ /*
+ u8 *ptr = (u8 *)malloc(MAP_INITIAL_SIZE);
+
+ if (ptr && (ssize_t)ptr != -1) {
- __afl_area_ptr = ptr;
- __afl_area_ptr_backup = __afl_area_ptr;
+ __afl_area_ptr = ptr;
+ __afl_area_ptr_backup = __afl_area_ptr;
- }
+ }
+
+ */
} // ptr memleak report is a false positive
@@ -1414,6 +1588,102 @@ void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
}
+#ifdef __AFL_CODE_COVERAGE
+void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg,
+ const uintptr_t *pcs_end) {
+
+ if (__afl_debug) {
+
+ fprintf(stderr, "DEBUG: __sanitizer_cov_pcs_init called\n");
+
+ }
+
+ // If for whatever reason, we cannot get dlinfo here, then pc_guard_init also
+ // couldn't get it and we'd end up attributing to the wrong module.
+ Dl_info dlinfo;
+ if (!dladdr(__builtin_return_address(0), &dlinfo)) {
+
+ fprintf(stderr,
+ "WARNING: Ignoring __sanitizer_cov_pcs_init callback due to "
+ "missing module info\n");
+ return;
+
+ }
+
+ afl_module_info_t *last_module_info = __afl_module_info;
+ while (last_module_info && last_module_info->next) {
+
+ last_module_info = last_module_info->next;
+
+ }
+
+ if (!last_module_info) {
+
+ fprintf(stderr,
+ "ERROR: __sanitizer_cov_pcs_init called with no module info?!\n");
+ abort();
+
+ }
+
+ last_module_info->pcs_beg = pcs_beg;
+ last_module_info->pcs_end = pcs_end;
+
+ // Now update the pcmap. If this is the last module coming in, after all
+ // pre-loaded code, then this will also map all of our delayed previous
+ // modules.
+
+ if (!__afl_pcmap_ptr) { return; }
+
+ for (afl_module_info_t *mod_info = __afl_module_info; mod_info;
+ mod_info = mod_info->next) {
+
+ if (mod_info->mapped) { continue; }
+
+ PCTableEntry *start = (PCTableEntry *)(mod_info->pcs_beg);
+ PCTableEntry *end = (PCTableEntry *)(mod_info->pcs_end);
+
+ u32 in_module_index = 0;
+
+ while (start < end) {
+
+ if (mod_info->start + in_module_index >= __afl_map_size) {
+
+ fprintf(stderr, "ERROR: __sanitizer_cov_pcs_init out of bounds?!\n");
+ abort();
+
+ }
+
+ uintptr_t PC = start->PC;
+
+ // This is what `GetPreviousInstructionPc` in sanitizer runtime does
+ // for x86/x86-64. Needs more work for ARM and other archs.
+ PC = PC - 1;
+
+ // Calculate relative offset in module
+ PC = PC - mod_info->base_address;
+
+ __afl_pcmap_ptr[mod_info->start + in_module_index] = PC;
+
+ start++;
+ in_module_index++;
+
+ }
+
+ mod_info->mapped = 1;
+
+ if (__afl_debug) {
+
+ fprintf(stderr, "DEBUG: __sanitizer_cov_pcs_init initialized %u PCs\n",
+ in_module_index);
+
+ }
+
+ }
+
+}
+
+#endif // __AFL_CODE_COVERAGE
+
/* Init callback. Populates instrumentation IDs. Note that we're using
ID of 0 as a special value to indicate non-instrumented bits. That may
still touch the bitmap, but in a fairly harmless way. */
@@ -1425,6 +1695,14 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
_is_sancov = 1;
+ if (!getenv("AFL_DUMP_MAP_SIZE")) {
+
+ __afl_auto_first();
+ __afl_auto_second();
+ __afl_auto_early();
+
+ }
+
if (__afl_debug) {
fprintf(stderr,
@@ -1435,101 +1713,167 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
}
- if (start == stop || *start) return;
+ if (start == stop || *start) { return; }
- // If a dlopen of an instrumented library happens after the forkserver then
- // we have a problem as we cannot increase the coverage map anymore.
- if (__afl_already_initialized_forkserver) {
+#ifdef __AFL_CODE_COVERAGE
+ u32 *orig_start = start;
+ afl_module_info_t *mod_info = NULL;
- if (!getenv("AFL_IGNORE_PROBLEMS")) {
+ Dl_info dlinfo;
+ if (dladdr(__builtin_return_address(0), &dlinfo)) {
- fprintf(
- stderr,
- "[-] FATAL: forkserver is already up, but an instrumented dlopen() "
- "library loaded afterwards. You must AFL_PRELOAD such libraries to "
- "be able to fuzz them or LD_PRELOAD to run outside of afl-fuzz.\n"
- "To ignore this set AFL_IGNORE_PROBLEMS=1.\n");
- abort();
+ if (__afl_already_initialized_forkserver) {
+
+ fprintf(stderr, "[pcmap] Error: Module was not preloaded: %s\n",
+ dlinfo.dli_fname);
} else {
- static u32 offset = 4;
+ afl_module_info_t *last_module_info = __afl_module_info;
+ while (last_module_info && last_module_info->next) {
- while (start < stop) {
+ last_module_info = last_module_info->next;
+
+ }
- *(start++) = offset;
- if (unlikely(++offset >= __afl_final_loc)) { offset = 4; }
+ mod_info = malloc(sizeof(afl_module_info_t));
+
+ mod_info->id = last_module_info ? last_module_info->id + 1 : 0;
+ mod_info->name = strdup(dlinfo.dli_fname);
+ mod_info->base_address = (uintptr_t)dlinfo.dli_fbase;
+ mod_info->start = 0;
+ mod_info->stop = 0;
+ mod_info->pcs_beg = NULL;
+ mod_info->pcs_end = NULL;
+ mod_info->mapped = 0;
+ mod_info->next = NULL;
+
+ if (last_module_info) {
+
+ last_module_info->next = mod_info;
+
+ } else {
+
+ __afl_module_info = mod_info;
}
+ fprintf(stderr, "[pcmap] Module: %s Base Address: %p\n", dlinfo.dli_fname,
+ dlinfo.dli_fbase);
+
}
+ } else {
+
+ fprintf(stderr, "[pcmap] dladdr call failed\n");
+
}
+#endif // __AFL_CODE_COVERAGE
+
x = getenv("AFL_INST_RATIO");
- if (x) { inst_ratio = (u32)atoi(x); }
+ if (x) {
- if (!inst_ratio || inst_ratio > 100) {
+ inst_ratio = (u32)atoi(x);
- fprintf(stderr, "[-] ERROR: Invalid AFL_INST_RATIO (must be 1-100).\n");
- abort();
+ if (!inst_ratio || inst_ratio > 100) {
+
+ fprintf(stderr, "[-] ERROR: Invalid AFL_INST_RATIO (must be 1-100).\n");
+ abort();
+
+ }
}
- /* instrumented code is loaded *after* our forkserver is up. this is a
- problem. We cannot prevent collisions then :( */
- /*
- if (__afl_already_initialized_forkserver &&
- __afl_final_loc + 1 + stop - start > __afl_map_size) {
+ // If a dlopen of an instrumented library happens after the forkserver then
+ // we have a problem as we cannot increase the coverage map anymore.
+ if (__afl_already_initialized_forkserver) {
- if (__afl_debug) {
+ if (!getenv("AFL_IGNORE_PROBLEMS")) {
+
+ fprintf(
+ stderr,
+ "[-] FATAL: forkserver is already up, but an instrumented dlopen() "
+ "library loaded afterwards. You must AFL_PRELOAD such libraries to "
+ "be able to fuzz them or LD_PRELOAD to run outside of afl-fuzz.\n"
+ "To ignore this set AFL_IGNORE_PROBLEMS=1 but this will lead to "
+ "ambiguous coverage data.\n"
+ "In addition, you can set AFL_IGNORE_PROBLEMS_COVERAGE=1 to "
+ "ignore the additional coverage instead (use with caution!).\n");
+ abort();
- fprintf(stderr, "Warning: new instrumented code after the forkserver!\n");
+ } else {
- }
+ u8 ignore_dso_after_fs = !!getenv("AFL_IGNORE_PROBLEMS_COVERAGE");
+ if (__afl_debug && ignore_dso_after_fs) {
- __afl_final_loc = 2;
+ fprintf(stderr, "Ignoring coverage from dynamically loaded code\n");
- if (1 + stop - start > __afl_map_size) {
+ }
- *(start++) = ++__afl_final_loc;
+ static u32 offset = 5;
while (start < stop) {
- if (R(100) < inst_ratio)
- *start = ++__afl_final_loc % __afl_map_size;
- else
- *start = 4;
+ if (!ignore_dso_after_fs &&
+ (likely(inst_ratio == 100) || R(100) < inst_ratio)) {
- start++;
+ *(start++) = offset;
- }
+ } else {
+
+ *(start++) = 0; // write to map[0]
+
+ }
+
+ if (unlikely(++offset >= __afl_final_loc)) { offset = 5; }
- return;
+ }
}
- }
+ return; // we are done for this special case
- */
+ }
/* Make sure that the first element in the range is always set - we use that
to avoid duplicate calls (which can happen as an artifact of the underlying
implementation in LLVM). */
+ if (__afl_final_loc < 5) __afl_final_loc = 5; // we skip the first 5 entries
+
*(start++) = ++__afl_final_loc;
while (start < stop) {
- if (R(100) < inst_ratio)
- *start = ++__afl_final_loc;
- else
- *start = 4;
+ if (likely(inst_ratio == 100) || R(100) < inst_ratio) {
+
+ *(start++) = ++__afl_final_loc;
+
+ } else {
- start++;
+ *(start++) = 0; // write to map[0]
+
+ }
+
+ }
+
+#ifdef __AFL_CODE_COVERAGE
+ if (mod_info) {
+
+ mod_info->start = *orig_start;
+ mod_info->stop = *(stop - 1);
+ if (__afl_debug) {
+
+ fprintf(stderr, "DEBUG: [pcmap] Start Index: %u Stop Index: %u\n",
+ mod_info->start, mod_info->stop);
+
+ }
}
+#endif // __AFL_CODE_COVERAGE
+
if (__afl_debug) {
fprintf(stderr,
@@ -1538,17 +1882,23 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
}
- if (__afl_already_initialized_shm && __afl_final_loc > __afl_map_size) {
+ if (__afl_already_initialized_shm) {
- if (__afl_debug) {
+ if (__afl_final_loc > __afl_map_size) {
+
+ if (__afl_debug) {
+
+ fprintf(stderr, "Reinit shm necessary (+%u)\n",
+ __afl_final_loc - __afl_map_size);
+
+ }
- fprintf(stderr, "Reinit shm necessary (+%u)\n",
- __afl_final_loc - __afl_map_size);
+ __afl_unmap_shm();
+ __afl_map_shm();
}
- __afl_unmap_shm();
- __afl_map_shm();
+ __afl_map_size = __afl_final_loc + 1;
}
diff --git a/instrumentation/afl-gcc-cmplog-pass.so.cc b/instrumentation/afl-gcc-cmplog-pass.so.cc
new file mode 100644
index 00000000..b4e6fda9
--- /dev/null
+++ b/instrumentation/afl-gcc-cmplog-pass.so.cc
@@ -0,0 +1,404 @@
+/* GCC plugin for cmplog instrumentation of code for AFL++.
+
+ Copyright 2014-2019 Free Software Foundation, Inc
+ Copyright 2015, 2016 Google Inc. All rights reserved.
+ Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 AdaCore
+
+ Written by Alexandre Oliva <oliva@adacore.com>, based on the AFL++
+ LLVM CmpLog pass by Andrea Fioraldi <andreafioraldi@gmail.com>, and
+ on the AFL GCC pass.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ */
+
+#include "afl-gcc-common.h"
+
+/* This plugin, being under the same license as GCC, satisfies the
+ "GPL-compatible Software" definition in the GCC RUNTIME LIBRARY
+ EXCEPTION, so it can be part of an "Eligible" "Compilation
+ Process". */
+int plugin_is_GPL_compatible = 1;
+
+namespace {
+
+static const struct pass_data afl_cmplog_pass_data = {
+
+ .type = GIMPLE_PASS,
+ .name = "aflcmplog",
+ .optinfo_flags = OPTGROUP_NONE,
+ .tv_id = TV_NONE,
+ .properties_required = 0,
+ .properties_provided = 0,
+ .properties_destroyed = 0,
+ .todo_flags_start = 0,
+ .todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg | TODO_verify_il |
+ TODO_rebuild_cgraph_edges),
+
+};
+
+struct afl_cmplog_pass : afl_base_pass {
+
+ afl_cmplog_pass(bool quiet)
+ : afl_base_pass(quiet, /*debug=*/false, afl_cmplog_pass_data),
+ t8u(),
+ cmplog_hooks() {
+
+ }
+
+ /* An unsigned 8-bit integral type. */
+ tree t8u;
+
+ /* Declarations for the various cmplog hook functions, allocated on demand..
+ [0] is for __cmplog_ins_hookN, that accepts non-power-of-2 sizes.
+ [n in 1..5] are for unsigned ints of 2^{n-1} bytes. */
+ tree cmplog_hooks[6];
+
+ tree cmplog_hook(unsigned i) {
+
+ tree t, fnt;
+
+ if (!t8u) {
+
+ if (BITS_PER_UNIT == 8)
+ t8u = unsigned_char_type_node;
+ else
+ t8u = build_nonstandard_integer_type(8, 1);
+
+ }
+
+ if (i <= ARRAY_SIZE(cmplog_hooks) && cmplog_hooks[i])
+ return cmplog_hooks[i];
+
+ switch (i) {
+
+ case 0:
+#ifdef uint128_type_node
+ t = uint128_type_node;
+#else
+ t = build_nonstandard_integer_type(128, 1);
+#endif
+ fnt =
+ build_function_type_list(void_type_node, t, t, t8u, t8u, NULL_TREE);
+ t = cmplog_hooks[0] = build_fn_decl("__cmplog_ins_hookN", fnt);
+ break;
+
+ case 1:
+ t = t8u;
+ fnt = build_function_type_list(void_type_node, t, t, t8u, NULL_TREE);
+ t = cmplog_hooks[1] = build_fn_decl("__cmplog_ins_hook1", fnt);
+ break;
+
+ case 2:
+ t = uint16_type_node;
+ fnt = build_function_type_list(void_type_node, t, t, t8u, NULL_TREE);
+ t = cmplog_hooks[2] = build_fn_decl("__cmplog_ins_hook2", fnt);
+ break;
+
+ case 3:
+ t = uint32_type_node;
+ fnt = build_function_type_list(void_type_node, t, t, t8u, NULL_TREE);
+ t = cmplog_hooks[3] = build_fn_decl("__cmplog_ins_hook4", fnt);
+ break;
+
+ case 4:
+ t = uint64_type_node;
+ fnt = build_function_type_list(void_type_node, t, t, t8u, NULL_TREE);
+ t = cmplog_hooks[4] = build_fn_decl("__cmplog_ins_hook8", fnt);
+ break;
+
+ case 5:
+#ifdef uint128_type_node
+ t = uint128_type_node;
+#else
+ t = build_nonstandard_integer_type(128, 1);
+#endif
+ fnt = build_function_type_list(void_type_node, t, t, t8u, NULL_TREE);
+ t = cmplog_hooks[5] = build_fn_decl("__cmplog_ins_hook16", fnt);
+ break;
+
+ default:
+ gcc_unreachable();
+
+ }
+
+ /* Mark the newly-created decl as non-throwing, so that we can
+ insert call within basic blocks. */
+ TREE_NOTHROW(t) = 1;
+
+ return t;
+
+ }
+
+ /* Insert a cmplog hook call before GSI for a CODE compare between
+ LHS and RHS. */
+ void insert_cmplog_call(gimple_stmt_iterator gsi, tree_code code, tree lhs,
+ tree rhs) {
+
+ gcc_checking_assert(TYPE_MAIN_VARIANT(TREE_TYPE(lhs)) ==
+ TYPE_MAIN_VARIANT(TREE_TYPE(rhs)));
+
+ tree fn;
+ bool pass_n = false;
+
+ /* Obtain the compare operand size as a constant. */
+ tree st = TREE_TYPE(lhs);
+ tree szt = TYPE_SIZE(st);
+
+ if (!tree_fits_uhwi_p(szt)) return;
+
+ unsigned HOST_WIDE_INT sz = tree_to_uhwi(szt);
+
+ /* Round it up. */
+ if (sz % 8) sz = (((sz - 1) / 8) + 1) * 8;
+
+ /* Select the hook function to call, based on the size. */
+ switch (sz) {
+
+ default:
+ fn = cmplog_hook(0);
+ pass_n = true;
+ break;
+
+ case 8:
+ fn = cmplog_hook(1);
+ break;
+
+ case 16:
+ fn = cmplog_hook(2);
+ break;
+
+ case 32:
+ fn = cmplog_hook(3);
+ break;
+
+ case 64:
+ fn = cmplog_hook(4);
+ break;
+
+ case 128:
+ fn = cmplog_hook(5);
+ break;
+
+ }
+
+ /* Set attr according to the compare operation. */
+ unsigned char attr = 0;
+
+ switch (code) {
+
+ case UNORDERED_EXPR:
+ case ORDERED_EXPR:
+ /* ??? */
+ /* Fallthrough. */
+ case NE_EXPR:
+ case LTGT_EXPR:
+ break;
+
+ case EQ_EXPR:
+ case UNEQ_EXPR:
+ attr += 1;
+ break;
+
+ case GT_EXPR:
+ case UNGT_EXPR:
+ attr += 2;
+ break;
+
+ case GE_EXPR:
+ case UNGE_EXPR:
+ attr += 3;
+ break;
+
+ case LT_EXPR:
+ case UNLT_EXPR:
+ attr += 4;
+ break;
+
+ case LE_EXPR:
+ case UNLE_EXPR:
+ attr += 5;
+ break;
+
+ default:
+ gcc_unreachable();
+
+ }
+
+ if (FLOAT_TYPE_P(TREE_TYPE(lhs))) {
+
+ attr += 8;
+
+ tree t = build_nonstandard_integer_type(sz, 1);
+
+ tree s = make_ssa_name(t);
+ gimple g = gimple_build_assign(s, VIEW_CONVERT_EXPR,
+ build1(VIEW_CONVERT_EXPR, t, lhs));
+ lhs = s;
+ gsi_insert_before(&gsi, g, GSI_SAME_STMT);
+
+ s = make_ssa_name(t);
+ g = gimple_build_assign(s, VIEW_CONVERT_EXPR,
+ build1(VIEW_CONVERT_EXPR, t, rhs));
+ rhs = s;
+ gsi_insert_before(&gsi, g, GSI_SAME_STMT);
+
+ }
+
+ /* Convert the operands to the hook arg type, if needed. */
+ tree t = TREE_VALUE(TYPE_ARG_TYPES(TREE_TYPE(fn)));
+
+ lhs = fold_convert_loc(UNKNOWN_LOCATION, t, lhs);
+ if (!is_gimple_val(lhs)) {
+
+ tree s = make_ssa_name(t);
+ gimple g = gimple_build_assign(s, lhs);
+ lhs = s;
+ gsi_insert_before(&gsi, g, GSI_SAME_STMT);
+
+ }
+
+ rhs = fold_convert_loc(UNKNOWN_LOCATION, t, rhs);
+ if (!is_gimple_val(rhs)) {
+
+ tree s = make_ssa_name(t);
+ gimple g = gimple_build_assign(s, rhs);
+ rhs = s;
+ gsi_insert_before(&gsi, g, GSI_SAME_STMT);
+
+ }
+
+ /* Insert the call. */
+ tree att = build_int_cst(t8u, attr);
+ gimple call;
+ if (pass_n)
+ call = gimple_build_call(fn, 4, lhs, rhs, att,
+ build_int_cst(t8u, sz / 8 - 1));
+ else
+ call = gimple_build_call(fn, 3, lhs, rhs, att);
+
+ gsi_insert_before(&gsi, call, GSI_SAME_STMT);
+
+ }
+
+ virtual unsigned int execute(function *fn) {
+
+ if (!isInInstrumentList(fn)) return 0;
+
+ basic_block bb;
+ FOR_EACH_BB_FN(bb, fn) {
+
+ /* A GIMPLE_COND or GIMPLE_SWITCH will always be the last stmt
+ in a BB. */
+ gimple_stmt_iterator gsi = gsi_last_bb(bb);
+ if (gsi_end_p(gsi)) continue;
+
+ gimple stmt = gsi_stmt(gsi);
+
+ if (gimple_code(stmt) == GIMPLE_COND) {
+
+ tree_code code = gimple_cond_code(stmt);
+ tree lhs = gimple_cond_lhs(stmt);
+ tree rhs = gimple_cond_rhs(stmt);
+
+ insert_cmplog_call(gsi, code, lhs, rhs);
+
+ } else if (gimple_code(stmt) == GIMPLE_SWITCH) {
+
+ gswitch *sw = as_a<gswitch *>(stmt);
+ tree lhs = gimple_switch_index(sw);
+
+ for (int i = 0, e = gimple_switch_num_labels(sw); i < e; i++) {
+
+ tree clx = gimple_switch_label(sw, i);
+ tree rhsl = CASE_LOW(clx);
+ /* Default case labels exprs don't have a CASE_LOW. */
+ if (!rhsl) continue;
+ tree rhsh = CASE_HIGH(clx);
+ /* If there is a CASE_HIGH, issue range compares. */
+ if (rhsh) {
+
+ insert_cmplog_call(gsi, GE_EXPR, lhs, rhsl);
+ insert_cmplog_call(gsi, LE_EXPR, lhs, rhsh);
+
+ }
+
+ /* Otherwise, use a single equality compare. */
+ else
+ insert_cmplog_call(gsi, EQ_EXPR, lhs, rhsl);
+
+ }
+
+ } else
+
+ continue;
+
+ }
+
+ return 0;
+
+ }
+
+};
+
+static struct plugin_info afl_cmplog_plugin = {
+
+ .version = "20220420",
+ .help = G_("AFL gcc cmplog plugin\n\
+\n\
+Set AFL_QUIET in the environment to silence it.\n\
+"),
+
+};
+
+} // namespace
+
+/* This is the function GCC calls when loading a plugin. Initialize
+ and register further callbacks. */
+int plugin_init(struct plugin_name_args *info,
+ struct plugin_gcc_version *version) {
+
+ if (!plugin_default_version_check(version, &gcc_version))
+ FATAL(G_("GCC and plugin have incompatible versions, expected GCC %s, "
+ "is %s"),
+ gcc_version.basever, version->basever);
+
+ /* Show a banner. */
+ bool quiet = false;
+ if (isatty(2) && !getenv("AFL_QUIET"))
+ SAYF(cCYA "afl-gcc-cmplog-pass " cBRI VERSION cRST
+ " by <oliva@adacore.com>\n");
+ else
+ quiet = true;
+
+ const char *name = info->base_name;
+ register_callback(name, PLUGIN_INFO, NULL, &afl_cmplog_plugin);
+
+ afl_cmplog_pass *aflp = new afl_cmplog_pass(quiet);
+ struct register_pass_info pass_info = {
+
+ .pass = aflp,
+ .reference_pass_name = "ssa",
+ .ref_pass_instance_number = 1,
+ .pos_op = PASS_POS_INSERT_AFTER,
+
+ };
+
+ register_callback(name, PLUGIN_PASS_MANAGER_SETUP, NULL, &pass_info);
+
+ return 0;
+
+}
+
diff --git a/instrumentation/afl-gcc-cmptrs-pass.so.cc b/instrumentation/afl-gcc-cmptrs-pass.so.cc
new file mode 100644
index 00000000..dbb408b0
--- /dev/null
+++ b/instrumentation/afl-gcc-cmptrs-pass.so.cc
@@ -0,0 +1,366 @@
+/* GCC plugin for cmplog routines instrumentation of code for AFL++.
+
+ Copyright 2014-2019 Free Software Foundation, Inc
+ Copyright 2015, 2016 Google Inc. All rights reserved.
+ Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 AdaCore
+
+ Written by Alexandre Oliva <oliva@adacore.com>, based on the AFL++
+ LLVM CmpLog Routines pass by Andrea Fioraldi
+ <andreafioraldi@gmail.com>, and on the AFL GCC CmpLog pass.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ */
+
+#include "afl-gcc-common.h"
+
+/* This plugin, being under the same license as GCC, satisfies the
+ "GPL-compatible Software" definition in the GCC RUNTIME LIBRARY
+ EXCEPTION, so it can be part of an "Eligible" "Compilation
+ Process". */
+int plugin_is_GPL_compatible = 1;
+
+namespace {
+
+static const struct pass_data afl_cmptrs_pass_data = {
+
+ .type = GIMPLE_PASS,
+ .name = "aflcmptrs",
+ .optinfo_flags = OPTGROUP_NONE,
+ .tv_id = TV_NONE,
+ .properties_required = 0,
+ .properties_provided = 0,
+ .properties_destroyed = 0,
+ .todo_flags_start = 0,
+ .todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg | TODO_verify_il |
+ TODO_rebuild_cgraph_edges),
+
+};
+
+struct afl_cmptrs_pass : afl_base_pass {
+
+ afl_cmptrs_pass(bool quiet)
+ : afl_base_pass(quiet, /*debug=*/false, afl_cmptrs_pass_data),
+ tp8u(),
+ cmptrs_hooks() {
+
+ }
+
+ /* A pointer type to a unsigned 8-bit integral type. */
+ tree tp8u;
+
+ /* Declarations for the various cmptrs hook functions, allocated on
+ demand.. [0] is for compares between any pointers, [1] is for
+ compares between G++ std::string, [2] is for compares between G++
+ std::string and GCC C strings, [3] and [4] are analogous to [1]
+ and [2] but for LLVM C++ strings. */
+ tree cmptrs_hooks[5];
+
+ tree cmptrs_hook(unsigned i) {
+
+ if (!tp8u) {
+
+ tree t8u;
+ if (BITS_PER_UNIT == 8)
+ t8u = unsigned_char_type_node;
+ else
+ t8u = build_nonstandard_integer_type(8, 1);
+ tp8u = build_pointer_type(t8u);
+
+ }
+
+ if (i <= ARRAY_SIZE(cmptrs_hooks) && cmptrs_hooks[i])
+ return cmptrs_hooks[i];
+
+ const char *n = NULL;
+
+ switch (i) {
+
+ case 0:
+ n = "__cmplog_rtn_hook";
+ break;
+
+ case 1:
+ n = "__cmplog_rtn_gcc_stdstring_stdstring";
+ break;
+
+ case 2:
+ n = "__cmplog_rtn_gcc_stdstring_cstring";
+ break;
+
+ case 3:
+ n = "__cmplog_rtn_llvm_stdstring_stdstring";
+ break;
+
+ case 4:
+ n = "__cmplog_rtn_llvm_stdstring_cstring";
+ break;
+
+ default:
+ gcc_unreachable();
+
+ }
+
+ tree fnt = build_function_type_list(void_type_node, tp8u, tp8u, NULL_TREE);
+ tree t = cmptrs_hooks[i] = build_fn_decl(n, fnt);
+
+ /* Mark the newly-created decl as non-throwing, so that we can
+ insert call within basic blocks. */
+ TREE_NOTHROW(t) = 1;
+
+ return t;
+
+ }
+
+ /* Return true if T is the char* type. */
+ bool is_c_string(tree t) {
+
+ return (POINTER_TYPE_P(t) &&
+ TYPE_MAIN_VARIANT(TREE_TYPE(t)) == char_type_node);
+
+ }
+
+ /* Return true if T is an indirect std::string type. The LLVM pass
+ tests portions of the mangled name of the callee. We could do
+ that in GCC too, but computing the mangled name may cause
+ template instantiations and get symbols defined that could
+ otherwise be considered unused. We check for compatible layout,
+ and class, namespace, and field names. These have been unchanged
+ since at least GCC 7, probably longer, up to GCC 11. Odds are
+ that, if it were to change in significant ways, mangling would
+ also change to flag the incompatibility, and we'd have to use a
+ different hook anyway. */
+ bool is_gxx_std_string(tree t) {
+
+ /* We need a pointer or reference type. */
+ if (!POINTER_TYPE_P(t)) return false;
+
+ /* Get to the pointed-to type. */
+ t = TREE_TYPE(t);
+ if (!t) return false;
+
+ /* Select the main variant, so that can compare types with pointers. */
+ t = TYPE_MAIN_VARIANT(t);
+
+ /* We expect it to be a record type. */
+ if (TREE_CODE(t) != RECORD_TYPE) return false;
+
+ /* The type of the template is basic_string. */
+ if (strcmp(IDENTIFIER_POINTER(TYPE_IDENTIFIER(t)), "basic_string") != 0)
+ return false;
+
+ /* It's declared in an internal namespace named __cxx11. */
+ tree c = DECL_CONTEXT(TYPE_NAME(t));
+ if (!c || TREE_CODE(c) != NAMESPACE_DECL ||
+ strcmp(IDENTIFIER_POINTER(DECL_NAME(c)), "__cxx11") != 0)
+ return false;
+
+ /* The __cxx11 namespace is a member of namespace std. */
+ c = DECL_CONTEXT(c);
+ if (!c || TREE_CODE(c) != NAMESPACE_DECL ||
+ strcmp(IDENTIFIER_POINTER(DECL_NAME(c)), "std") != 0)
+ return false;
+
+ /* And the std namespace is in the global namespace. */
+ c = DECL_CONTEXT(c);
+ if (c && TREE_CODE(c) != TRANSLATION_UNIT_DECL) return false;
+
+ /* Check that the first nonstatic data member of the record type
+ is named _M_dataplus. */
+ for (c = TYPE_FIELDS(t); c; c = DECL_CHAIN(c))
+ if (TREE_CODE(c) == FIELD_DECL) break;
+ if (!c || !integer_zerop(DECL_FIELD_BIT_OFFSET(c)) ||
+ strcmp(IDENTIFIER_POINTER(DECL_NAME(c)), "_M_dataplus") != 0)
+ return false;
+
+ /* Check that the second nonstatic data member of the record type
+ is named _M_string_length. */
+ tree f2;
+ for (f2 = DECL_CHAIN(c); f2; f2 = DECL_CHAIN(f2))
+ if (TREE_CODE(f2) == FIELD_DECL) break;
+ if (!f2 /* No need to check this field's offset. */
+ || strcmp(IDENTIFIER_POINTER(DECL_NAME(f2)), "_M_string_length") != 0)
+ return false;
+
+ /* The type of the second data member is size_t. */
+ if (!TREE_TYPE(f2) || TYPE_MAIN_VARIANT(TREE_TYPE(f2)) != size_type_node)
+ return false;
+
+ /* Now go back to the first data member. Its type should be a
+ record type named _Alloc_hider. */
+ c = TREE_TYPE(c);
+ if (!c || TREE_CODE(c) != RECORD_TYPE ||
+ strcmp(IDENTIFIER_POINTER(TYPE_IDENTIFIER(c)), "_Alloc_hider") != 0)
+ return false;
+
+ /* And its first data member is named _M_p. */
+ for (c = TYPE_FIELDS(c); c; c = DECL_CHAIN(c))
+ if (TREE_CODE(c) == FIELD_DECL) break;
+ if (!c || !integer_zerop(DECL_FIELD_BIT_OFFSET(c)) ||
+ strcmp(IDENTIFIER_POINTER(DECL_NAME(c)), "_M_p") != 0)
+ return false;
+
+ /* For the basic_string<char> type we're interested in, the type
+ of the data member is the C string type. */
+ if (!is_c_string(TREE_TYPE(c))) return false;
+
+ /* This might not be the real thing, but the bits that matter for
+ the hook are there. */
+
+ return true;
+
+ }
+
+ /* ??? This is not implemented. What would the point be of
+ recognizing LLVM's string type in GCC? */
+ bool is_llvm_std_string(tree t) {
+
+ return false;
+
+ }
+
+ virtual unsigned int execute(function *fn) {
+
+ if (!isInInstrumentList(fn)) return 0;
+
+ basic_block bb;
+ FOR_EACH_BB_FN(bb, fn) {
+
+ for (gimple_stmt_iterator gsi = gsi_after_labels(bb); !gsi_end_p(gsi);
+ gsi_next(&gsi)) {
+
+ gimple stmt = gsi_stmt(gsi);
+
+ /* We're only interested in GIMPLE_CALLs. */
+ if (gimple_code(stmt) != GIMPLE_CALL) continue;
+
+ if (gimple_call_num_args(stmt) < 2) continue;
+
+ gcall *c = as_a<gcall *>(stmt);
+
+ tree callee_type = gimple_call_fntype(c);
+
+ if (!callee_type || !TYPE_ARG_TYPES(callee_type) ||
+ !TREE_CHAIN(TYPE_ARG_TYPES(callee_type)))
+ continue;
+
+ tree arg_type[2] = {
+
+ TYPE_MAIN_VARIANT(TREE_VALUE(TYPE_ARG_TYPES(callee_type))),
+ TYPE_MAIN_VARIANT(
+ TREE_VALUE(TREE_CHAIN(TYPE_ARG_TYPES(callee_type))))};
+
+ tree fn = NULL;
+ /* Callee arglist starts with two GCC std::string arguments. */
+ if (arg_type[0] == arg_type[1] && is_gxx_std_string(arg_type[0]))
+ fn = cmptrs_hook(1);
+ /* Callee arglist starts with GCC std::string and C string. */
+ else if (is_gxx_std_string(arg_type[0]) && is_c_string(arg_type[1]))
+ fn = cmptrs_hook(2);
+ /* Callee arglist starts with two LLVM std::string arguments. */
+ else if (arg_type[0] == arg_type[1] && is_llvm_std_string(arg_type[0]))
+ fn = cmptrs_hook(3);
+ /* Callee arglist starts with LLVM std::string and C string. */
+ else if (is_llvm_std_string(arg_type[0]) && is_c_string(arg_type[1]))
+ fn = cmptrs_hook(4);
+ /* Callee arglist starts with two pointers to the same type,
+ and callee returns a value. */
+ else if (arg_type[0] == arg_type[1] && POINTER_TYPE_P(arg_type[0]) &&
+ (TYPE_MAIN_VARIANT(gimple_call_return_type(c)) !=
+ void_type_node))
+ fn = cmptrs_hook(0);
+ else
+ continue;
+
+ tree arg[2] = {gimple_call_arg(c, 0), gimple_call_arg(c, 1)};
+
+ for (unsigned i = 0; i < ARRAY_SIZE(arg); i++) {
+
+ tree c = fold_convert_loc(UNKNOWN_LOCATION, tp8u, arg[i]);
+ if (!is_gimple_val(c)) {
+
+ tree s = make_ssa_name(tp8u);
+ gimple g = gimple_build_assign(s, c);
+ c = s;
+ gsi_insert_before(&gsi, g, GSI_SAME_STMT);
+
+ }
+
+ arg[i] = c;
+
+ }
+
+ gimple call = gimple_build_call(fn, 2, arg[0], arg[1]);
+ gsi_insert_before(&gsi, call, GSI_SAME_STMT);
+
+ }
+
+ }
+
+ return 0;
+
+ }
+
+};
+
+static struct plugin_info afl_cmptrs_plugin = {
+
+ .version = "20220420",
+ .help = G_("AFL gcc cmptrs plugin\n\
+\n\
+Set AFL_QUIET in the environment to silence it.\n\
+"),
+
+};
+
+} // namespace
+
+/* This is the function GCC calls when loading a plugin. Initialize
+ and register further callbacks. */
+int plugin_init(struct plugin_name_args *info,
+ struct plugin_gcc_version *version) {
+
+ if (!plugin_default_version_check(version, &gcc_version))
+ FATAL(G_("GCC and plugin have incompatible versions, expected GCC %s, "
+ "is %s"),
+ gcc_version.basever, version->basever);
+
+ /* Show a banner. */
+ bool quiet = false;
+ if (isatty(2) && !getenv("AFL_QUIET"))
+ SAYF(cCYA "afl-gcc-cmptrs-pass " cBRI VERSION cRST
+ " by <oliva@adacore.com>\n");
+ else
+ quiet = true;
+
+ const char *name = info->base_name;
+ register_callback(name, PLUGIN_INFO, NULL, &afl_cmptrs_plugin);
+
+ afl_cmptrs_pass *aflp = new afl_cmptrs_pass(quiet);
+ struct register_pass_info pass_info = {
+
+ .pass = aflp,
+ .reference_pass_name = "ssa",
+ .ref_pass_instance_number = 1,
+ .pos_op = PASS_POS_INSERT_AFTER,
+
+ };
+
+ register_callback(name, PLUGIN_PASS_MANAGER_SETUP, NULL, &pass_info);
+
+ return 0;
+
+}
+
diff --git a/instrumentation/afl-gcc-common.h b/instrumentation/afl-gcc-common.h
new file mode 100644
index 00000000..1d5eb466
--- /dev/null
+++ b/instrumentation/afl-gcc-common.h
@@ -0,0 +1,508 @@
+/* GCC plugin common infrastructure for AFL++ instrumentation passes.
+
+ Copyright 2014-2019 Free Software Foundation, Inc
+ Copyright 2015, 2016 Google Inc. All rights reserved.
+ Copyright 2019-2023 AdaCore
+
+ Written by Alexandre Oliva <oliva@adacore.com>, based on the AFL++
+ GCC plugin.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ */
+
+#include "../include/config.h"
+#include "../include/debug.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef likely
+ #undef likely
+#endif
+#ifdef unlikely
+ #undef unlikely
+#endif
+
+#include <list>
+#include <string>
+#include <fstream>
+
+#include <algorithm>
+#include <fnmatch.h>
+
+#include <gcc-plugin.h>
+#include <plugin-version.h>
+#include <toplev.h>
+#include <tree-pass.h>
+#include <context.h>
+#include <tree.h>
+#include <gimplify.h>
+#include <basic-block.h>
+#include <tree-ssa-alias.h>
+#include <gimple-expr.h>
+#include <gimple.h>
+#include <gimple-iterator.h>
+#include <stringpool.h>
+#include <gimple-ssa.h>
+#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= \
+ 60200 /* >= version 6.2.0 */
+ #include <tree-vrp.h>
+#endif
+#include <tree-ssanames.h>
+#include <tree-phinodes.h>
+#include <ssa-iterators.h>
+
+#include <intl.h>
+
+namespace {
+
+struct afl_base_pass : gimple_opt_pass {
+
+ afl_base_pass(bool quiet, bool debug, struct pass_data const &pd)
+ : gimple_opt_pass(pd, g), be_quiet(quiet), debug(debug) {
+
+ initInstrumentList();
+
+ }
+
+ /* Are we outputting to a non-terminal, or running with AFL_QUIET
+ set? */
+ const bool be_quiet;
+
+ /* Are we running with AFL_DEBUG set? */
+ const bool debug;
+
+#define report_fatal_error(msg) BADF(msg)
+
+ std::list<std::string> allowListFiles;
+ std::list<std::string> allowListFunctions;
+ std::list<std::string> denyListFiles;
+ std::list<std::string> denyListFunctions;
+
+ /* Note: this ignore check is also called in isInInstrumentList() */
+ bool isIgnoreFunction(function *F) {
+
+ // Starting from "LLVMFuzzer" these are functions used in libfuzzer based
+ // fuzzing campaign installations, e.g. oss-fuzz
+
+ static constexpr const char *ignoreList[] = {
+
+ "asan.",
+ "llvm.",
+ "sancov.",
+ "__ubsan_",
+ "ign.",
+ "__afl_",
+ "_fini",
+ "__libc_csu",
+ "__asan",
+ "__msan",
+ "__cmplog",
+ "__sancov",
+ "msan.",
+ "LLVMFuzzerM",
+ "LLVMFuzzerC",
+ "LLVMFuzzerI",
+ "__decide_deferred",
+ "maybe_duplicate_stderr",
+ "discard_output",
+ "close_stdout",
+ "dup_and_close_stderr",
+ "maybe_close_fd_mask",
+ "ExecuteFilesOnyByOne"
+
+ };
+
+ const char *name = IDENTIFIER_POINTER(DECL_NAME(F->decl));
+ int len = IDENTIFIER_LENGTH(DECL_NAME(F->decl));
+
+ for (auto const &ignoreListFunc : ignoreList) {
+
+ if (strncmp(name, ignoreListFunc, len) == 0) { return true; }
+
+ }
+
+ return false;
+
+ }
+
+ void initInstrumentList() {
+
+ char *allowlist = getenv("AFL_GCC_ALLOWLIST");
+ if (!allowlist) allowlist = getenv("AFL_GCC_INSTRUMENT_FILE");
+ if (!allowlist) allowlist = getenv("AFL_GCC_WHITELIST");
+ if (!allowlist) allowlist = getenv("AFL_LLVM_ALLOWLIST");
+ if (!allowlist) allowlist = getenv("AFL_LLVM_INSTRUMENT_FILE");
+ if (!allowlist) allowlist = getenv("AFL_LLVM_WHITELIST");
+ char *denylist = getenv("AFL_GCC_DENYLIST");
+ if (!denylist) denylist = getenv("AFL_GCC_BLOCKLIST");
+ if (!denylist) denylist = getenv("AFL_LLVM_DENYLIST");
+ if (!denylist) denylist = getenv("AFL_LLVM_BLOCKLIST");
+
+ if (allowlist && denylist)
+ FATAL(
+ "You can only specify either AFL_GCC_ALLOWLIST or AFL_GCC_DENYLIST "
+ "but not both!");
+
+ if (allowlist) {
+
+ std::string line;
+ std::ifstream fileStream;
+ fileStream.open(allowlist);
+ if (!fileStream) report_fatal_error("Unable to open AFL_GCC_ALLOWLIST");
+ getline(fileStream, line);
+
+ while (fileStream) {
+
+ int is_file = -1;
+ std::size_t npos;
+ std::string original_line = line;
+
+ line.erase(std::remove_if(line.begin(), line.end(), ::isspace),
+ line.end());
+
+ // remove # and following
+ if ((npos = line.find("#")) != std::string::npos)
+ line = line.substr(0, npos);
+
+ if (line.compare(0, 4, "fun:") == 0) {
+
+ is_file = 0;
+ line = line.substr(4);
+
+ } else if (line.compare(0, 9, "function:") == 0) {
+
+ is_file = 0;
+ line = line.substr(9);
+
+ } else if (line.compare(0, 4, "src:") == 0) {
+
+ is_file = 1;
+ line = line.substr(4);
+
+ } else if (line.compare(0, 7, "source:") == 0) {
+
+ is_file = 1;
+ line = line.substr(7);
+
+ }
+
+ if (line.find(":") != std::string::npos) {
+
+ FATAL("invalid line in AFL_GCC_ALLOWLIST: %s", original_line.c_str());
+
+ }
+
+ if (line.length() > 0) {
+
+ // if the entry contains / or . it must be a file
+ if (is_file == -1)
+ if (line.find("/") != std::string::npos ||
+ line.find(".") != std::string::npos)
+ is_file = 1;
+ // otherwise it is a function
+
+ if (is_file == 1)
+ allowListFiles.push_back(line);
+ else
+ allowListFunctions.push_back(line);
+
+ }
+
+ getline(fileStream, line);
+
+ }
+
+ if (debug)
+ DEBUGF("loaded allowlist with %zu file and %zu function entries\n",
+ allowListFiles.size(), allowListFunctions.size());
+
+ }
+
+ if (denylist) {
+
+ std::string line;
+ std::ifstream fileStream;
+ fileStream.open(denylist);
+ if (!fileStream) report_fatal_error("Unable to open AFL_GCC_DENYLIST");
+ getline(fileStream, line);
+
+ while (fileStream) {
+
+ int is_file = -1;
+ std::size_t npos;
+ std::string original_line = line;
+
+ line.erase(std::remove_if(line.begin(), line.end(), ::isspace),
+ line.end());
+
+ // remove # and following
+ if ((npos = line.find("#")) != std::string::npos)
+ line = line.substr(0, npos);
+
+ if (line.compare(0, 4, "fun:") == 0) {
+
+ is_file = 0;
+ line = line.substr(4);
+
+ } else if (line.compare(0, 9, "function:") == 0) {
+
+ is_file = 0;
+ line = line.substr(9);
+
+ } else if (line.compare(0, 4, "src:") == 0) {
+
+ is_file = 1;
+ line = line.substr(4);
+
+ } else if (line.compare(0, 7, "source:") == 0) {
+
+ is_file = 1;
+ line = line.substr(7);
+
+ }
+
+ if (line.find(":") != std::string::npos) {
+
+ FATAL("invalid line in AFL_GCC_DENYLIST: %s", original_line.c_str());
+
+ }
+
+ if (line.length() > 0) {
+
+ // if the entry contains / or . it must be a file
+ if (is_file == -1)
+ if (line.find("/") != std::string::npos ||
+ line.find(".") != std::string::npos)
+ is_file = 1;
+ // otherwise it is a function
+
+ if (is_file == 1)
+ denyListFiles.push_back(line);
+ else
+ denyListFunctions.push_back(line);
+
+ }
+
+ getline(fileStream, line);
+
+ }
+
+ if (debug)
+ DEBUGF("loaded denylist with %zu file and %zu function entries\n",
+ denyListFiles.size(), denyListFunctions.size());
+
+ }
+
+ }
+
+ /* Returns the source file name attached to the function declaration F. If
+ there is no source location information, returns an empty string. */
+ std::string getSourceName(function *F) {
+
+ return DECL_SOURCE_FILE(F->decl) ? DECL_SOURCE_FILE(F->decl) : "";
+
+ }
+
+ bool isInInstrumentList(function *F) {
+
+ bool return_default = true;
+
+ // is this a function with code? If it is external we don't instrument it
+ // anyway and it can't be in the instrument file list. Or if it is it is
+ // ignored.
+ if (isIgnoreFunction(F)) return false;
+
+ if (!denyListFiles.empty() || !denyListFunctions.empty()) {
+
+ if (!denyListFunctions.empty()) {
+
+ std::string instFunction = IDENTIFIER_POINTER(DECL_NAME(F->decl));
+
+ for (std::list<std::string>::iterator it = denyListFunctions.begin();
+ it != denyListFunctions.end(); ++it) {
+
+ /* We don't check for filename equality here because
+ * filenames might actually be full paths. Instead we
+ * check that the actual filename ends in the filename
+ * specified in the list. We also allow UNIX-style pattern
+ * matching */
+
+ if (instFunction.length() >= it->length()) {
+
+ if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) {
+
+ if (debug)
+ DEBUGF(
+ "Function %s is in the deny function list, not "
+ "instrumenting ... \n",
+ instFunction.c_str());
+ return false;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ if (!denyListFiles.empty()) {
+
+ std::string source_file = getSourceName(F);
+
+ if (!source_file.empty()) {
+
+ for (std::list<std::string>::iterator it = denyListFiles.begin();
+ it != denyListFiles.end(); ++it) {
+
+ /* We don't check for filename equality here because
+ * filenames might actually be full paths. Instead we
+ * check that the actual filename ends in the filename
+ * specified in the list. We also allow UNIX-style pattern
+ * matching */
+
+ if (source_file.length() >= it->length()) {
+
+ if (fnmatch(("*" + *it).c_str(), source_file.c_str(), 0) == 0) {
+
+ return false;
+
+ }
+
+ }
+
+ }
+
+ } else {
+
+ // we could not find out the location. in this case we say it is not
+ // in the instrument file list
+ if (!be_quiet)
+ WARNF(
+ "No debug information found for function %s, will be "
+ "instrumented (recompile with -g -O[1-3]).",
+ IDENTIFIER_POINTER(DECL_NAME(F->decl)));
+
+ }
+
+ }
+
+ }
+
+ // if we do not have a instrument file list return true
+ if (!allowListFiles.empty() || !allowListFunctions.empty()) {
+
+ return_default = false;
+
+ if (!allowListFunctions.empty()) {
+
+ std::string instFunction = IDENTIFIER_POINTER(DECL_NAME(F->decl));
+
+ for (std::list<std::string>::iterator it = allowListFunctions.begin();
+ it != allowListFunctions.end(); ++it) {
+
+ /* We don't check for filename equality here because
+ * filenames might actually be full paths. Instead we
+ * check that the actual filename ends in the filename
+ * specified in the list. We also allow UNIX-style pattern
+ * matching */
+
+ if (instFunction.length() >= it->length()) {
+
+ if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) {
+
+ if (debug)
+ DEBUGF(
+ "Function %s is in the allow function list, instrumenting "
+ "... \n",
+ instFunction.c_str());
+ return true;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ if (!allowListFiles.empty()) {
+
+ std::string source_file = getSourceName(F);
+
+ if (!source_file.empty()) {
+
+ for (std::list<std::string>::iterator it = allowListFiles.begin();
+ it != allowListFiles.end(); ++it) {
+
+ /* We don't check for filename equality here because
+ * filenames might actually be full paths. Instead we
+ * check that the actual filename ends in the filename
+ * specified in the list. We also allow UNIX-style pattern
+ * matching */
+
+ if (source_file.length() >= it->length()) {
+
+ if (fnmatch(("*" + *it).c_str(), source_file.c_str(), 0) == 0) {
+
+ if (debug)
+ DEBUGF(
+ "Function %s is in the allowlist (%s), instrumenting ... "
+ "\n",
+ IDENTIFIER_POINTER(DECL_NAME(F->decl)),
+ source_file.c_str());
+ return true;
+
+ }
+
+ }
+
+ }
+
+ } else {
+
+ // we could not find out the location. In this case we say it is not
+ // in the instrument file list
+ if (!be_quiet)
+ WARNF(
+ "No debug information found for function %s, will not be "
+ "instrumented (recompile with -g -O[1-3]).",
+ IDENTIFIER_POINTER(DECL_NAME(F->decl)));
+ return false;
+
+ }
+
+ }
+
+ }
+
+ return return_default;
+
+ }
+
+};
+
+} // namespace
+
+// compatibility for older gcc versions
+#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= \
+ 60200 /* >= version 6.2.0 */
+ #define gimple gimple *
+#else
+ #define gimple gimple
+#endif
+
diff --git a/instrumentation/afl-llvm-common.cc b/instrumentation/afl-llvm-common.cc
index 9483da83..7f17b02d 100644
--- a/instrumentation/afl-llvm-common.cc
+++ b/instrumentation/afl-llvm-common.cc
@@ -12,6 +12,7 @@
#include <list>
#include <string>
#include <fstream>
+#include <cmath>
#include <llvm/Support/raw_ostream.h>
@@ -288,10 +289,11 @@ void scanForDangerousFunctions(llvm::Module *M) {
StringRef ifunc_name = IF.getName();
Constant *r = IF.getResolver();
+ if (r->getNumOperands() == 0) { continue; }
StringRef r_name = cast<Function>(r->getOperand(0))->getName();
if (!be_quiet)
fprintf(stderr,
- "Info: Found an ifunc with name %s that points to resolver "
+ "Note: Found an ifunc with name %s that points to resolver "
"function %s, we will not instrument this, putting it into the "
"block list.\n",
ifunc_name.str().c_str(), r_name.str().c_str());
@@ -329,7 +331,7 @@ void scanForDangerousFunctions(llvm::Module *M) {
if (!be_quiet)
fprintf(stderr,
- "Info: Found constructor function %s with prio "
+ "Note: Found constructor function %s with prio "
"%u, we will not instrument this, putting it into a "
"block list.\n",
F->getName().str().c_str(), Priority);
@@ -582,7 +584,7 @@ bool isInInstrumentList(llvm::Function *F, std::string Filename) {
}
// Calculate the number of average collisions that would occur if all
-// location IDs would be assigned randomly (like normal afl/afl++).
+// location IDs would be assigned randomly (like normal afl/AFL++).
// This uses the "balls in bins" algorithm.
unsigned long long int calculateCollisions(uint32_t edges) {
diff --git a/instrumentation/afl-llvm-common.h b/instrumentation/afl-llvm-common.h
index dee5f9fc..23f67179 100644
--- a/instrumentation/afl-llvm-common.h
+++ b/instrumentation/afl-llvm-common.h
@@ -8,6 +8,7 @@
#include <list>
#include <string>
#include <fstream>
+#include <optional>
#include <sys/time.h>
#include "llvm/Config/llvm-config.h"
@@ -21,7 +22,9 @@ typedef long double max_align_t;
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
-#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#if LLVM_VERSION_MAJOR < 17
+ #include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#endif
#if LLVM_VERSION_MAJOR > 3 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
@@ -35,6 +38,12 @@ typedef long double max_align_t;
#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("")
diff --git a/instrumentation/afl-llvm-dict2file.so.cc b/instrumentation/afl-llvm-dict2file.so.cc
index 31aaab07..8ee13010 100644
--- a/instrumentation/afl-llvm-dict2file.so.cc
+++ b/instrumentation/afl-llvm-dict2file.so.cc
@@ -4,7 +4,7 @@
Written by Marc Heuse <mh@mh-sec.de>
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -53,7 +53,9 @@
#include "llvm/IR/Verifier.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#if LLVM_VERSION_MAJOR < 17
+ #include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#endif
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/ValueTracking.h"
@@ -181,8 +183,8 @@ bool AFLdict2filePass::runOnModule(Module &M) {
#endif
DenseMap<Value *, std::string *> valueMap;
- char * ptr;
- int found = 0;
+ char *ptr;
+ int found = 0, handle_main = 1;
/* Show a banner */
setvbuf(stdout, NULL, _IONBF, 0);
@@ -192,10 +194,14 @@ bool AFLdict2filePass::runOnModule(Module &M) {
SAYF(cCYA "afl-llvm-dict2file" VERSION cRST
" by Marc \"vanHauser\" Heuse <mh@mh-sec.de>\n");
- } else
+ } else {
be_quiet = 1;
+ }
+
+ if (getenv("AFL_LLVM_DICT2FILE_NO_MAIN")) { handle_main = 0; }
+
scanForDangerousFunctions(&M);
ptr = getenv("AFL_LLVM_DICT2FILE");
@@ -210,7 +216,14 @@ bool AFLdict2filePass::runOnModule(Module &M) {
for (auto &F : M) {
- if (isIgnoreFunction(&F)) continue;
+ if (!handle_main &&
+ (!F.getName().compare("main") || !F.getName().compare("_main"))) {
+
+ continue;
+
+ }
+
+ if (isIgnoreFunction(&F)) { continue; }
if (!isInInstrumentList(&F, MNAME) || !F.size()) { continue; }
/* Some implementation notes.
@@ -246,11 +259,11 @@ bool AFLdict2filePass::runOnModule(Module &M) {
for (auto &IN : BB) {
CallInst *callInst = nullptr;
- CmpInst * cmpInst = nullptr;
+ CmpInst *cmpInst = nullptr;
if ((cmpInst = dyn_cast<CmpInst>(&IN))) {
- Value * op = cmpInst->getOperand(1);
+ Value *op = cmpInst->getOperand(1);
ConstantInt *ilen = dyn_cast<ConstantInt>(op);
/* We skip > 64 bit integers. why? first because their value is
@@ -518,7 +531,7 @@ bool AFLdict2filePass::runOnModule(Module &M) {
if (HasStr2 == true) {
- Value * op2 = callInst->getArgOperand(2);
+ Value *op2 = callInst->getArgOperand(2);
ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
if (ilen) {
@@ -631,7 +644,7 @@ bool AFLdict2filePass::runOnModule(Module &M) {
if (isMemcmp || isStrncmp || isStrncasecmp) {
- Value * op2 = callInst->getArgOperand(2);
+ Value *op2 = callInst->getArgOperand(2);
ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
if (ilen) {
@@ -733,7 +746,7 @@ static void registerAFLdict2filePass(const PassManagerBuilder &,
}
static RegisterPass<AFLdict2filePass> X("afl-dict2file",
- "afl++ dict2file instrumentation pass",
+ "AFL++ dict2file instrumentation pass",
false, false);
static RegisterStandardPasses RegisterAFLdict2filePass(
diff --git a/instrumentation/afl-llvm-lto-instrumentlist.so.cc b/instrumentation/afl-llvm-lto-instrumentlist.so.cc
index 70c6b10d..61f97d77 100644
--- a/instrumentation/afl-llvm-lto-instrumentlist.so.cc
+++ b/instrumentation/afl-llvm-lto-instrumentlist.so.cc
@@ -9,7 +9,7 @@
from afl-as.c are Michal's fault.
Copyright 2015, 2016 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -45,7 +45,7 @@
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
-//#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+// #include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/IR/PassManager.h"
@@ -101,7 +101,7 @@ llvmGetPassPluginInfo() {
}
-PreservedAnalyses AFLcheckIfInstrument::run(Module & M,
+PreservedAnalyses AFLcheckIfInstrument::run(Module &M,
ModuleAnalysisManager &MAM) {
/* Show a banner */
@@ -135,7 +135,7 @@ PreservedAnalyses AFLcheckIfInstrument::run(Module & M,
DEBUGF("function %s is NOT in the instrument file list\n",
F.getName().str().c_str());
- auto & Ctx = F.getContext();
+ auto &Ctx = F.getContext();
AttributeList Attrs = F.getAttributes();
#if LLVM_VERSION_MAJOR >= 14
AttributeList NewAttrs = Attrs.addFnAttribute(Ctx, "skipinstrument");
diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc
index fde785bd..c59324fd 100644
--- a/instrumentation/afl-llvm-pass.so.cc
+++ b/instrumentation/afl-llvm-pass.so.cc
@@ -12,7 +12,7 @@
NGRAM previous location coverage comes from Adrian Herrera.
Copyright 2015, 2016 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -251,7 +251,7 @@ bool AFLCoverage::runOnModule(Module &M) {
/* Decide instrumentation ratio */
- char * inst_ratio_str = getenv("AFL_INST_RATIO");
+ char *inst_ratio_str = getenv("AFL_INST_RATIO");
unsigned int inst_ratio = 100;
if (inst_ratio_str) {
@@ -413,7 +413,7 @@ bool AFLCoverage::runOnModule(Module &M) {
GlobalVariable *AFLContext = NULL;
if (ctx_str || caller_str)
-#if defined(__ANDROID__) || defined(__HAIKU__)
+#if defined(__ANDROID__) || defined(__HAIKU__) || defined(NO_TLS)
AFLContext = new GlobalVariable(
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx");
#else
@@ -424,7 +424,7 @@ bool AFLCoverage::runOnModule(Module &M) {
#ifdef AFL_HAVE_VECTOR_INTRINSICS
if (ngram_size)
- #if defined(__ANDROID__) || defined(__HAIKU__)
+ #if defined(__ANDROID__) || defined(__HAIKU__) || defined(NO_TLS)
AFLPrevLoc = new GlobalVariable(
M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
/* Initializer */ nullptr, "__afl_prev_loc");
@@ -437,7 +437,7 @@ bool AFLCoverage::runOnModule(Module &M) {
#endif
else
#endif
-#if defined(__ANDROID__) || defined(__HAIKU__)
+#if defined(__ANDROID__) || defined(__HAIKU__) || defined(NO_TLS)
AFLPrevLoc = new GlobalVariable(
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc");
#else
@@ -448,7 +448,7 @@ bool AFLCoverage::runOnModule(Module &M) {
#ifdef AFL_HAVE_VECTOR_INTRINSICS
if (ctx_k)
- #if defined(__ANDROID__) || defined(__HAIKU__)
+ #if defined(__ANDROID__) || defined(__HAIKU__) || defined(NO_TLS)
AFLPrevCaller = new GlobalVariable(
M, PrevCallerTy, /* isConstant */ false, GlobalValue::ExternalLinkage,
/* Initializer */ nullptr, "__afl_prev_caller");
@@ -461,7 +461,7 @@ bool AFLCoverage::runOnModule(Module &M) {
#endif
else
#endif
-#if defined(__ANDROID__) || defined(__HAIKU__)
+#if defined(__ANDROID__) || defined(__HAIKU__) || defined(NO_TLS)
AFLPrevCaller =
new GlobalVariable(M, Int32Ty, false, GlobalValue::ExternalLinkage, 0,
"__afl_prev_caller");
@@ -486,7 +486,7 @@ bool AFLCoverage::runOnModule(Module &M) {
Constant *PrevLocShuffleMask = ConstantVector::get(PrevLocShuffle);
- Constant * PrevCallerShuffleMask = NULL;
+ Constant *PrevCallerShuffleMask = NULL;
SmallVector<Constant *, 32> PrevCallerShuffle = {UndefValue::get(Int32Ty)};
if (ctx_k) {
@@ -506,7 +506,7 @@ bool AFLCoverage::runOnModule(Module &M) {
// other constants we need
ConstantInt *One = ConstantInt::get(Int8Ty, 1);
- Value * PrevCtx = NULL; // CTX sensitive coverage
+ Value *PrevCtx = NULL; // CTX sensitive coverage
LoadInst *PrevCaller = NULL; // K-CTX coverage
/* Instrument all the things! */
diff --git a/instrumentation/cmplog-instructions-pass.cc b/instrumentation/cmplog-instructions-pass.cc
index 4d37bcb2..bca1f927 100644
--- a/instrumentation/cmplog-instructions-pass.cc
+++ b/instrumentation/cmplog-instructions-pass.cc
@@ -5,7 +5,7 @@
Written by Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2015, 2016 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -156,9 +156,9 @@ Iterator Unique(Iterator first, Iterator last) {
bool CmpLogInstructions::hookInstrs(Module &M) {
std::vector<Instruction *> icomps;
- LLVMContext & C = M.getContext();
+ LLVMContext &C = M.getContext();
- Type * VoidTy = Type::getVoidTy(C);
+ Type *VoidTy = Type::getVoidTy(C);
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
IntegerType *Int16Ty = IntegerType::getInt16Ty(C);
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
@@ -338,7 +338,7 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
IntegerType *intTyOp1 = NULL;
unsigned max_size = 0, cast_size = 0;
unsigned attr = 0, vector_cnt = 0, is_fp = 0;
- CmpInst * cmpInst = dyn_cast<CmpInst>(selectcmpInst);
+ CmpInst *cmpInst = dyn_cast<CmpInst>(selectcmpInst);
if (!cmpInst) { continue; }
@@ -666,7 +666,7 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
}
#if LLVM_MAJOR >= 11 /* use new pass manager */
-PreservedAnalyses CmpLogInstructions::run(Module & M,
+PreservedAnalyses CmpLogInstructions::run(Module &M,
ModuleAnalysisManager &MAM) {
#else
diff --git a/instrumentation/cmplog-routines-pass.cc b/instrumentation/cmplog-routines-pass.cc
index 8205cfb0..c3fbed8d 100644
--- a/instrumentation/cmplog-routines-pass.cc
+++ b/instrumentation/cmplog-routines-pass.cc
@@ -5,7 +5,7 @@
Written by Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2015, 2016 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -38,7 +38,9 @@
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#if LLVM_VERSION_MAJOR < 17
+ #include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#endif
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Pass.h"
#include "llvm/Analysis/ValueTracking.h"
@@ -506,8 +508,8 @@ bool CmpLogRoutines::hookRtns(Module &M) {
IRBuilder<> IRB(ThenTerm);
std::vector<Value *> args;
- Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
- Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
+ Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
+ Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
args.push_back(v1Pcasted);
args.push_back(v2Pcasted);
@@ -537,9 +539,9 @@ bool CmpLogRoutines::hookRtns(Module &M) {
IRBuilder<> IRB(ThenTerm);
std::vector<Value *> args;
- Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
- Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
- Value * v3Pbitcast = IRB.CreateBitCast(
+ Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
+ Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
+ Value *v3Pbitcast = IRB.CreateBitCast(
v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits()));
Value *v3Pcasted =
IRB.CreateIntCast(v3Pbitcast, IntegerType::get(C, 64), false);
@@ -572,8 +574,8 @@ bool CmpLogRoutines::hookRtns(Module &M) {
IRBuilder<> IRB(ThenTerm);
std::vector<Value *> args;
- Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
- Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
+ Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
+ Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
args.push_back(v1Pcasted);
args.push_back(v2Pcasted);
@@ -603,9 +605,9 @@ bool CmpLogRoutines::hookRtns(Module &M) {
IRBuilder<> IRB(ThenTerm);
std::vector<Value *> args;
- Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
- Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
- Value * v3Pbitcast = IRB.CreateBitCast(
+ Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
+ Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
+ Value *v3Pbitcast = IRB.CreateBitCast(
v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits()));
Value *v3Pcasted =
IRB.CreateIntCast(v3Pbitcast, IntegerType::get(C, 64), false);
@@ -638,8 +640,8 @@ bool CmpLogRoutines::hookRtns(Module &M) {
IRBuilder<> IRB(ThenTerm);
std::vector<Value *> args;
- Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
- Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
+ Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
+ Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
args.push_back(v1Pcasted);
args.push_back(v2Pcasted);
@@ -668,8 +670,8 @@ bool CmpLogRoutines::hookRtns(Module &M) {
IRBuilder<> IRB(ThenTerm);
std::vector<Value *> args;
- Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
- Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
+ Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
+ Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
args.push_back(v1Pcasted);
args.push_back(v2Pcasted);
@@ -698,8 +700,8 @@ bool CmpLogRoutines::hookRtns(Module &M) {
IRBuilder<> IRB(ThenTerm);
std::vector<Value *> args;
- Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
- Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
+ Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
+ Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
args.push_back(v1Pcasted);
args.push_back(v2Pcasted);
@@ -728,8 +730,8 @@ bool CmpLogRoutines::hookRtns(Module &M) {
IRBuilder<> IRB(ThenTerm);
std::vector<Value *> args;
- Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
- Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
+ Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
+ Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
args.push_back(v1Pcasted);
args.push_back(v2Pcasted);
diff --git a/instrumentation/cmplog-switches-pass.cc b/instrumentation/cmplog-switches-pass.cc
index 37bf3889..38de669d 100644
--- a/instrumentation/cmplog-switches-pass.cc
+++ b/instrumentation/cmplog-switches-pass.cc
@@ -5,7 +5,7 @@
Written by Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2015, 2016 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -39,7 +39,9 @@
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#if LLVM_VERSION_MAJOR < 17
+ #include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#endif
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Pass.h"
#include "llvm/Analysis/ValueTracking.h"
@@ -149,9 +151,9 @@ Iterator Unique(Iterator first, Iterator last) {
bool CmplogSwitches::hookInstrs(Module &M) {
std::vector<SwitchInst *> switches;
- LLVMContext & C = M.getContext();
+ LLVMContext &C = M.getContext();
- Type * VoidTy = Type::getVoidTy(C);
+ Type *VoidTy = Type::getVoidTy(C);
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
IntegerType *Int16Ty = IntegerType::getInt16Ty(C);
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
@@ -270,7 +272,7 @@ bool CmplogSwitches::hookInstrs(Module &M) {
for (auto &SI : switches) {
- Value * Val = SI->getCondition();
+ Value *Val = SI->getCondition();
unsigned int max_size = Val->getType()->getIntegerBitWidth(), cast_size;
unsigned char do_cast = 0;
diff --git a/instrumentation/compare-transform-pass.so.cc b/instrumentation/compare-transform-pass.so.cc
index 34c88735..5dd705cf 100644
--- a/instrumentation/compare-transform-pass.so.cc
+++ b/instrumentation/compare-transform-pass.so.cc
@@ -168,10 +168,10 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
DenseMap<Value *, std::string *> valueMap;
std::vector<CallInst *> calls;
- LLVMContext & C = M.getContext();
- IntegerType * Int8Ty = IntegerType::getInt8Ty(C);
- IntegerType * Int32Ty = IntegerType::getInt32Ty(C);
- IntegerType * Int64Ty = IntegerType::getInt64Ty(C);
+ LLVMContext &C = M.getContext();
+ IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
+ IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
+ IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee tolowerFn;
@@ -409,7 +409,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
/* check if third operand is a constant integer
* strlen("constStr") and sizeof() are treated as constant */
- Value * op2 = callInst->getArgOperand(2);
+ Value *op2 = callInst->getArgOperand(2);
ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
if (ilen) {
@@ -449,7 +449,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
*Str2P = callInst->getArgOperand(1);
StringRef Str1, Str2, ConstStr;
std::string TmpConstStr;
- Value * VarStr;
+ Value *VarStr;
bool HasStr1 = getConstantStringInfo(Str1P, Str1);
bool HasStr2 = getConstantStringInfo(Str2P, Str2);
uint64_t constStrLen, unrollLen, constSizedLen = 0;
@@ -457,7 +457,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
bool isSizedcmp = false;
bool isCaseInsensitive = false;
bool needs_null = false;
- Function * Callee = callInst->getCalledFunction();
+ Function *Callee = callInst->getCalledFunction();
if (Callee) {
@@ -616,13 +616,13 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
for (uint64_t i = 0; i < unrollLen; i++) {
- BasicBlock * cur_cmp_bb = next_cmp_bb, *cur_lenchk_bb = next_lenchk_bb;
+ BasicBlock *cur_cmp_bb = next_cmp_bb, *cur_lenchk_bb = next_lenchk_bb;
unsigned char c;
if (cur_lenchk_bb) {
IRBuilder<> cur_lenchk_IRB(&*(cur_lenchk_bb->getFirstInsertionPt()));
- Value * icmp = cur_lenchk_IRB.CreateICmpEQ(
+ Value *icmp = cur_lenchk_IRB.CreateICmpEQ(
sizedValue, ConstantInt::get(sizedValue->getType(), i));
cur_lenchk_IRB.CreateCondBr(icmp, end_bb, cur_cmp_bb);
cur_lenchk_bb->getTerminator()->eraseFromParent();
@@ -708,7 +708,11 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
/* since the call is the first instruction of the bb it is safe to
* replace it with a phi instruction */
BasicBlock::iterator ii(callInst);
+#if LLVM_MAJOR >= 16
+ ReplaceInstWithInst(callInst->getParent(), ii, PN);
+#else
ReplaceInstWithInst(callInst->getParent()->getInstList(), ii, PN);
+#endif
}
diff --git a/instrumentation/split-compares-pass.so.cc b/instrumentation/split-compares-pass.so.cc
index d7bb7aba..aec6758e 100644
--- a/instrumentation/split-compares-pass.so.cc
+++ b/instrumentation/split-compares-pass.so.cc
@@ -60,7 +60,7 @@ using namespace llvm;
// uncomment this toggle function verification at each step. horribly slow, but
// helps to pinpoint a potential problem in the splitting code.
-//#define VERIFY_TOO_MUCH 1
+// #define VERIFY_TOO_MUCH 1
namespace {
@@ -230,9 +230,9 @@ char SplitComparesTransform::ID = 0;
/// FCMP instructions with predicate xGT or xLT and EQ
bool SplitComparesTransform::simplifyFPCompares(Module &M) {
- LLVMContext & C = M.getContext();
+ LLVMContext &C = M.getContext();
std::vector<Instruction *> fcomps;
- IntegerType * Int1Ty = IntegerType::getInt1Ty(C);
+ IntegerType *Int1Ty = IntegerType::getInt1Ty(C);
/* iterate over all functions, bbs and instruction and add
* all integer comparisons with >= and <= predicates to the icomps vector */
@@ -322,8 +322,12 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) {
* block bb it is now at the position where the old FcmpInst was */
Instruction *fcmp_np;
fcmp_np = CmpInst::Create(Instruction::FCmp, new_pred, op0, op1);
+#if LLVM_MAJOR >= 16
+ fcmp_np->insertInto(bb, BasicBlock::iterator(bb->getTerminator()));
+#else
bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()),
fcmp_np);
+#endif
/* create a new basic block which holds the new EQ fcmp */
Instruction *fcmp_eq;
@@ -331,7 +335,11 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) {
BasicBlock *middle_bb =
BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb);
fcmp_eq = CmpInst::Create(Instruction::FCmp, CmpInst::FCMP_OEQ, op0, op1);
+#if LLVM_MAJOR >= 16
+ fcmp_eq->insertInto(middle_bb, middle_bb->end());
+#else
middle_bb->getInstList().push_back(fcmp_eq);
+#endif
/* add an unconditional branch to the end of middle_bb with destination
* end_bb */
BranchInst::Create(end_bb, middle_bb);
@@ -352,7 +360,11 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) {
PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb);
/* replace the old FcmpInst with our new and shiny PHI inst */
BasicBlock::iterator ii(FcmpInst);
+#if LLVM_MAJOR >= 16
+ ReplaceInstWithInst(FcmpInst->getParent(), ii, PN);
+#else
ReplaceInstWithInst(FcmpInst->getParent()->getInstList(), ii, PN);
+#endif
}
@@ -362,8 +374,8 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) {
/// This function splits ICMP instructions with xGE or xLE predicates into two
/// ICMP instructions with predicate xGT or xLT and EQ
-bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst * IcmpInst,
- Module & M,
+bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst *IcmpInst,
+ Module &M,
CmpWorklist &worklist) {
LLVMContext &C = M.getContext();
@@ -409,7 +421,11 @@ bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst * IcmpInst,
/* create the ICMP instruction with new_pred and add it to the old basic
* block bb it is now at the position where the old IcmpInst was */
CmpInst *icmp_np = CmpInst::Create(Instruction::ICmp, new_pred, op0, op1);
+#if LLVM_MAJOR >= 16
+ icmp_np->insertInto(bb, BasicBlock::iterator(bb->getTerminator()));
+#else
bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), icmp_np);
+#endif
/* create a new basic block which holds the new EQ icmp */
CmpInst *icmp_eq;
@@ -417,7 +433,11 @@ bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst * IcmpInst,
BasicBlock *middle_bb =
BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb);
icmp_eq = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, op0, op1);
+#if LLVM_MAJOR >= 16
+ icmp_eq->insertInto(middle_bb, middle_bb->end());
+#else
middle_bb->getInstList().push_back(icmp_eq);
+#endif
/* add an unconditional branch to the end of middle_bb with destination
* end_bb */
BranchInst::Create(end_bb, middle_bb);
@@ -438,7 +458,11 @@ bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst * IcmpInst,
PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb);
/* replace the old IcmpInst with our new and shiny PHI inst */
BasicBlock::iterator ii(IcmpInst);
+#if LLVM_MAJOR >= 16
+ ReplaceInstWithInst(IcmpInst->getParent(), ii, PN);
+#else
ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN);
+#endif
worklist.push_back(icmp_np);
worklist.push_back(icmp_eq);
@@ -498,7 +522,7 @@ bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M,
/* create a new basic block which is executed if the signedness bit is
* different */
- CmpInst * icmp_inv_sig_cmp;
+ CmpInst *icmp_inv_sig_cmp;
BasicBlock *sign_bb =
BasicBlock::Create(C, "sign", end_bb->getParent(), end_bb);
if (pred == CmpInst::ICMP_SGT) {
@@ -518,17 +542,25 @@ bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M,
}
+#if LLVM_MAJOR >= 16
+ icmp_inv_sig_cmp->insertInto(sign_bb, sign_bb->end());
+#else
sign_bb->getInstList().push_back(icmp_inv_sig_cmp);
+#endif
BranchInst::Create(end_bb, sign_bb);
/* create a new bb which is executed if signedness is equal */
- CmpInst * icmp_usign_cmp;
+ CmpInst *icmp_usign_cmp;
BasicBlock *middle_bb =
BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb);
/* we can do a normal unsigned compare now */
icmp_usign_cmp = CmpInst::Create(Instruction::ICmp, new_pred, op0, op1);
+#if LLVM_MAJOR >= 16
+ icmp_usign_cmp->insertInto(middle_bb, middle_bb->end());
+#else
middle_bb->getInstList().push_back(icmp_usign_cmp);
+#endif
BranchInst::Create(end_bb, middle_bb);
auto term = bb->getTerminator();
@@ -543,7 +575,11 @@ bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M,
PN->addIncoming(icmp_inv_sig_cmp, sign_bb);
BasicBlock::iterator ii(IcmpInst);
+#if LLVM_MAJOR >= 16
+ ReplaceInstWithInst(IcmpInst->getParent(), ii, PN);
+#else
ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN);
+#endif
// save for later
worklist.push_back(icmp_usign_cmp);
@@ -566,8 +602,17 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M,
case CmpInst::ICMP_NE:
case CmpInst::ICMP_UGT:
case CmpInst::ICMP_ULT:
+ case CmpInst::ICMP_UGE:
+ case CmpInst::ICMP_ULE:
+ case CmpInst::ICMP_SGT:
+ case CmpInst::ICMP_SLT:
+ case CmpInst::ICMP_SGE:
+ case CmpInst::ICMP_SLE:
break;
default:
+ if (!be_quiet)
+ fprintf(stderr, "Error: split-compare: Unsupported predicate (%u)\n",
+ pred);
// unsupported predicate!
return false;
@@ -581,6 +626,8 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M,
if (!intTyOp0) {
// not an integer type
+ if (!be_quiet)
+ fprintf(stderr, "Error: split-compare: not an integer type\n");
return false;
}
@@ -595,11 +642,11 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M,
LLVMContext &C = M.getContext();
IntegerType *Int1Ty = IntegerType::getInt1Ty(C);
- BasicBlock * bb = cmp_inst->getParent();
+ BasicBlock *bb = cmp_inst->getParent();
IntegerType *OldIntType = IntegerType::get(C, bitw);
IntegerType *NewIntType = IntegerType::get(C, bitw / 2);
- BasicBlock * end_bb = bb->splitBasicBlock(BasicBlock::iterator(cmp_inst));
- CmpInst * icmp_high, *icmp_low;
+ BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(cmp_inst));
+ CmpInst *icmp_high, *icmp_low;
/* create the comparison of the top halves of the original operands */
Value *s_op0, *op0_high, *s_op1, *op1_high;
@@ -629,7 +676,7 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M,
BasicBlock *cmp_low_bb =
BasicBlock::Create(C, "" /*"injected"*/, end_bb->getParent(), end_bb);
- Value * op0_low, *op1_low;
+ Value *op0_low, *op1_low;
IRBuilder<> Builder(cmp_low_bb);
op0_low = Builder.CreateTrunc(op0, NewIntType);
@@ -675,6 +722,12 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M,
}
+ case CmpInst::ICMP_SGE:
+ case CmpInst::ICMP_SLE:
+ case CmpInst::ICMP_SGT:
+ case CmpInst::ICMP_SLT:
+ case CmpInst::ICMP_UGE:
+ case CmpInst::ICMP_ULE:
case CmpInst::ICMP_UGT:
case CmpInst::ICMP_ULT: {
@@ -684,10 +737,11 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M,
* if this is true we can go to the end if not we have to go to the
* bb which checks the lower half of the operands */
Instruction *op0_low, *op1_low;
- CmpInst * icmp_inv_cmp = nullptr;
- BasicBlock * inv_cmp_bb =
+ CmpInst *icmp_inv_cmp = nullptr;
+ BasicBlock *inv_cmp_bb =
BasicBlock::Create(C, "inv_cmp", end_bb->getParent(), end_bb);
- if (pred == CmpInst::ICMP_UGT) {
+ if (pred == CmpInst::ICMP_UGT || pred == CmpInst::ICMP_SGT ||
+ pred == CmpInst::ICMP_UGE || pred == CmpInst::ICMP_SGE) {
icmp_inv_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT,
op0_high, op1_high);
@@ -699,7 +753,11 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M,
}
+#if LLVM_MAJOR >= 16
+ icmp_inv_cmp->insertInto(inv_cmp_bb, inv_cmp_bb->end());
+#else
inv_cmp_bb->getInstList().push_back(icmp_inv_cmp);
+#endif
worklist.push_back(icmp_inv_cmp);
auto term = bb->getTerminator();
@@ -710,12 +768,18 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M,
BasicBlock *cmp_low_bb =
BasicBlock::Create(C, "" /*"injected"*/, end_bb->getParent(), end_bb);
op0_low = new TruncInst(op0, NewIntType);
- cmp_low_bb->getInstList().push_back(op0_low);
op1_low = new TruncInst(op1, NewIntType);
- cmp_low_bb->getInstList().push_back(op1_low);
-
icmp_low = CmpInst::Create(Instruction::ICmp, pred, op0_low, op1_low);
+
+#if LLVM_MAJOR >= 16
+ op0_low->insertInto(cmp_low_bb, cmp_low_bb->end());
+ op1_low->insertInto(cmp_low_bb, cmp_low_bb->end());
+ icmp_low->insertInto(cmp_low_bb, cmp_low_bb->end());
+#else
+ cmp_low_bb->getInstList().push_back(op0_low);
+ cmp_low_bb->getInstList().push_back(op1_low);
cmp_low_bb->getInstList().push_back(icmp_low);
+#endif
BranchInst::Create(end_bb, cmp_low_bb);
BranchInst::Create(end_bb, cmp_low_bb, icmp_inv_cmp, inv_cmp_bb);
@@ -729,12 +793,18 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M,
}
default:
+ if (!be_quiet)
+ fprintf(stderr, "Error: split-compare: should not happen\n");
return false;
}
BasicBlock::iterator ii(cmp_inst);
+#if LLVM_MAJOR >= 16
+ ReplaceInstWithInst(cmp_inst->getParent(), ii, PN);
+#else
ReplaceInstWithInst(cmp_inst->getParent()->getInstList(), ii, PN);
+#endif
// We split the comparison into low and high. If this isn't our target
// bitwidth we recursively split the low and high parts again until we have
@@ -944,7 +1014,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
// BUG FIXME TODO: u64 does not work for > 64 bit ... e.g. 80 and 128 bit
if (sizeInBits > 64) { continue; }
- IntegerType * intType = IntegerType::get(C, op_size);
+ IntegerType *intType = IntegerType::get(C, op_size);
const unsigned int precision = sizeInBits == 32 ? 24
: sizeInBits == 64 ? 53
: sizeInBits == 128 ? 113
@@ -979,13 +1049,21 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
Instruction *bpre_op0, *bpre_op1;
bpre_op0 = CastInst::Create(Instruction::BitCast, op0,
IntegerType::get(C, op_size));
+#if LLVM_MAJOR >= 16
+ bpre_op0->insertInto(bb, BasicBlock::iterator(bb->getTerminator()));
+#else
bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()),
bpre_op0);
+#endif
bpre_op1 = CastInst::Create(Instruction::BitCast, op1,
IntegerType::get(C, op_size));
+#if LLVM_MAJOR >= 16
+ bpre_op1->insertInto(bb, BasicBlock::iterator(bb->getTerminator()));
+#else
bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()),
bpre_op1);
+#endif
/* Check if any operand is NaN.
* If so, all comparisons except unequal (which yields true) yield false */
@@ -1005,34 +1083,42 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
Instruction *nan_op0, *nan_op1;
nan_op0 = BinaryOperator::Create(Instruction::Shl, bpre_op0,
ConstantInt::get(bpre_op0->getType(), 1));
- bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()),
- nan_op0);
-
+ /* Check op1 for NaN */
+ /* Shift right 1 Bit, ignore sign bit */
+ nan_op1 = BinaryOperator::Create(Instruction::Shl, bpre_op1,
+ ConstantInt::get(bpre_op1->getType(), 1));
/* compare to NaN interval */
Instruction *is_op0_nan =
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, nan_op0,
ConstantInt::get(intType, NaN_lowend));
+ /* compare to NaN interval */
+ Instruction *is_op1_nan =
+ CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, nan_op1,
+ ConstantInt::get(intType, NaN_lowend));
+ /* combine checks */
+ Instruction *is_nan =
+ BinaryOperator::Create(Instruction::Or, is_op0_nan, is_op1_nan);
+#if LLVM_MAJOR >= 16
+ nan_op0->insertInto(bb, BasicBlock::iterator(bb->getTerminator()));
+ is_op0_nan->insertInto(bb, BasicBlock::iterator(bb->getTerminator()));
+ nan_op1->insertInto(bb, BasicBlock::iterator(bb->getTerminator()));
+ is_op1_nan->insertInto(bb, BasicBlock::iterator(bb->getTerminator()));
+ is_nan->insertInto(bb, BasicBlock::iterator(bb->getTerminator()));
+#else
+ bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()),
+ nan_op0);
+
bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()),
is_op0_nan);
- /* Check op1 for NaN */
- /* Shift right 1 Bit, ignore sign bit */
- nan_op1 = BinaryOperator::Create(Instruction::Shl, bpre_op1,
- ConstantInt::get(bpre_op1->getType(), 1));
bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()),
nan_op1);
- /* compare to NaN interval */
- Instruction *is_op1_nan =
- CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, nan_op1,
- ConstantInt::get(intType, NaN_lowend));
bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()),
is_op1_nan);
- /* combine checks */
- Instruction *is_nan =
- BinaryOperator::Create(Instruction::Or, is_op0_nan, is_op1_nan);
bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), is_nan);
+#endif
/* the result of the comparison, when at least one op is NaN
is true only for the "NOT EQUAL" predicates. */
@@ -1052,30 +1138,41 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
/*** now working in nonan_bb ***/
/* Treat -0.0 as equal to +0.0, that is for -0.0 make it +0.0 */
- Instruction * b_op0, *b_op1;
- Instruction * isMzero_op0, *isMzero_op1;
+ Instruction *b_op0, *b_op1;
+ Instruction *isMzero_op0, *isMzero_op1;
const unsigned long long MinusZero = 1UL << (sizeInBits - 1U);
const unsigned long long PlusZero = 0;
isMzero_op0 = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, bpre_op0,
ConstantInt::get(intType, MinusZero));
+ isMzero_op1 = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, bpre_op1,
+ ConstantInt::get(intType, MinusZero));
+ b_op0 = SelectInst::Create(isMzero_op0, ConstantInt::get(intType, PlusZero),
+ bpre_op0);
+ b_op1 = SelectInst::Create(isMzero_op1, ConstantInt::get(intType, PlusZero),
+ bpre_op1);
+#if LLVM_MAJOR >= 16
+ isMzero_op0->insertInto(nonan_bb,
+ BasicBlock::iterator(nonan_bb->getTerminator()));
+ isMzero_op1->insertInto(nonan_bb,
+ BasicBlock::iterator(nonan_bb->getTerminator()));
+ b_op0->insertInto(nonan_bb,
+ BasicBlock::iterator(nonan_bb->getTerminator()));
+ b_op1->insertInto(nonan_bb,
+ BasicBlock::iterator(nonan_bb->getTerminator()));
+#else
nonan_bb->getInstList().insert(
BasicBlock::iterator(nonan_bb->getTerminator()), isMzero_op0);
- isMzero_op1 = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, bpre_op1,
- ConstantInt::get(intType, MinusZero));
nonan_bb->getInstList().insert(
BasicBlock::iterator(nonan_bb->getTerminator()), isMzero_op1);
- b_op0 = SelectInst::Create(isMzero_op0, ConstantInt::get(intType, PlusZero),
- bpre_op0);
nonan_bb->getInstList().insert(
BasicBlock::iterator(nonan_bb->getTerminator()), b_op0);
- b_op1 = SelectInst::Create(isMzero_op1, ConstantInt::get(intType, PlusZero),
- bpre_op1);
nonan_bb->getInstList().insert(
BasicBlock::iterator(nonan_bb->getTerminator()), b_op1);
+#endif
/* isolate signs of value of floating point type */
@@ -1086,26 +1183,35 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
s_s0 =
BinaryOperator::Create(Instruction::LShr, b_op0,
ConstantInt::get(b_op0->getType(), op_size - 1));
+ s_s1 =
+ BinaryOperator::Create(Instruction::LShr, b_op1,
+ ConstantInt::get(b_op1->getType(), op_size - 1));
+ t_s0 = new TruncInst(s_s0, Int1Ty);
+ t_s1 = new TruncInst(s_s1, Int1Ty);
+ /* compare of the sign bits */
+ icmp_sign_bit =
+ CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, t_s0, t_s1);
+#if LLVM_MAJOR >= 16
+ s_s0->insertInto(nonan_bb, BasicBlock::iterator(nonan_bb->getTerminator()));
+ t_s0->insertInto(nonan_bb, BasicBlock::iterator(nonan_bb->getTerminator()));
+ s_s1->insertInto(nonan_bb, BasicBlock::iterator(nonan_bb->getTerminator()));
+ t_s1->insertInto(nonan_bb, BasicBlock::iterator(nonan_bb->getTerminator()));
+ icmp_sign_bit->insertInto(nonan_bb,
+ BasicBlock::iterator(nonan_bb->getTerminator()));
+#else
nonan_bb->getInstList().insert(
BasicBlock::iterator(nonan_bb->getTerminator()), s_s0);
- t_s0 = new TruncInst(s_s0, Int1Ty);
nonan_bb->getInstList().insert(
BasicBlock::iterator(nonan_bb->getTerminator()), t_s0);
- s_s1 =
- BinaryOperator::Create(Instruction::LShr, b_op1,
- ConstantInt::get(b_op1->getType(), op_size - 1));
nonan_bb->getInstList().insert(
BasicBlock::iterator(nonan_bb->getTerminator()), s_s1);
- t_s1 = new TruncInst(s_s1, Int1Ty);
nonan_bb->getInstList().insert(
BasicBlock::iterator(nonan_bb->getTerminator()), t_s1);
- /* compare of the sign bits */
- icmp_sign_bit =
- CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, t_s0, t_s1);
nonan_bb->getInstList().insert(
BasicBlock::iterator(nonan_bb->getTerminator()), icmp_sign_bit);
+#endif
/* create a new basic block which is executed if the signedness bits are
* equal */
@@ -1137,17 +1243,31 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
s_e1 = BinaryOperator::Create(
Instruction::LShr, b_op1,
ConstantInt::get(b_op1->getType(), shiftR_exponent));
+#if LLVM_MAJOR >= 16
+ s_e0->insertInto(signequal_bb,
+ BasicBlock::iterator(signequal_bb->getTerminator()));
+ s_e1->insertInto(signequal_bb,
+ BasicBlock::iterator(signequal_bb->getTerminator()));
+#else
signequal_bb->getInstList().insert(
BasicBlock::iterator(signequal_bb->getTerminator()), s_e0);
signequal_bb->getInstList().insert(
BasicBlock::iterator(signequal_bb->getTerminator()), s_e1);
+#endif
t_e0 = new TruncInst(s_e0, IntExponentTy);
t_e1 = new TruncInst(s_e1, IntExponentTy);
+#if LLVM_MAJOR >= 16
+ t_e0->insertInto(signequal_bb,
+ BasicBlock::iterator(signequal_bb->getTerminator()));
+ t_e1->insertInto(signequal_bb,
+ BasicBlock::iterator(signequal_bb->getTerminator()));
+#else
signequal_bb->getInstList().insert(
BasicBlock::iterator(signequal_bb->getTerminator()), t_e0);
signequal_bb->getInstList().insert(
BasicBlock::iterator(signequal_bb->getTerminator()), t_e1);
+#endif
if (sizeInBits - precision < exTySizeBytes * 8) {
@@ -1157,10 +1277,17 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
m_e1 = BinaryOperator::Create(
Instruction::And, t_e1,
ConstantInt::get(t_e1->getType(), mask_exponent));
+#if LLVM_MAJOR >= 16
+ m_e0->insertInto(signequal_bb,
+ BasicBlock::iterator(signequal_bb->getTerminator()));
+ m_e1->insertInto(signequal_bb,
+ BasicBlock::iterator(signequal_bb->getTerminator()));
+#else
signequal_bb->getInstList().insert(
BasicBlock::iterator(signequal_bb->getTerminator()), m_e0);
signequal_bb->getInstList().insert(
BasicBlock::iterator(signequal_bb->getTerminator()), m_e1);
+#endif
} else {
@@ -1172,7 +1299,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
/* compare the exponents of the operands */
Instruction *icmp_exponents_equal;
Instruction *icmp_exponent_result;
- BasicBlock * signequal2_bb = signequal_bb;
+ BasicBlock *signequal2_bb = signequal_bb;
switch (FcmpInst->getPredicate()) {
case CmpInst::FCMP_UEQ:
@@ -1194,9 +1321,14 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
Instruction *icmp_exponent;
icmp_exponents_equal =
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, m_e0, m_e1);
+#if LLVM_MAJOR >= 16
+ icmp_exponents_equal->insertInto(
+ signequal_bb, BasicBlock::iterator(signequal_bb->getTerminator()));
+#else
signequal_bb->getInstList().insert(
BasicBlock::iterator(signequal_bb->getTerminator()),
icmp_exponents_equal);
+#endif
// shortcut for unequal exponents
signequal2_bb = signequal_bb->splitBasicBlock(
@@ -1210,9 +1342,15 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
icmp_exponent =
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, m_e0, m_e1);
+#if LLVM_MAJOR >= 16
+ icmp_exponent->insertInto(
+ signequal2_bb,
+ BasicBlock::iterator(signequal2_bb->getTerminator()));
+#else
signequal2_bb->getInstList().insert(
BasicBlock::iterator(signequal2_bb->getTerminator()),
icmp_exponent);
+#endif
icmp_exponent_result =
BinaryOperator::Create(Instruction::Xor, icmp_exponent, t_s0);
break;
@@ -1220,9 +1358,14 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
case CmpInst::FCMP_ULT:
icmp_exponents_equal =
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, m_e0, m_e1);
+#if LLVM_MAJOR >= 16
+ icmp_exponents_equal->insertInto(
+ signequal_bb, BasicBlock::iterator(signequal_bb->getTerminator()));
+#else
signequal_bb->getInstList().insert(
BasicBlock::iterator(signequal_bb->getTerminator()),
icmp_exponents_equal);
+#endif
// shortcut for unequal exponents
signequal2_bb = signequal_bb->splitBasicBlock(
@@ -1236,9 +1379,15 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
icmp_exponent =
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, m_e0, m_e1);
+#if LLVM_MAJOR >= 16
+ icmp_exponent->insertInto(
+ signequal2_bb,
+ BasicBlock::iterator(signequal2_bb->getTerminator()));
+#else
signequal2_bb->getInstList().insert(
BasicBlock::iterator(signequal2_bb->getTerminator()),
icmp_exponent);
+#endif
icmp_exponent_result =
BinaryOperator::Create(Instruction::Xor, icmp_exponent, t_s0);
break;
@@ -1247,9 +1396,14 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
}
+#if LLVM_MAJOR >= 16
+ icmp_exponent_result->insertInto(
+ signequal2_bb, BasicBlock::iterator(signequal2_bb->getTerminator()));
+#else
signequal2_bb->getInstList().insert(
BasicBlock::iterator(signequal2_bb->getTerminator()),
icmp_exponent_result);
+#endif
{
@@ -1299,19 +1453,33 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
m_f1 = BinaryOperator::Create(
Instruction::And, b_op1,
ConstantInt::get(b_op1->getType(), mask_fraction));
+#if LLVM_MAJOR >= 16
+ m_f0->insertInto(middle_bb,
+ BasicBlock::iterator(middle_bb->getTerminator()));
+ m_f1->insertInto(middle_bb,
+ BasicBlock::iterator(middle_bb->getTerminator()));
+#else
middle_bb->getInstList().insert(
BasicBlock::iterator(middle_bb->getTerminator()), m_f0);
middle_bb->getInstList().insert(
BasicBlock::iterator(middle_bb->getTerminator()), m_f1);
+#endif
if (needTrunc) {
t_f0 = new TruncInst(m_f0, IntFractionTy);
t_f1 = new TruncInst(m_f1, IntFractionTy);
+#if LLVM_MAJOR >= 16
+ t_f0->insertInto(middle_bb,
+ BasicBlock::iterator(middle_bb->getTerminator()));
+ t_f1->insertInto(middle_bb,
+ BasicBlock::iterator(middle_bb->getTerminator()));
+#else
middle_bb->getInstList().insert(
BasicBlock::iterator(middle_bb->getTerminator()), t_f0);
middle_bb->getInstList().insert(
BasicBlock::iterator(middle_bb->getTerminator()), t_f1);
+#endif
} else {
@@ -1326,10 +1494,17 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
t_f0 = new TruncInst(b_op0, IntFractionTy);
t_f1 = new TruncInst(b_op1, IntFractionTy);
+#if LLVM_MAJOR >= 16
+ t_f0->insertInto(middle_bb,
+ BasicBlock::iterator(middle_bb->getTerminator()));
+ t_f1->insertInto(middle_bb,
+ BasicBlock::iterator(middle_bb->getTerminator()));
+#else
middle_bb->getInstList().insert(
BasicBlock::iterator(middle_bb->getTerminator()), t_f0);
middle_bb->getInstList().insert(
BasicBlock::iterator(middle_bb->getTerminator()), t_f1);
+#endif
} else {
@@ -1342,26 +1517,36 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
/* compare the fractions of the operands */
Instruction *icmp_fraction_result;
- BasicBlock * middle2_bb = middle_bb;
- PHINode * PN2 = nullptr;
+ BasicBlock *middle2_bb = middle_bb;
+ PHINode *PN2 = nullptr;
switch (FcmpInst->getPredicate()) {
case CmpInst::FCMP_UEQ:
case CmpInst::FCMP_OEQ:
icmp_fraction_result =
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, t_f0, t_f1);
+#if LLVM_MAJOR >= 16
+ icmp_fraction_result->insertInto(
+ middle2_bb, BasicBlock::iterator(middle2_bb->getTerminator()));
+#else
middle2_bb->getInstList().insert(
BasicBlock::iterator(middle2_bb->getTerminator()),
icmp_fraction_result);
+#endif
break;
case CmpInst::FCMP_UNE:
case CmpInst::FCMP_ONE:
icmp_fraction_result =
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_NE, t_f0, t_f1);
+#if LLVM_MAJOR >= 16
+ icmp_fraction_result->insertInto(
+ middle2_bb, BasicBlock::iterator(middle2_bb->getTerminator()));
+#else
middle2_bb->getInstList().insert(
BasicBlock::iterator(middle2_bb->getTerminator()),
icmp_fraction_result);
+#endif
break;
case CmpInst::FCMP_OGT:
@@ -1382,21 +1567,31 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
if (FcmpInst->getPredicate() == CmpInst::FCMP_OGT ||
FcmpInst->getPredicate() == CmpInst::FCMP_UGT) {
- negative_bb->getInstList().push_back(
- icmp_fraction_result = CmpInst::Create(
- Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1));
- positive_bb->getInstList().push_back(
- icmp_fraction_result2 = CmpInst::Create(
- Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1));
+ icmp_fraction_result =
+ CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1);
+ icmp_fraction_result2 =
+ CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1);
+#if LLVM_MAJOR >= 16
+ icmp_fraction_result->insertInto(negative_bb, negative_bb->end());
+ icmp_fraction_result2->insertInto(positive_bb, negative_bb->end());
+#else
+ negative_bb->getInstList().push_back(icmp_fraction_result);
+ positive_bb->getInstList().push_back(icmp_fraction_result2);
+#endif
} else {
- negative_bb->getInstList().push_back(
- icmp_fraction_result = CmpInst::Create(
- Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1));
- positive_bb->getInstList().push_back(
- icmp_fraction_result2 = CmpInst::Create(
- Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1));
+ icmp_fraction_result =
+ CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1);
+ icmp_fraction_result2 =
+ CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1);
+#if LLVM_MAJOR >= 16
+ icmp_fraction_result->insertInto(negative_bb, negative_bb->end());
+ icmp_fraction_result2->insertInto(positive_bb, negative_bb->end());
+#else
+ negative_bb->getInstList().push_back(icmp_fraction_result);
+ positive_bb->getInstList().push_back(icmp_fraction_result2);
+#endif
}
@@ -1410,8 +1605,13 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
PN2 = PHINode::Create(Int1Ty, 2, "");
PN2->addIncoming(icmp_fraction_result, negative_bb);
PN2->addIncoming(icmp_fraction_result2, positive_bb);
+#if LLVM_MAJOR >= 16
+ PN2->insertInto(middle2_bb,
+ BasicBlock::iterator(middle2_bb->getTerminator()));
+#else
middle2_bb->getInstList().insert(
BasicBlock::iterator(middle2_bb->getTerminator()), PN2);
+#endif
} break;
@@ -1474,7 +1674,11 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
}
BasicBlock::iterator ii(FcmpInst);
+#if LLVM_MAJOR >= 16
+ ReplaceInstWithInst(FcmpInst->getParent(), ii, PN);
+#else
ReplaceInstWithInst(FcmpInst->getParent()->getInstList(), ii, PN);
+#endif
++count;
}
@@ -1484,7 +1688,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
}
#if LLVM_MAJOR >= 11
-PreservedAnalyses SplitComparesTransform::run(Module & M,
+PreservedAnalyses SplitComparesTransform::run(Module &M,
ModuleAnalysisManager &MAM) {
#else
diff --git a/instrumentation/split-switches-pass.so.cc b/instrumentation/split-switches-pass.so.cc
index 96e01a8b..dcd89652 100644
--- a/instrumentation/split-switches-pass.so.cc
+++ b/instrumentation/split-switches-pass.so.cc
@@ -102,7 +102,7 @@ class SplitSwitchesTransform : public ModulePass {
struct CaseExpr {
ConstantInt *Val;
- BasicBlock * BB;
+ BasicBlock *BB;
CaseExpr(ConstantInt *val = nullptr, BasicBlock *bb = nullptr)
: Val(val), BB(bb) {
@@ -182,7 +182,7 @@ BasicBlock *SplitSwitchesTransform::switchConvert(
unsigned ValTypeBitWidth = Cases[0].Val->getBitWidth();
IntegerType *ValType =
IntegerType::get(OrigBlock->getContext(), ValTypeBitWidth);
- IntegerType * ByteType = IntegerType::get(OrigBlock->getContext(), 8);
+ IntegerType *ByteType = IntegerType::get(OrigBlock->getContext(), 8);
unsigned BytesInValue = bytesChecked.size();
std::vector<uint8_t> setSizes;
std::vector<std::set<uint8_t> > byteSets(BytesInValue, std::set<uint8_t>());
@@ -221,16 +221,24 @@ BasicBlock *SplitSwitchesTransform::switchConvert(
/* there are only smallestSize different bytes at index smallestIndex */
Instruction *Shift, *Trunc;
- Function * F = OrigBlock->getParent();
- BasicBlock * NewNode = BasicBlock::Create(Val->getContext(), "NodeBlock", F);
+ Function *F = OrigBlock->getParent();
+ BasicBlock *NewNode = BasicBlock::Create(Val->getContext(), "NodeBlock", F);
Shift = BinaryOperator::Create(Instruction::LShr, Val,
ConstantInt::get(ValType, smallestIndex * 8));
+#if LLVM_VERSION_MAJOR >= 16
+ Shift->insertInto(NewNode, NewNode->end());
+#else
NewNode->getInstList().push_back(Shift);
+#endif
if (ValTypeBitWidth > 8) {
Trunc = new TruncInst(Shift, ByteType);
+#if LLVM_VERSION_MAJOR >= 16
+ Trunc->insertInto(NewNode, NewNode->end());
+#else
NewNode->getInstList().push_back(Trunc);
+#endif
} else {
@@ -253,7 +261,11 @@ BasicBlock *SplitSwitchesTransform::switchConvert(
ICmpInst *Comp =
new ICmpInst(ICmpInst::ICMP_EQ, Trunc, ConstantInt::get(ByteType, byte),
"byteMatch");
+#if LLVM_VERSION_MAJOR >= 16
+ Comp->insertInto(NewNode, NewNode->end());
+#else
NewNode->getInstList().push_back(Comp);
+#endif
bytesChecked[smallestIndex] = true;
bool allBytesAreChecked = true;
@@ -355,7 +367,11 @@ BasicBlock *SplitSwitchesTransform::switchConvert(
ICmpInst *Comp =
new ICmpInst(ICmpInst::ICMP_ULT, Trunc,
ConstantInt::get(ByteType, pivot), "byteMatch");
+#if LLVM_VERSION_MAJOR >= 16
+ Comp->insertInto(NewNode, NewNode->end());
+#else
NewNode->getInstList().push_back(Comp);
+#endif
BranchInst::Create(LBB, RBB, Comp, NewNode);
}
@@ -403,9 +419,9 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) {
BasicBlock *CurBlock = SI->getParent();
BasicBlock *OrigBlock = CurBlock;
- Function * F = CurBlock->getParent();
+ Function *F = CurBlock->getParent();
/* this is the value we are switching on */
- Value * Val = SI->getCondition();
+ Value *Val = SI->getCondition();
BasicBlock *Default = SI->getDefaultDest();
unsigned bitw = Val->getType()->getIntegerBitWidth();
@@ -445,14 +461,18 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) {
* round up bytesChecked (in case getBitWidth() % 8 != 0) */
std::vector<bool> bytesChecked((7 + Cases[0].Val->getBitWidth()) / 8,
false);
- BasicBlock * SwitchBlock =
+ BasicBlock *SwitchBlock =
switchConvert(Cases, bytesChecked, OrigBlock, NewDefault, Val, 0);
/* Branch to our shiny new if-then stuff... */
BranchInst::Create(SwitchBlock, OrigBlock);
/* We are now done with the switch instruction, delete it. */
+#if LLVM_VERSION_MAJOR >= 16
+ SI->eraseFromParent();
+#else
CurBlock->getInstList().erase(SI);
+#endif
/* we have to update the phi nodes! */
for (BasicBlock::iterator I = Default->begin(); I != Default->end(); ++I) {
@@ -483,7 +503,7 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) {
}
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
-PreservedAnalyses SplitSwitchesTransform::run(Module & M,
+PreservedAnalyses SplitSwitchesTransform::run(Module &M,
ModuleAnalysisManager &MAM) {
#else
diff --git a/src/afl-analyze.c b/src/afl-analyze.c
index fc868603..5b122741 100644
--- a/src/afl-analyze.c
+++ b/src/afl-analyze.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -114,16 +114,16 @@ static void kill_child() {
if (fsrv.child_pid > 0) {
- kill(fsrv.child_pid, fsrv.kill_signal);
+ kill(fsrv.child_pid, fsrv.child_kill_signal);
fsrv.child_pid = -1;
}
}
-static void classify_counts(u8 *mem) {
+static void classify_counts(u8 *mem, u32 mem_size) {
- u32 i = map_size;
+ u32 i = mem_size;
if (edges_only) {
@@ -203,7 +203,7 @@ static void read_initial_file(void) {
/* Execute target application. Returns exec checksum, or 0 if program
times out. */
-static u32 analyze_run_target(u8 *mem, u32 len, u8 first_run) {
+static u64 analyze_run_target(u8 *mem, u32 len, u8 first_run) {
afl_fsrv_write_to_testcase(&fsrv, mem, len);
fsrv_run_result_t ret = afl_fsrv_run_target(&fsrv, exec_tmout, &stop_soon);
@@ -222,7 +222,7 @@ static u32 analyze_run_target(u8 *mem, u32 len, u8 first_run) {
}
- classify_counts(fsrv.trace_bits);
+ classify_counts(fsrv.trace_bits, fsrv.map_size);
total_execs++;
if (stop_soon) {
@@ -528,7 +528,7 @@ static void analyze() {
for (i = 0; i < in_len; i++) {
- u32 xor_ff, xor_01, sub_10, add_10;
+ u64 xor_ff, xor_01, sub_10, add_10;
u8 xff_orig, x01_orig, s10_orig, a10_orig;
/* Perform walking byte adjustments across the file. We perform four
@@ -626,7 +626,7 @@ 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;
@@ -656,28 +656,6 @@ static void set_up_environment(char **argv) {
if (fsrv.out_fd < 0) { PFATAL("Unable to create '%s'", fsrv.out_file); }
/* Set sane defaults... */
-
- x = get_afl_env("ASAN_OPTIONS");
-
- if (x) {
-
- if (!strstr(x, "abort_on_error=1")) {
-
- FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!");
-
- }
-
-#ifndef ASAN_BUILD
- if (!getenv("AFL_DEBUG") && !strstr(x, "symbolize=0")) {
-
- FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!");
-
- }
-
-#endif
-
- }
-
x = get_afl_env("MSAN_OPTIONS");
if (x) {
@@ -689,69 +667,9 @@ static void set_up_environment(char **argv) {
}
- if (!strstr(x, "symbolize=0")) {
-
- FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!");
-
- }
-
- }
-
- x = get_afl_env("LSAN_OPTIONS");
-
- if (x) {
-
- if (!strstr(x, "symbolize=0")) {
-
- FATAL("Custom LSAN_OPTIONS set without symbolize=0 - please fix!");
-
- }
-
}
- setenv("ASAN_OPTIONS",
- "abort_on_error=1:"
- "detect_leaks=0:"
- "allocator_may_return_null=1:"
- "detect_odr_violation=0:"
- "symbolize=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0",
- 0);
-
- setenv("UBSAN_OPTIONS",
- "halt_on_error=1:"
- "abort_on_error=1:"
- "malloc_context_size=0:"
- "allocator_may_return_null=1:"
- "symbolize=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0",
- 0);
-
- setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
- "abort_on_error=1:"
- "msan_track_origins=0"
- "allocator_may_return_null=1:"
- "symbolize=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0", 0);
-
- setenv("LSAN_OPTIONS",
- "exitcode=" STRINGIFY(LSAN_ERROR) ":"
- "fast_unwind_on_malloc=0:"
- "symbolize=0:"
- "print_suppressions=0",
- 0);
+ set_sanitizer_defaults();
if (get_afl_env("AFL_PRELOAD")) {
@@ -807,7 +725,11 @@ static void setup_signal_handlers(void) {
struct sigaction sa;
sa.sa_handler = NULL;
+#ifdef SA_RESTART
sa.sa_flags = SA_RESTART;
+#else
+ sa.sa_flags = 0;
+#endif
sa.sa_sigaction = NULL;
sigemptyset(&sa.sa_mask);
@@ -846,6 +768,7 @@ static void usage(u8 *argv0) {
" -U - use unicorn-based instrumentation (Unicorn mode)\n"
" -W - use qemu-based instrumentation with Wine (Wine "
"mode)\n"
+ " -X - use Nyx mode\n"
#endif
"\n"
@@ -862,11 +785,15 @@ static void usage(u8 *argv0) {
"MSAN_OPTIONS: custom settings for MSAN\n"
" (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
"AFL_ANALYZE_HEX: print file offsets in hexadecimal instead of decimal\n"
+ "AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc.\n"
+ " (default: SIGKILL)\n"
+ "AFL_FORK_SERVER_KILL_SIGNAL: Kill signal for the fork server on termination\n"
+ " (default: SIGTERM). If unset and AFL_KILL_SIGNAL is\n"
+ " set, that value will be used.\n"
"AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
" the target was compiled for\n"
"AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
"AFL_SKIP_BIN_CHECK: skip checking the location of and the target\n"
-
, argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path);
exit(1);
@@ -888,7 +815,7 @@ int main(int argc, char **argv_orig, char **envp) {
afl_fsrv_init(&fsrv);
- while ((opt = getopt(argc, argv, "+i:f:m:t:eAOQUWh")) > 0) {
+ while ((opt = getopt(argc, argv, "+i:f:m:t:eAOQUWXYh")) > 0) {
switch (opt) {
@@ -1040,6 +967,23 @@ int main(int argc, char **argv_orig, char **envp) {
break;
+ case 'Y': // fallthough
+#ifdef __linux__
+ case 'X': /* NYX mode */
+
+ if (fsrv.nyx_mode) { FATAL("Multiple -X options not supported"); }
+
+ fsrv.nyx_mode = 1;
+ fsrv.nyx_parent = true;
+ fsrv.nyx_standalone = true;
+
+ break;
+#else
+ case 'X':
+ FATAL("Nyx mode is only availabe on linux...");
+ break;
+#endif
+
case 'h':
usage(argv[0]);
return -1;
@@ -1071,7 +1015,21 @@ int main(int argc, char **argv_orig, char **envp) {
set_up_environment(argv);
+#ifdef __linux__
+ if (!fsrv.nyx_mode) {
+
+ fsrv.target_path = find_binary(argv[optind]);
+
+ } else {
+
+ fsrv.target_path = ck_strdup(argv[optind]);
+
+ }
+
+#else
fsrv.target_path = find_binary(argv[optind]);
+#endif
+
fsrv.trace_bits = afl_shm_init(&shm, map_size, 0);
detect_file_args(argv + optind, fsrv.out_file, &use_stdin);
signal(SIGALRM, kill_child);
@@ -1094,6 +1052,26 @@ int main(int argc, char **argv_orig, char **envp) {
use_argv = get_cs_argv(argv[0], &target_path, argc - optind, argv + optind);
+#ifdef __linux__
+
+ } else if (fsrv.nyx_mode) {
+
+ fsrv.nyx_id = 0;
+
+ u8 *libnyx_binary = find_afl_binary(argv[0], "libnyx.so");
+ fsrv.nyx_handlers = afl_load_libnyx_plugin(libnyx_binary);
+ if (fsrv.nyx_handlers == NULL) {
+
+ FATAL("failed to initialize libnyx.so...");
+
+ }
+
+ fsrv.nyx_use_tmp_workdir = true;
+ fsrv.nyx_bind_cpu_id = 0;
+
+ use_argv = argv + optind;
+#endif
+
} else {
use_argv = argv + optind;
@@ -1115,11 +1093,15 @@ int main(int argc, char **argv_orig, char **envp) {
}
- fsrv.kill_signal =
- parse_afl_kill_signal_env(getenv("AFL_KILL_SIGNAL"), SIGKILL);
+ configure_afl_kill_signals(
+ &fsrv, NULL, NULL, (fsrv.qemu_mode || unicorn_mode) ? SIGKILL : SIGTERM);
read_initial_file();
+#ifdef __linux__
+ if (!fsrv.nyx_mode) { (void)check_binary_signatures(fsrv.target_path); }
+#else
(void)check_binary_signatures(fsrv.target_path);
+#endif
ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...",
mem_limit, exec_tmout, edges_only ? ", edges only" : "");
diff --git a/src/afl-as.c b/src/afl-as.c
index 1edc8cca..772e31b3 100644
--- a/src/afl-as.c
+++ b/src/afl-as.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -93,7 +93,7 @@ static u8 use_64bit = 0;
static void edit_params(int argc, char **argv) {
u8 *tmp_dir = getenv("TMPDIR"), *afl_as = getenv("AFL_AS");
- u32 i;
+ u32 i, input_index;
#ifdef __APPLE__
@@ -142,7 +142,23 @@ static void edit_params(int argc, char **argv) {
as_params[argc] = 0;
- for (i = 1; (s32)i < argc - 1; i++) {
+ /* Find the input file. It's usually located near the end.
+ Assume there won't be any arguments referring to files after the input
+ file, e.g. as input.s -o output.o */
+ for (input_index = argc - 1; input_index > 0; input_index--) {
+
+ input_file = argv[input_index];
+ /* Clang may add debug arguments after the input file. */
+ if (strncmp(input_file, "-g", 2)) break;
+
+ }
+
+ if (input_index == 0)
+ FATAL("Could not find input file (not called through afl-gcc?)");
+
+ for (i = 1; (s32)i < argc; i++) {
+
+ if (i == input_index) continue;
if (!strcmp(argv[i], "--64")) {
@@ -194,8 +210,6 @@ static void edit_params(int argc, char **argv) {
#endif /* __APPLE__ */
- input_file = argv[argc - 1];
-
if (input_file[0] == '-') {
if (!strcmp(input_file + 1, "-version")) {
diff --git a/src/afl-cc.c b/src/afl-cc.c
index 2667ae28..9e56828c 100644
--- a/src/afl-cc.c
+++ b/src/afl-cc.c
@@ -5,7 +5,7 @@
Written by Michal Zalewski, Laszlo Szekeres and Marc Heuse
Copyright 2015, 2016 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -31,6 +31,8 @@
#include <strings.h>
#include <limits.h>
#include <assert.h>
+#include <ctype.h>
+#include <sys/stat.h>
#if (LLVM_MAJOR - 0 == 0)
#undef LLVM_MAJOR
@@ -45,15 +47,15 @@
#define LLVM_MINOR 0
#endif
-static u8 * obj_path; /* Path to runtime libraries */
+static u8 *obj_path; /* Path to runtime libraries */
static u8 **cc_params; /* Parameters passed to the real CC */
static u32 cc_par_cnt = 1; /* Param count, including argv0 */
static u8 clang_mode; /* Invoked as afl-clang*? */
static u8 llvm_fullpath[PATH_MAX];
static u8 instrument_mode, instrument_opt_mode, ngram_size, ctx_k, lto_mode;
-static u8 compiler_mode, plusplus_mode, have_instr_env = 0;
+static u8 compiler_mode, plusplus_mode, have_instr_env = 0, need_aflpplib = 0;
static u8 have_gcc, have_llvm, have_gcc_plugin, have_lto, have_instr_list = 0;
-static u8 * lto_flag = AFL_CLANG_FLTO, *argvnull;
+static u8 *lto_flag = AFL_CLANG_FLTO, *argvnull;
static u8 debug;
static u8 cwd[4096];
static u8 cmplog_mode;
@@ -76,6 +78,7 @@ enum {
INSTRUMENT_OPT_NGRAM = 16,
INSTRUMENT_OPT_CALLER = 32,
INSTRUMENT_OPT_CTX_K = 64,
+ INSTRUMENT_OPT_CODECOV = 128,
};
@@ -310,15 +313,373 @@ static u8 *find_object(u8 *obj, u8 *argv0) {
}
+void parse_fsanitize(char *string) {
+
+ char *p, *ptr = string + strlen("-fsanitize=");
+ char *new = malloc(strlen(string) + 1);
+ char *tmp = malloc(strlen(ptr));
+ u32 count = 0, len, ende = 0;
+
+ if (!new || !tmp) { FATAL("could not acquire memory"); }
+ strcpy(new, "-fsanitize=");
+
+ do {
+
+ p = strchr(ptr, ',');
+ if (!p) {
+
+ p = ptr + strlen(ptr) + 1;
+ ende = 1;
+
+ }
+
+ len = p - ptr;
+ if (len) {
+
+ strncpy(tmp, ptr, len);
+ tmp[len] = 0;
+ // fprintf(stderr, "Found: %s\n", tmp);
+ ptr += len + 1;
+ if (*tmp) {
+
+ u32 copy = 1;
+ if (!strcmp(tmp, "fuzzer")) {
+
+ need_aflpplib = 1;
+ copy = 0;
+
+ } else if (!strncmp(tmp, "fuzzer", 6)) {
+
+ copy = 0;
+
+ }
+
+ if (copy) {
+
+ if (count) { strcat(new, ","); }
+ strcat(new, tmp);
+ ++count;
+
+ }
+
+ }
+
+ } else {
+
+ ptr++; /*fprintf(stderr, "NO!\n"); */
+
+ }
+
+ } while (!ende);
+
+ strcpy(string, new);
+ // fprintf(stderr, "string: %s\n", string);
+ // fprintf(stderr, "new: %s\n", new);
+
+}
+
+static u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0,
+ shared_linking = 0, preprocessor_only = 0, have_unroll = 0,
+ have_o = 0, have_pic = 0, have_c = 0, partial_linking = 0,
+ non_dash = 0;
+
+static void process_params(u32 argc, char **argv) {
+
+ if (cc_par_cnt + argc >= 1024) { FATAL("Too many command line parameters"); }
+
+ if (lto_mode && argc > 1) {
+
+ u32 idx;
+ for (idx = 1; idx < argc; idx++) {
+
+ if (!strncasecmp(argv[idx], "-fpic", 5)) have_pic = 1;
+
+ }
+
+ }
+
+ // for (u32 x = 0; x < argc; ++x) fprintf(stderr, "[%u] %s\n", x, argv[x]);
+
+ /* Process the argument list. */
+
+ u8 skip_next = 0;
+ while (--argc) {
+
+ u8 *cur = *(++argv);
+
+ if (skip_next) {
+
+ skip_next = 0;
+ continue;
+
+ }
+
+ if (cur[0] != '-') { non_dash = 1; }
+ if (!strncmp(cur, "--afl", 5)) continue;
+
+ if (lto_mode && !strncmp(cur, "-flto=thin", 10)) {
+
+ FATAL(
+ "afl-clang-lto cannot work with -flto=thin. Switch to -flto=full or "
+ "use afl-clang-fast!");
+
+ }
+
+ if (lto_mode && !strncmp(cur, "-fuse-ld=", 9)) continue;
+ if (lto_mode && !strncmp(cur, "--ld-path=", 10)) continue;
+ if (!strncmp(cur, "-fno-unroll", 11)) continue;
+ if (strstr(cur, "afl-compiler-rt") || strstr(cur, "afl-llvm-rt")) continue;
+ if (!strcmp(cur, "-Wl,-z,defs") || !strcmp(cur, "-Wl,--no-undefined") ||
+ !strcmp(cur, "--no-undefined")) {
+
+ continue;
+
+ }
+
+ if (compiler_mode == GCC_PLUGIN && !strcmp(cur, "-pipe")) { continue; }
+
+ if (!strcmp(cur, "-z") || !strcmp(cur, "-Wl,-z")) {
+
+ u8 *param = *(argv + 1);
+ if (!strcmp(param, "defs") || !strcmp(param, "-Wl,defs")) {
+
+ skip_next = 1;
+ continue;
+
+ }
+
+ }
+
+ if ((compiler_mode == GCC || compiler_mode == GCC_PLUGIN) &&
+ !strncmp(cur, "-stdlib=", 8)) {
+
+ if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); }
+ continue;
+
+ }
+
+ if (!strncmp(cur, "-fsanitize-coverage-", 20) && strstr(cur, "list=")) {
+
+ have_instr_list = 1;
+
+ }
+
+ if (!strncmp(cur, "-fsanitize=", strlen("-fsanitize=")) &&
+ strchr(cur, ',')) {
+
+ parse_fsanitize(cur);
+ if (!cur || strlen(cur) <= strlen("-fsanitize=")) { continue; }
+
+ } else if ((!strncmp(cur, "-fsanitize=fuzzer-",
+
+ strlen("-fsanitize=fuzzer-")) ||
+ !strncmp(cur, "-fsanitize-coverage",
+ strlen("-fsanitize-coverage"))) &&
+ (strncmp(cur, "sanitize-coverage-allow",
+ strlen("sanitize-coverage-allow")) &&
+ strncmp(cur, "sanitize-coverage-deny",
+ strlen("sanitize-coverage-deny")) &&
+ instrument_mode != INSTRUMENT_LLVMNATIVE)) {
+
+ if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); }
+ continue;
+
+ }
+
+ if (need_aflpplib || !strcmp(cur, "-fsanitize=fuzzer")) {
+
+ u8 *afllib = find_object("libAFLDriver.a", argv[0]);
+
+ if (!be_quiet) {
+
+ OKF("Found '-fsanitize=fuzzer', replacing with libAFLDriver.a");
+
+ }
+
+ if (!afllib) {
+
+ if (!be_quiet) {
+
+ WARNF(
+ "Cannot find 'libAFLDriver.a' to replace '-fsanitize=fuzzer' in "
+ "the flags - this will fail!");
+
+ }
+
+ } else {
+
+ cc_params[cc_par_cnt++] = afllib;
+
+#ifdef __APPLE__
+ cc_params[cc_par_cnt++] = "-undefined";
+ cc_params[cc_par_cnt++] = "dynamic_lookup";
+#endif
+
+ }
+
+ if (need_aflpplib) {
+
+ need_aflpplib = 0;
+
+ } else {
+
+ continue;
+
+ }
+
+ }
+
+ if (!strcmp(cur, "-m32")) bit_mode = 32;
+ if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32;
+ if (!strcmp(cur, "-m64")) bit_mode = 64;
+
+ if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory"))
+ asan_set = 1;
+
+ if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;
+
+ if (!strcmp(cur, "-x")) x_set = 1;
+ if (!strcmp(cur, "-E")) preprocessor_only = 1;
+ if (!strcmp(cur, "-shared")) shared_linking = 1;
+ if (!strcmp(cur, "-dynamiclib")) shared_linking = 1;
+ if (!strcmp(cur, "--target=wasm32-wasi")) passthrough = 1;
+ if (!strcmp(cur, "-Wl,-r")) partial_linking = 1;
+ if (!strcmp(cur, "-Wl,-i")) partial_linking = 1;
+ if (!strcmp(cur, "-Wl,--relocatable")) partial_linking = 1;
+ if (!strcmp(cur, "-r")) partial_linking = 1;
+ if (!strcmp(cur, "--relocatable")) partial_linking = 1;
+ if (!strcmp(cur, "-c")) have_c = 1;
+
+ if (!strncmp(cur, "-O", 2)) have_o = 1;
+ if (!strncmp(cur, "-funroll-loop", 13)) have_unroll = 1;
+
+ if (*cur == '@') {
+
+ // response file support.
+ // we have two choices - move everything to the command line or
+ // rewrite the response files to temporary files and delete them
+ // afterwards. We choose the first for easiness.
+ // We do *not* support quotes in the rsp files to cope with spaces in
+ // filenames etc! If you need that then send a patch!
+ u8 *filename = cur + 1;
+ if (debug) { DEBUGF("response file=%s\n", filename); }
+ FILE *f = fopen(filename, "r");
+ struct stat st;
+
+ // Check not found or empty? let the compiler complain if so.
+ if (!f || fstat(fileno(f), &st) < 0 || st.st_size < 1) {
+
+ cc_params[cc_par_cnt++] = cur;
+ continue;
+
+ }
+
+ u8 *tmpbuf = malloc(st.st_size + 2), *ptr;
+ char **args = malloc(sizeof(char *) * (st.st_size >> 1));
+ int count = 1, cont = 0, cont_act = 0;
+
+ while (fgets(tmpbuf, st.st_size + 1, f)) {
+
+ ptr = tmpbuf;
+ // fprintf(stderr, "1: %s\n", ptr);
+ // no leading whitespace
+ while (isspace(*ptr)) {
+
+ ++ptr;
+ cont_act = 0;
+
+ }
+
+ // no comments, no empty lines
+ if (*ptr == '#' || *ptr == '\n' || !*ptr) { continue; }
+ // remove LF
+ if (ptr[strlen(ptr) - 1] == '\n') { ptr[strlen(ptr) - 1] = 0; }
+ // remove CR
+ if (*ptr && ptr[strlen(ptr) - 1] == '\r') { ptr[strlen(ptr) - 1] = 0; }
+ // handle \ at end of line
+ if (*ptr && ptr[strlen(ptr) - 1] == '\\') {
+
+ cont = 1;
+ ptr[strlen(ptr) - 1] = 0;
+
+ }
+
+ // fprintf(stderr, "2: %s\n", ptr);
+
+ // remove whitespace at end
+ while (*ptr && isspace(ptr[strlen(ptr) - 1])) {
+
+ ptr[strlen(ptr) - 1] = 0;
+ cont = 0;
+
+ }
+
+ // fprintf(stderr, "3: %s\n", ptr);
+ if (*ptr) {
+
+ do {
+
+ u8 *value = ptr;
+ while (*ptr && !isspace(*ptr)) {
+
+ ++ptr;
+
+ }
+
+ while (*ptr && isspace(*ptr)) {
+
+ *ptr++ = 0;
+
+ }
+
+ if (cont_act) {
+
+ u32 len = strlen(args[count - 1]) + strlen(value) + 1;
+ u8 *tmp = malloc(len);
+ snprintf(tmp, len, "%s%s", args[count - 1], value);
+ free(args[count - 1]);
+ args[count - 1] = tmp;
+ cont_act = 0;
+
+ } else {
+
+ args[count++] = strdup(value);
+
+ }
+
+ } while (*ptr);
+
+ }
+
+ if (cont) {
+
+ cont_act = 1;
+ cont = 0;
+
+ }
+
+ }
+
+ if (count) { process_params(count, args); }
+
+ // we cannot free args[]
+ free(tmpbuf);
+
+ continue;
+
+ }
+
+ cc_params[cc_par_cnt++] = cur;
+
+ }
+
+}
+
/* Copy argv to cc_params, making the necessary edits. */
static void edit_params(u32 argc, char **argv, char **envp) {
- u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0, shared_linking = 0,
- preprocessor_only = 0, have_unroll = 0, have_o = 0, have_pic = 0,
- have_c = 0, partial_linking = 0;
-
- cc_params = ck_alloc((argc + 128) * sizeof(u8 *));
+ cc_params = ck_alloc(1024 * sizeof(u8 *));
if (lto_mode) {
@@ -396,7 +757,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang",
LLVM_BINDIR);
else
- snprintf(llvm_fullpath, sizeof(llvm_fullpath), CLANG_BIN);
+ snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s", CLANG_BIN);
alt_cc = llvm_fullpath;
}
@@ -422,7 +783,20 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (compiler_mode == GCC_PLUGIN) {
- char *fplugin_arg = alloc_printf("-fplugin=%s/afl-gcc-pass.so", obj_path);
+ char *fplugin_arg;
+
+ if (cmplog_mode) {
+
+ fplugin_arg =
+ alloc_printf("-fplugin=%s/afl-gcc-cmplog-pass.so", obj_path);
+ cc_params[cc_par_cnt++] = fplugin_arg;
+ fplugin_arg =
+ alloc_printf("-fplugin=%s/afl-gcc-cmptrs-pass.so", obj_path);
+ cc_params[cc_par_cnt++] = fplugin_arg;
+
+ }
+
+ fplugin_arg = alloc_printf("-fplugin=%s/afl-gcc-pass.so", obj_path);
cc_params[cc_par_cnt++] = fplugin_arg;
cc_params[cc_par_cnt++] = "-fno-if-conversion";
cc_params[cc_par_cnt++] = "-fno-if-conversion2";
@@ -436,7 +810,9 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (lto_mode && have_instr_env) {
#if LLVM_MAJOR >= 11 /* use new pass manager */
+ #if LLVM_MAJOR < 16
cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+ #endif
cc_params[cc_par_cnt++] = alloc_printf(
"-fpass-plugin=%s/afl-llvm-lto-instrumentlist.so", obj_path);
#else
@@ -452,7 +828,9 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (getenv("AFL_LLVM_DICT2FILE")) {
#if LLVM_MAJOR >= 11 /* use new pass manager */
+ #if LLVM_MAJOR < 16
cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+ #endif
cc_params[cc_par_cnt++] =
alloc_printf("-fpass-plugin=%s/afl-llvm-dict2file.so", obj_path);
#else
@@ -469,7 +847,9 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (getenv("LAF_SPLIT_SWITCHES") || getenv("AFL_LLVM_LAF_SPLIT_SWITCHES")) {
#if LLVM_MAJOR >= 11 /* use new pass manager */
+ #if LLVM_MAJOR < 16
cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+ #endif
cc_params[cc_par_cnt++] =
alloc_printf("-fpass-plugin=%s/split-switches-pass.so", obj_path);
#else
@@ -486,7 +866,9 @@ static void edit_params(u32 argc, char **argv, char **envp) {
getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES")) {
#if LLVM_MAJOR >= 11 /* use new pass manager */
+ #if LLVM_MAJOR < 16
cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+ #endif
cc_params[cc_par_cnt++] =
alloc_printf("-fpass-plugin=%s/compare-transform-pass.so", obj_path);
#else
@@ -503,7 +885,9 @@ static void edit_params(u32 argc, char **argv, char **envp) {
getenv("AFL_LLVM_LAF_SPLIT_FLOATS")) {
#if LLVM_MAJOR >= 11 /* use new pass manager */
+ #if LLVM_MAJOR < 16
cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+ #endif
cc_params[cc_par_cnt++] =
alloc_printf("-fpass-plugin=%s/split-compares-pass.so", obj_path);
#else
@@ -526,10 +910,14 @@ static void edit_params(u32 argc, char **argv, char **envp) {
cc_params[cc_par_cnt++] = "-fno-inline";
#if LLVM_MAJOR >= 11 /* use new pass manager */
+ #if LLVM_MAJOR < 16
cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+ #endif
cc_params[cc_par_cnt++] =
alloc_printf("-fpass-plugin=%s/cmplog-switches-pass.so", obj_path);
+ #if LLVM_MAJOR < 16
cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+ #endif
cc_params[cc_par_cnt++] =
alloc_printf("-fpass-plugin=%s/split-switches-pass.so", obj_path);
#else
@@ -549,10 +937,10 @@ static void edit_params(u32 argc, char **argv, char **envp) {
}
- //#if LLVM_MAJOR >= 13
- // // Use the old pass manager in LLVM 14 which the afl++ passes still
- // use. cc_params[cc_par_cnt++] = "-flegacy-pass-manager";
- //#endif
+ // #if LLVM_MAJOR >= 13
+ // // Use the old pass manager in LLVM 14 which the AFL++ passes still
+ // use. cc_params[cc_par_cnt++] = "-flegacy-pass-manager";
+ // #endif
if (lto_mode && !have_c) {
@@ -588,22 +976,28 @@ static void edit_params(u32 argc, char **argv, char **envp) {
#endif
free(ld_path);
-#if defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 13
+#if defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 15
+ // The NewPM implementation only works fully since LLVM 15.
+ cc_params[cc_par_cnt++] = alloc_printf(
+ "-Wl,--load-pass-plugin=%s/SanitizerCoverageLTO.so", obj_path);
+#elif defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 13
cc_params[cc_par_cnt++] = "-Wl,--lto-legacy-pass-manager";
+ cc_params[cc_par_cnt++] =
+ alloc_printf("-Wl,-mllvm=-load=%s/SanitizerCoverageLTO.so", obj_path);
#else
cc_params[cc_par_cnt++] = "-fno-experimental-new-pass-manager";
+ cc_params[cc_par_cnt++] =
+ alloc_printf("-Wl,-mllvm=-load=%s/SanitizerCoverageLTO.so", obj_path);
#endif
cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition";
- cc_params[cc_par_cnt++] =
- alloc_printf("-Wl,-mllvm=-load=%s/SanitizerCoverageLTO.so", obj_path);
cc_params[cc_par_cnt++] = lto_flag;
} else {
if (instrument_mode == INSTRUMENT_PCGUARD) {
-#if LLVM_MAJOR >= 11
+#if LLVM_MAJOR >= 13
#if defined __ANDROID__ || ANDROID
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
instrument_mode = INSTRUMENT_LLVMNATIVE;
@@ -620,8 +1014,10 @@ static void edit_params(u32 argc, char **argv, char **envp) {
} else {
- #if LLVM_MAJOR >= 11 /* use new pass manager */
+ #if LLVM_MAJOR >= 13 /* use new pass manager */
+ #if LLVM_MAJOR < 16
cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+ #endif
cc_params[cc_par_cnt++] = alloc_printf(
"-fpass-plugin=%s/SanitizerCoveragePCGUARD.so", obj_path);
#else
@@ -639,27 +1035,43 @@ static void edit_params(u32 argc, char **argv, char **envp) {
#if LLVM_MAJOR >= 4
if (!be_quiet)
SAYF(
- "Using unoptimized trace-pc-guard, upgrade to llvm 10.0.1+ for "
+ "Using unoptimized trace-pc-guard, upgrade to LLVM 13+ for "
"enhanced version.\n");
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
instrument_mode = INSTRUMENT_LLVMNATIVE;
#else
- FATAL("pcguard instrumentation requires llvm 4.0.1+");
+ FATAL("pcguard instrumentation requires LLVM 4.0.1+");
#endif
#endif
} else if (instrument_mode == INSTRUMENT_LLVMNATIVE) {
#if LLVM_MAJOR >= 4
- cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
+ if (instrument_opt_mode & INSTRUMENT_OPT_CODECOV) {
+
+ #if LLVM_MAJOR >= 6
+ cc_params[cc_par_cnt++] =
+ "-fsanitize-coverage=trace-pc-guard,bb,no-prune,pc-table";
+ #else
+ FATAL("pcguard instrumentation with pc-table requires LLVM 6.0.1+");
+ #endif
+
+ } else {
+
+ cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
+
+ }
+
#else
- FATAL("pcguard instrumentation requires llvm 4.0.1+");
+ FATAL("pcguard instrumentation requires LLVM 4.0.1+");
#endif
} else {
#if LLVM_MAJOR >= 11 /* use new pass manager */
+ #if LLVM_MAJOR < 16
cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+ #endif
cc_params[cc_par_cnt++] =
alloc_printf("-fpass-plugin=%s/afl-llvm-pass.so", obj_path);
#else
@@ -677,10 +1089,14 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (cmplog_mode) {
#if LLVM_MAJOR >= 11
+ #if LLVM_MAJOR < 16
cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+ #endif
cc_params[cc_par_cnt++] = alloc_printf(
"-fpass-plugin=%s/cmplog-instructions-pass.so", obj_path);
+ #if LLVM_MAJOR < 16
cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+ #endif
cc_params[cc_par_cnt++] =
alloc_printf("-fpass-plugin=%s/cmplog-routines-pass.so", obj_path);
#else
@@ -710,137 +1126,15 @@ static void edit_params(u32 argc, char **argv, char **envp) {
}
- if (!have_pic) cc_params[cc_par_cnt++] = "-fPIC";
-
}
}
- /* Detect stray -v calls from ./configure scripts. */
-
- u8 skip_next = 0, non_dash = 0;
- while (--argc) {
-
- u8 *cur = *(++argv);
-
- if (skip_next) {
+ /* Inspect the command line parameters. */
- skip_next = 0;
- continue;
+ process_params(argc, argv);
- }
-
- if (cur[0] != '-') { non_dash = 1; }
- if (!strncmp(cur, "--afl", 5)) continue;
- if (lto_mode && !strncmp(cur, "-fuse-ld=", 9)) continue;
- if (lto_mode && !strncmp(cur, "--ld-path=", 10)) continue;
- if (!strncmp(cur, "-fno-unroll", 11)) continue;
- if (strstr(cur, "afl-compiler-rt") || strstr(cur, "afl-llvm-rt")) continue;
- if (!strcmp(cur, "-Wl,-z,defs") || !strcmp(cur, "-Wl,--no-undefined") ||
- !strcmp(cur, "--no-undefined")) {
-
- continue;
-
- }
-
- if (!strcmp(cur, "-z") || !strcmp(cur, "-Wl,-z")) {
-
- u8 *param = *(argv + 1);
- if (!strcmp(param, "defs") || !strcmp(param, "-Wl,defs")) {
-
- skip_next = 1;
- continue;
-
- }
-
- }
-
- if ((compiler_mode == GCC || compiler_mode == GCC_PLUGIN) &&
- !strncmp(cur, "-stdlib=", 8)) {
-
- if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); }
- continue;
-
- }
-
- if ((!strncmp(cur, "-fsanitize=fuzzer-", strlen("-fsanitize=fuzzer-")) ||
- !strncmp(cur, "-fsanitize-coverage", strlen("-fsanitize-coverage"))) &&
- (strncmp(cur, "sanitize-coverage-allow",
- strlen("sanitize-coverage-allow")) &&
- strncmp(cur, "sanitize-coverage-deny",
- strlen("sanitize-coverage-deny")) &&
- instrument_mode != INSTRUMENT_LLVMNATIVE)) {
-
- if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); }
- continue;
-
- }
-
- if (!strcmp(cur, "-fsanitize=fuzzer")) {
-
- u8 *afllib = find_object("libAFLDriver.a", argv[0]);
-
- if (!be_quiet) {
-
- OKF("Found '-fsanitize=fuzzer', replacing with libAFLDriver.a");
-
- }
-
- if (!afllib) {
-
- if (!be_quiet) {
-
- WARNF(
- "Cannot find 'libAFLDriver.a' to replace '-fsanitize=fuzzer' in "
- "the flags - this will fail!");
-
- }
-
- } else {
-
- cc_params[cc_par_cnt++] = afllib;
-
-#ifdef __APPLE__
- cc_params[cc_par_cnt++] = "-undefined";
- cc_params[cc_par_cnt++] = "dynamic_lookup";
-#endif
-
- }
-
- continue;
-
- }
-
- if (!strcmp(cur, "-m32")) bit_mode = 32;
- if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32;
- if (!strcmp(cur, "-m64")) bit_mode = 64;
-
- if (!strncmp(cur, "-fsanitize-coverage-", 20) && strstr(cur, "list="))
- have_instr_list = 1;
-
- if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory"))
- asan_set = 1;
-
- if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;
-
- if (!strcmp(cur, "-x")) x_set = 1;
- if (!strcmp(cur, "-E")) preprocessor_only = 1;
- if (!strcmp(cur, "-shared")) shared_linking = 1;
- if (!strcmp(cur, "-dynamiclib")) shared_linking = 1;
- if (!strcmp(cur, "--target=wasm32-wasi")) passthrough = 1;
- if (!strcmp(cur, "-Wl,-r")) partial_linking = 1;
- if (!strcmp(cur, "-Wl,-i")) partial_linking = 1;
- if (!strcmp(cur, "-Wl,--relocatable")) partial_linking = 1;
- if (!strcmp(cur, "-r")) partial_linking = 1;
- if (!strcmp(cur, "--relocatable")) partial_linking = 1;
- if (!strcmp(cur, "-c")) have_c = 1;
-
- if (!strncmp(cur, "-O", 2)) have_o = 1;
- if (!strncmp(cur, "-funroll-loop", 13)) have_unroll = 1;
-
- cc_params[cc_par_cnt++] = cur;
-
- }
+ if (!have_pic) { cc_params[cc_par_cnt++] = "-fPIC"; }
// in case LLVM is installed not via a package manager or "make install"
// e.g. compiled download or compiled from github then its ./lib directory
@@ -849,7 +1143,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (plusplus_mode && strlen(libdir) && strncmp(libdir, "/usr", 4) &&
strncmp(libdir, "/lib", 4)) {
- cc_params[cc_par_cnt++] = "-rpath";
+ cc_params[cc_par_cnt++] = "-Wl,-rpath";
cc_params[cc_par_cnt++] = libdir;
} else {
@@ -922,17 +1216,25 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (getenv("AFL_USE_CFISAN")) {
- if (!lto_mode) {
+ if (compiler_mode == GCC_PLUGIN || compiler_mode == GCC) {
- uint32_t i = 0, found = 0;
- while (envp[i] != NULL && !found)
- if (strncmp("-flto", envp[i++], 5) == 0) found = 1;
- if (!found) cc_params[cc_par_cnt++] = "-flto";
+ cc_params[cc_par_cnt++] = "-fcf-protection=full";
- }
+ } else {
- cc_params[cc_par_cnt++] = "-fsanitize=cfi";
- cc_params[cc_par_cnt++] = "-fvisibility=hidden";
+ if (!lto_mode) {
+
+ uint32_t i = 0, found = 0;
+ while (envp[i] != NULL && !found)
+ if (strncmp("-flto", envp[i++], 5) == 0) found = 1;
+ if (!found) cc_params[cc_par_cnt++] = "-flto";
+
+ }
+
+ cc_params[cc_par_cnt++] = "-fsanitize=cfi";
+ cc_params[cc_par_cnt++] = "-fvisibility=hidden";
+
+ }
}
@@ -965,37 +1267,45 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (!have_c) cc_params[cc_par_cnt++] = "-lrt";
#endif
- cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1";
cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1";
cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1";
- /* When the user tries to use persistent or deferred forkserver modes by
- appending a single line to the program, we want to reliably inject a
- signature into the binary (to be picked up by afl-fuzz) and we want
- to call a function from the runtime .o file. This is unnecessarily
- painful for three reasons:
+ /* As documented in instrumentation/README.persistent_mode.md, deferred
+ forkserver initialization and persistent mode are not available in afl-gcc
+ and afl-clang. */
+ if (compiler_mode != GCC && compiler_mode != CLANG) {
+
+ cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1";
- 1) We need to convince the compiler not to optimize out the signature.
- This is done with __attribute__((used)).
+ /* When the user tries to use persistent or deferred forkserver modes by
+ appending a single line to the program, we want to reliably inject a
+ signature into the binary (to be picked up by afl-fuzz) and we want
+ to call a function from the runtime .o file. This is unnecessarily
+ painful for three reasons:
- 2) We need to convince the linker, when called with -Wl,--gc-sections,
- not to do the same. This is done by forcing an assignment to a
- 'volatile' pointer.
+ 1) We need to convince the compiler not to optimize out the signature.
+ This is done with __attribute__((used)).
- 3) We need to declare __afl_persistent_loop() in the global namespace,
- but doing this within a method in a class is hard - :: and extern "C"
- are forbidden and __attribute__((alias(...))) doesn't work. Hence the
- __asm__ aliasing trick.
+ 2) We need to convince the linker, when called with -Wl,--gc-sections,
+ not to do the same. This is done by forcing an assignment to a
+ 'volatile' pointer.
- */
+ 3) We need to declare __afl_persistent_loop() in the global namespace,
+ but doing this within a method in a class is hard - :: and extern "C"
+ are forbidden and __attribute__((alias(...))) doesn't work. Hence the
+ __asm__ aliasing trick.
- cc_params[cc_par_cnt++] =
- "-D__AFL_FUZZ_INIT()="
- "int __afl_sharedmem_fuzzing = 1;"
- "extern unsigned int *__afl_fuzz_len;"
- "extern unsigned char *__afl_fuzz_ptr;"
- "unsigned char __afl_fuzz_alt[1048576];"
- "unsigned char *__afl_fuzz_alt_ptr = __afl_fuzz_alt;";
+ */
+
+ cc_params[cc_par_cnt++] =
+ "-D__AFL_FUZZ_INIT()="
+ "int __afl_sharedmem_fuzzing = 1;"
+ "extern unsigned int *__afl_fuzz_len;"
+ "extern unsigned char *__afl_fuzz_ptr;"
+ "unsigned char __afl_fuzz_alt[1048576];"
+ "unsigned char *__afl_fuzz_alt_ptr = __afl_fuzz_alt;";
+
+ }
if (plusplus_mode) {
@@ -1033,33 +1343,39 @@ static void edit_params(u32 argc, char **argv, char **envp) {
"(*__afl_fuzz_len = read(0, __afl_fuzz_alt_ptr, 1048576)) == 0xffffffff "
"? 0 : *__afl_fuzz_len)";
- cc_params[cc_par_cnt++] =
- "-D__AFL_LOOP(_A)="
- "({ static volatile char *_B __attribute__((used,unused)); "
- " _B = (char*)\"" PERSIST_SIG
- "\"; "
+ if (compiler_mode != GCC && compiler_mode != CLANG) {
+
+ cc_params[cc_par_cnt++] =
+ "-D__AFL_LOOP(_A)="
+ "({ static volatile const char *_B __attribute__((used,unused)); "
+ " _B = (const char*)\"" PERSIST_SIG
+ "\"; "
+ "extern int __afl_connected;"
#ifdef __APPLE__
- "__attribute__((visibility(\"default\"))) "
- "int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); "
+ "__attribute__((visibility(\"default\"))) "
+ "int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); "
#else
- "__attribute__((visibility(\"default\"))) "
- "int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); "
+ "__attribute__((visibility(\"default\"))) "
+ "int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); "
#endif /* ^__APPLE__ */
- "_L(_A); })";
+ // if afl is connected, we run _A times, else once.
+ "_L(__afl_connected ? _A : 1); })";
- cc_params[cc_par_cnt++] =
- "-D__AFL_INIT()="
- "do { static volatile char *_A __attribute__((used,unused)); "
- " _A = (char*)\"" DEFER_SIG
- "\"; "
+ cc_params[cc_par_cnt++] =
+ "-D__AFL_INIT()="
+ "do { static volatile const char *_A __attribute__((used,unused)); "
+ " _A = (const char*)\"" DEFER_SIG
+ "\"; "
#ifdef __APPLE__
- "__attribute__((visibility(\"default\"))) "
- "void _I(void) __asm__(\"___afl_manual_init\"); "
+ "__attribute__((visibility(\"default\"))) "
+ "void _I(void) __asm__(\"___afl_manual_init\"); "
#else
- "__attribute__((visibility(\"default\"))) "
- "void _I(void) __asm__(\"__afl_manual_init\"); "
+ "__attribute__((visibility(\"default\"))) "
+ "void _I(void) __asm__(\"__afl_manual_init\"); "
#endif /* ^__APPLE__ */
- "_I(); } while (0)";
+ "_I(); } while (0)";
+
+ }
if (x_set) {
@@ -1501,13 +1817,17 @@ int main(int argc, char **argv, char **envp) {
instrument_mode = INSTRUMENT_CLASSIC;
lto_mode = 1;
- } else if (!instrument_mode || instrument_mode == INSTRUMENT_AFL)
+ } else if (!instrument_mode || instrument_mode == INSTRUMENT_AFL) {
instrument_mode = INSTRUMENT_AFL;
- else
+
+ } else {
+
FATAL("main instrumentation mode already set with %s",
instrument_mode_string[instrument_mode]);
+ }
+
}
if (strncasecmp(ptr2, "pc-guard", strlen("pc-guard")) == 0 ||
@@ -1522,7 +1842,8 @@ int main(int argc, char **argv, char **envp) {
}
if (strncasecmp(ptr2, "llvmnative", strlen("llvmnative")) == 0 ||
- strncasecmp(ptr2, "llvm-native", strlen("llvm-native")) == 0) {
+ strncasecmp(ptr2, "llvm-native", strlen("llvm-native")) == 0 ||
+ strncasecmp(ptr2, "native", strlen("native")) == 0) {
if (!instrument_mode || instrument_mode == INSTRUMENT_LLVMNATIVE)
instrument_mode = INSTRUMENT_LLVMNATIVE;
@@ -1532,6 +1853,23 @@ int main(int argc, char **argv, char **envp) {
}
+ if (strncasecmp(ptr2, "llvmcodecov", strlen("llvmcodecov")) == 0 ||
+ strncasecmp(ptr2, "llvm-codecov", strlen("llvm-codecov")) == 0) {
+
+ if (!instrument_mode || instrument_mode == INSTRUMENT_LLVMNATIVE) {
+
+ instrument_mode = INSTRUMENT_LLVMNATIVE;
+ instrument_opt_mode |= INSTRUMENT_OPT_CODECOV;
+
+ } else {
+
+ FATAL("main instrumentation mode already set with %s",
+ instrument_mode_string[instrument_mode]);
+
+ }
+
+ }
+
if (strncasecmp(ptr2, "cfg", strlen("cfg")) == 0 ||
strncasecmp(ptr2, "instrim", strlen("instrim")) == 0) {
@@ -1693,7 +2031,7 @@ int main(int argc, char **argv, char **envp) {
if (!compiler_mode) {
// lto is not a default because outside of afl-cc RANLIB and AR have to
- // be set to llvm versions so this would work
+ // be set to LLVM versions so this would work
if (have_llvm)
compiler_mode = LLVM;
else if (have_gcc_plugin)
@@ -1712,6 +2050,17 @@ int main(int argc, char **argv, char **envp) {
}
+ /* if our PCGUARD implementation is not available then silently switch to
+ native LLVM PCGUARD */
+ if (compiler_mode == CLANG &&
+ (instrument_mode == INSTRUMENT_DEFAULT ||
+ instrument_mode == INSTRUMENT_PCGUARD) &&
+ find_object("SanitizerCoveragePCGUARD.so", argv[0]) == NULL) {
+
+ instrument_mode = INSTRUMENT_LLVMNATIVE;
+
+ }
+
if (compiler_mode == GCC) {
if (clang_mode) {
@@ -1758,12 +2107,12 @@ int main(int argc, char **argv, char **envp) {
"-------------|\n"
"MODES: NCC PERSIST DICT LAF "
"CMPLOG SELECT\n"
- " [LTO] llvm LTO: %s%s\n"
+ " [LTO] LLVM LTO: %s%s\n"
" PCGUARD DEFAULT yes yes yes yes yes "
" yes\n"
" CLASSIC yes yes yes yes yes "
" yes\n"
- " [LLVM] llvm: %s%s\n"
+ " [LLVM] LLVM: %s%s\n"
" PCGUARD %s yes yes module yes yes "
"yes\n"
" CLASSIC %s no yes module yes yes "
@@ -1833,7 +2182,7 @@ int main(int argc, char **argv, char **envp) {
" (instrumentation/README.lto.md)\n"
" PERSIST: persistent mode support [code] (huge speed increase!)\n"
" (instrumentation/README.persistent_mode.md)\n"
- " DICT: dictionary in the target [yes=automatic or llvm module "
+ " DICT: dictionary in the target [yes=automatic or LLVM module "
"pass]\n"
" (instrumentation/README.lto.md + "
"instrumentation/README.llvm.md)\n"
@@ -1879,6 +2228,7 @@ int main(int argc, char **argv, char **envp) {
if (have_gcc_plugin)
SAYF(
"\nGCC Plugin-specific environment variables:\n"
+ " AFL_GCC_CMPLOG: log operands of comparisons (RedQueen mutator)\n"
" AFL_GCC_OUT_OF_LINE: disable inlined instrumentation\n"
" AFL_GCC_SKIP_NEVERZERO: do not skip zero on trace counters\n"
" AFL_GCC_INSTRUMENT_FILE: enable selective instrumentation by "
@@ -1902,6 +2252,8 @@ int main(int argc, char **argv, char **envp) {
" AFL_LLVM_DICT2FILE: generate an afl dictionary based on found "
"comparisons\n"
+ " AFL_LLVM_DICT2FILE_NO_MAIN: skip parsing main() for the "
+ "dictionary\n"
" AFL_LLVM_LAF_ALL: enables all LAF splits/transforms\n"
" AFL_LLVM_LAF_SPLIT_COMPARES: enable cascaded comparisons\n"
" AFL_LLVM_LAF_SPLIT_COMPARES_BITW: size limit (default 8)\n"
@@ -1946,6 +2298,8 @@ int main(int argc, char **argv, char **envp) {
"bb\n"
" AFL_REAL_LD: use this lld linker instead of the compiled in "
"path\n"
+ " AFL_LLVM_LTO_SKIPINIT: don't inject initialization code "
+ "(used in WAFL mode)\n"
"If anything fails - be sure to read README.lto.md!\n");
#endif
@@ -1989,7 +2343,8 @@ int main(int argc, char **argv, char **envp) {
"defaults.\n"
"Recommended is afl-clang-lto with AFL_LLVM_CMPLOG or afl-clang-fast "
"with\n"
- "AFL_LLVM_CMPLOG and AFL_LLVM_DICT2FILE.\n\n");
+ "AFL_LLVM_CMPLOG and "
+ "AFL_LLVM_DICT2FILE+AFL_LLVM_DICT2FILE_NO_MAIN.\n\n");
exit(1);
@@ -2085,7 +2440,8 @@ int main(int argc, char **argv, char **envp) {
"(requires LLVM 11 or higher)");
#endif
- if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC)
+ if (instrument_opt_mode && instrument_opt_mode != INSTRUMENT_OPT_CODECOV &&
+ instrument_mode != INSTRUMENT_CLASSIC)
FATAL(
"CALLER, CTX and NGRAM instrumentation options can only be used with "
"the LLVM CLASSIC instrumentation mode.");
@@ -2149,9 +2505,8 @@ int main(int argc, char **argv, char **envp) {
}
- cmplog_mode = getenv("AFL_CMPLOG") || getenv("AFL_LLVM_CMPLOG");
- if (!be_quiet && cmplog_mode)
- printf("CmpLog mode by <andreafioraldi@gmail.com>\n");
+ cmplog_mode = getenv("AFL_CMPLOG") || getenv("AFL_LLVM_CMPLOG") ||
+ getenv("AFL_GCC_CMPLOG");
#if !defined(__ANDROID__) && !defined(ANDROID)
ptr = find_object("afl-compiler-rt.o", argv[0]);
diff --git a/src/afl-common.c b/src/afl-common.c
index eca7d272..84ddefd8 100644
--- a/src/afl-common.c
+++ b/src/afl-common.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -25,8 +25,13 @@
#include <stdlib.h>
#include <stdio.h>
-#define _GNU_SOURCE
-#define __USE_GNU
+#include "forkserver.h"
+#ifndef _GNU_SOURCE
+ #define _GNU_SOURCE
+#endif
+#ifndef __USE_GNU
+ #define __USE_GNU
+#endif
#include <string.h>
#include <strings.h>
#include <math.h>
@@ -43,6 +48,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include <signal.h>
u8 be_quiet = 0;
u8 *doc_path = "";
@@ -52,6 +58,90 @@ u8 last_intr = 0;
#define AFL_PATH "/usr/local/lib/afl/"
#endif
+void *afl_memmem(const void *haystack, size_t haystacklen, const void *needle,
+ size_t needlelen) {
+
+ if (unlikely(needlelen > haystacklen)) { return NULL; }
+
+ for (u32 i = 0; i <= haystacklen - needlelen; ++i) {
+
+ if (unlikely(memcmp(haystack + i, needle, needlelen) == 0)) {
+
+ return (void *)(haystack + i);
+
+ }
+
+ }
+
+ return (void *)NULL;
+
+}
+
+void set_sanitizer_defaults() {
+
+ /* Set sane defaults for ASAN if nothing else is specified. */
+ u8 *have_asan_options = getenv("ASAN_OPTIONS");
+ u8 *have_ubsan_options = getenv("UBSAN_OPTIONS");
+ u8 *have_msan_options = getenv("MSAN_OPTIONS");
+ u8 *have_lsan_options = getenv("LSAN_OPTIONS");
+ u8 have_san_options = 0;
+ u8 default_options[1024] =
+ "detect_odr_violation=0:abort_on_error=1:symbolize=0:allocator_may_"
+ "return_null=1:handle_segv=0:handle_sigbus=0:handle_abort=0:handle_"
+ "sigfpe=0:handle_sigill=0:";
+
+ if (have_asan_options || have_ubsan_options || have_msan_options ||
+ have_lsan_options) {
+
+ have_san_options = 1;
+
+ }
+
+ /* LSAN does not support abort_on_error=1. (is this still true??) */
+
+ if (!have_lsan_options) {
+
+ u8 buf[2048] = "";
+ if (!have_san_options) { strcpy(buf, default_options); }
+ strcat(buf, "exitcode=" STRINGIFY(LSAN_ERROR) ":fast_unwind_on_malloc=0:print_suppressions=0:detect_leaks=1:malloc_context_size=30:");
+ setenv("LSAN_OPTIONS", buf, 1);
+
+ }
+
+ /* for everything not LSAN we disable detect_leaks */
+
+ if (!have_lsan_options) {
+
+ strcat(default_options, "detect_leaks=0:malloc_context_size=0:");
+
+ }
+
+ /* Set sane defaults for ASAN if nothing else is specified. */
+
+ if (!have_san_options) { setenv("ASAN_OPTIONS", default_options, 1); }
+
+ /* Set sane defaults for UBSAN if nothing else is specified. */
+
+ if (!have_san_options) { setenv("UBSAN_OPTIONS", default_options, 1); }
+
+ /* MSAN is tricky, because it doesn't support abort_on_error=1 at this
+ point. So, we do this in a very hacky way. */
+
+ if (!have_msan_options) {
+
+ u8 buf[2048] = "";
+ if (!have_san_options) { strcpy(buf, default_options); }
+ strcat(buf, "exit_code=" STRINGIFY(MSAN_ERROR) ":msan_track_origins=0:");
+ setenv("MSAN_OPTIONS", buf, 1);
+
+ }
+
+ /* Envs for QASan */
+ setenv("QASAN_MAX_CALL_STACK", "0", 0);
+ setenv("QASAN_SYMBOLIZE", "0", 0);
+
+}
+
u32 check_binary_signatures(u8 *fn) {
int ret = 0, fd = open(fn, O_RDONLY);
@@ -63,7 +153,7 @@ u32 check_binary_signatures(u8 *fn) {
if (f_data == MAP_FAILED) { PFATAL("Unable to mmap file '%s'", fn); }
close(fd);
- if (memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG) + 1)) {
+ 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);
@@ -88,7 +178,7 @@ u32 check_binary_signatures(u8 *fn) {
}
- if (memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
+ 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);
@@ -452,38 +542,57 @@ u8 *find_afl_binary(u8 *own_loc, u8 *fname) {
}
-/* Parses the kill signal environment variable, FATALs on error.
- If the env is not set, sets the env to default_signal for the signal handlers
- and returns the default_signal. */
-int parse_afl_kill_signal_env(u8 *afl_kill_signal_env, int default_signal) {
+int parse_afl_kill_signal(u8 *numeric_signal_as_str, int default_signal) {
- if (afl_kill_signal_env && afl_kill_signal_env[0]) {
+ if (numeric_signal_as_str && numeric_signal_as_str[0]) {
char *endptr;
u8 signal_code;
- signal_code = (u8)strtoul(afl_kill_signal_env, &endptr, 10);
+ signal_code = (u8)strtoul(numeric_signal_as_str, &endptr, 10);
/* Did we manage to parse the full string? */
- if (*endptr != '\0' || endptr == (char *)afl_kill_signal_env) {
+ if (*endptr != '\0' || endptr == (char *)numeric_signal_as_str) {
- FATAL("Invalid AFL_KILL_SIGNAL: %s (expected unsigned int)",
- afl_kill_signal_env);
+ FATAL("Invalid signal name: %s", numeric_signal_as_str);
+
+ } else {
+
+ return signal_code;
}
- return signal_code;
+ }
+
+ return default_signal;
- } else {
+}
- char *sigstr = alloc_printf("%d", default_signal);
- if (!sigstr) { FATAL("Failed to alloc mem for signal buf"); }
+void configure_afl_kill_signals(afl_forkserver_t *fsrv,
+ char *afl_kill_signal_env,
+ char *afl_fsrv_kill_signal_env,
+ int default_server_kill_signal) {
- /* Set the env for signal handler */
- setenv("AFL_KILL_SIGNAL", sigstr, 1);
- free(sigstr);
- return default_signal;
+ afl_kill_signal_env =
+ afl_kill_signal_env ? afl_kill_signal_env : getenv("AFL_KILL_SIGNAL");
+ afl_fsrv_kill_signal_env = afl_fsrv_kill_signal_env
+ ? afl_fsrv_kill_signal_env
+ : getenv("AFL_FORK_SERVER_KILL_SIGNAL");
+
+ fsrv->child_kill_signal = parse_afl_kill_signal(afl_kill_signal_env, SIGKILL);
+
+ if (afl_kill_signal_env && !afl_fsrv_kill_signal_env) {
+
+ /*
+ Set AFL_FORK_SERVER_KILL_SIGNAL to the value of AFL_KILL_SIGNAL for
+ backwards compatibility. However, if AFL_FORK_SERVER_KILL_SIGNAL is set, is
+ takes precedence.
+ */
+ afl_fsrv_kill_signal_env = afl_kill_signal_env;
}
+ fsrv->fsrv_kill_signal = parse_afl_kill_signal(afl_fsrv_kill_signal_env,
+ default_server_kill_signal);
+
}
static inline unsigned int helper_min3(unsigned int a, unsigned int b,
@@ -554,9 +663,9 @@ void print_suggested_envs(char *mispelled_env) {
for (j = 0; afl_environment_variables[j] != NULL; ++j) {
- char * afl_env = afl_environment_variables[j] + 4;
+ char *afl_env = afl_environment_variables[j] + 4;
size_t afl_env_len = strlen(afl_env);
- char * reduced = ck_alloc(afl_env_len + 1);
+ char *reduced = ck_alloc(afl_env_len + 1);
size_t start = 0;
while (start < afl_env_len) {
@@ -594,7 +703,7 @@ void print_suggested_envs(char *mispelled_env) {
if (found) goto cleanup;
- char * reduced = ck_alloc(env_name_len + 1);
+ char *reduced = ck_alloc(env_name_len + 1);
size_t start = 0;
while (start < env_name_len) {
@@ -715,17 +824,23 @@ char *get_afl_env(char *env) {
char *val;
- if ((val = getenv(env)) != NULL) {
+ if ((val = getenv(env))) {
- if (!be_quiet) {
+ if (*val) {
- OKF("Loaded environment variable %s with value %s", env, val);
+ if (!be_quiet) {
+
+ OKF("Enabled environment variable %s with value %s", env, val);
+
+ }
+
+ return val;
}
}
- return val;
+ return NULL;
}
@@ -834,7 +949,7 @@ void read_bitmap(u8 *fname, u8 *map, size_t len) {
/* Get unix time in milliseconds */
-u64 get_cur_time(void) {
+inline u64 get_cur_time(void) {
struct timeval tv;
struct timezone tz;
@@ -1187,7 +1302,7 @@ u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms) {
u32 get_map_size(void) {
uint32_t map_size = DEFAULT_SHMEM_SIZE;
- char * ptr;
+ char *ptr;
if ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE"))) {
@@ -1244,3 +1359,52 @@ s32 create_file(u8 *fn) {
}
+#ifdef __linux__
+
+/* Nyx requires a tmp workdir to access specific files (such as mmapped files,
+ * etc.). This helper function basically creates both a path to a tmp workdir
+ * and the workdir itself. If the environment variable TMPDIR is set, we use
+ * that as the base directory, otherwise we use /tmp. */
+char *create_nyx_tmp_workdir(void) {
+
+ char *tmpdir = getenv("TMPDIR");
+
+ if (!tmpdir) { tmpdir = "/tmp"; }
+
+ char *nyx_out_dir_path =
+ alloc_printf("%s/.nyx_tmp_%d/", tmpdir, (u32)getpid());
+
+ if (mkdir(nyx_out_dir_path, 0700)) { PFATAL("Unable to create nyx workdir"); }
+
+ return nyx_out_dir_path;
+
+}
+
+/* Vice versa, we remove the tmp workdir for nyx with this helper function. */
+void remove_nyx_tmp_workdir(afl_forkserver_t *fsrv, char *nyx_out_dir_path) {
+
+ char *workdir_path = alloc_printf("%s/workdir", nyx_out_dir_path);
+
+ if (access(workdir_path, R_OK) == 0) {
+
+ if (fsrv->nyx_handlers->nyx_remove_work_dir(workdir_path) != true) {
+
+ WARNF("Unable to remove nyx workdir (%s)", workdir_path);
+
+ }
+
+ }
+
+ if (rmdir(nyx_out_dir_path)) {
+
+ WARNF("Unable to remove nyx workdir (%s)", nyx_out_dir_path);
+
+ }
+
+ ck_free(workdir_path);
+ ck_free(nyx_out_dir_path);
+
+}
+
+#endif
+
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index 628ff590..7322f1ad 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -13,7 +13,7 @@
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -49,6 +49,134 @@
#include <sys/select.h>
#include <sys/stat.h>
+#ifdef __linux__
+ #include <dlfcn.h>
+
+/* function to load nyx_helper function from libnyx.so */
+
+nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) {
+
+ void *handle;
+ nyx_plugin_handler_t *plugin = calloc(1, sizeof(nyx_plugin_handler_t));
+
+ ACTF("Trying to load libnyx.so plugin...");
+ handle = dlopen((char *)libnyx_binary, RTLD_NOW);
+ if (!handle) { goto fail; }
+
+ plugin->nyx_config_load = dlsym(handle, "nyx_config_load");
+ if (plugin->nyx_config_load == NULL) { goto fail; }
+
+ plugin->nyx_config_set_workdir_path =
+ dlsym(handle, "nyx_config_set_workdir_path");
+ if (plugin->nyx_config_set_workdir_path == NULL) { goto fail; }
+
+ plugin->nyx_config_set_input_buffer_size =
+ dlsym(handle, "nyx_config_set_input_buffer_size");
+ if (plugin->nyx_config_set_input_buffer_size == NULL) { goto fail; }
+
+ plugin->nyx_config_set_input_buffer_write_protection =
+ dlsym(handle, "nyx_config_set_input_buffer_write_protection");
+ if (plugin->nyx_config_set_input_buffer_write_protection == NULL) {
+
+ goto fail;
+
+ }
+
+ plugin->nyx_config_set_hprintf_fd =
+ dlsym(handle, "nyx_config_set_hprintf_fd");
+ if (plugin->nyx_config_set_hprintf_fd == NULL) { goto fail; }
+
+ plugin->nyx_config_set_process_role =
+ dlsym(handle, "nyx_config_set_process_role");
+ if (plugin->nyx_config_set_process_role == NULL) { goto fail; }
+
+ plugin->nyx_config_set_reuse_snapshot_path =
+ dlsym(handle, "nyx_config_set_reuse_snapshot_path");
+ if (plugin->nyx_config_set_reuse_snapshot_path == NULL) { goto fail; }
+
+ plugin->nyx_new = dlsym(handle, "nyx_new");
+ if (plugin->nyx_new == NULL) { goto fail; }
+
+ plugin->nyx_shutdown = dlsym(handle, "nyx_shutdown");
+ if (plugin->nyx_shutdown == NULL) { goto fail; }
+
+ plugin->nyx_option_set_reload_mode =
+ dlsym(handle, "nyx_option_set_reload_mode");
+ if (plugin->nyx_option_set_reload_mode == NULL) { goto fail; }
+
+ plugin->nyx_option_set_timeout = dlsym(handle, "nyx_option_set_timeout");
+ if (plugin->nyx_option_set_timeout == NULL) { goto fail; }
+
+ plugin->nyx_option_apply = dlsym(handle, "nyx_option_apply");
+ if (plugin->nyx_option_apply == NULL) { goto fail; }
+
+ plugin->nyx_set_afl_input = dlsym(handle, "nyx_set_afl_input");
+ if (plugin->nyx_set_afl_input == NULL) { goto fail; }
+
+ plugin->nyx_exec = dlsym(handle, "nyx_exec");
+ if (plugin->nyx_exec == NULL) { goto fail; }
+
+ plugin->nyx_get_bitmap_buffer = dlsym(handle, "nyx_get_bitmap_buffer");
+ if (plugin->nyx_get_bitmap_buffer == NULL) { goto fail; }
+
+ plugin->nyx_get_bitmap_buffer_size =
+ dlsym(handle, "nyx_get_bitmap_buffer_size");
+ if (plugin->nyx_get_bitmap_buffer_size == NULL) { goto fail; }
+
+ plugin->nyx_get_aux_string = dlsym(handle, "nyx_get_aux_string");
+ if (plugin->nyx_get_aux_string == NULL) { goto fail; }
+
+ plugin->nyx_remove_work_dir = dlsym(handle, "nyx_remove_work_dir");
+ if (plugin->nyx_remove_work_dir == NULL) { goto fail; }
+
+ OKF("libnyx plugin is ready!");
+ return plugin;
+
+fail:
+
+ FATAL("failed to load libnyx: %s\n", dlerror());
+ ck_free(plugin);
+ return NULL;
+
+}
+
+void afl_nyx_runner_kill(afl_forkserver_t *fsrv) {
+
+ if (fsrv->nyx_mode) {
+
+ if (fsrv->nyx_aux_string) { ck_free(fsrv->nyx_aux_string); }
+
+ /* check if we actually got a valid nyx runner */
+ if (fsrv->nyx_runner) {
+
+ fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
+
+ }
+
+ /* if we have use a tmp work dir we need to remove it */
+ if (fsrv->nyx_use_tmp_workdir && fsrv->nyx_tmp_workdir_path) {
+
+ remove_nyx_tmp_workdir(fsrv, fsrv->nyx_tmp_workdir_path);
+
+ }
+
+ }
+
+}
+
+ /* Wrapper for FATAL() that kills the nyx runner (and removes all created tmp
+ * files) before exiting. Used before "afl_fsrv_killall()" is registered as
+ * an atexit() handler. */
+ #define NYX_PRE_FATAL(fsrv, x...) \
+ do { \
+ \
+ afl_nyx_runner_kill(fsrv); \
+ FATAL(x); \
+ \
+ } while (0)
+
+#endif
+
/**
* The correct fds for reading and writing pipes
*/
@@ -84,6 +212,8 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
fsrv->nyx_runner = NULL;
fsrv->nyx_id = 0xFFFFFFFF;
fsrv->nyx_bind_cpu_id = 0xFFFFFFFF;
+ fsrv->nyx_use_tmp_workdir = false;
+ fsrv->nyx_tmp_workdir_path = NULL;
#endif
// this structure needs default so we initialize it if this was not done
@@ -100,7 +230,7 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
fsrv->init_tmout = EXEC_TIMEOUT * FORK_WAIT_MULT;
fsrv->mem_limit = MEM_LIMIT;
fsrv->out_file = NULL;
- fsrv->kill_signal = SIGKILL;
+ fsrv->child_kill_signal = SIGKILL;
/* exec related stuff */
fsrv->child_pid = -1;
@@ -134,7 +264,7 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
fsrv_to->no_unlink = from->no_unlink;
fsrv_to->uses_crash_exitcode = from->uses_crash_exitcode;
fsrv_to->crash_exitcode = from->crash_exitcode;
- fsrv_to->kill_signal = from->kill_signal;
+ fsrv_to->child_kill_signal = from->child_kill_signal;
fsrv_to->debug = from->debug;
// These are forkserver specific.
@@ -359,7 +489,7 @@ static void report_error_and_exit(int error) {
break;
case FS_ERROR_OLD_CMPLOG:
FATAL(
- "the -c cmplog target was instrumented with an too old afl++ "
+ "the -c cmplog target was instrumented with an too old AFL++ "
"version, you need to recompile it.");
break;
case FS_ERROR_OLD_CMPLOG_QEMU:
@@ -397,40 +527,119 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
if (!be_quiet) { ACTF("Spinning up the NYX backend..."); }
- if (fsrv->out_dir_path == NULL) { FATAL("Nyx workdir path not found..."); }
+ if (fsrv->nyx_use_tmp_workdir) {
+
+ fsrv->nyx_tmp_workdir_path = create_nyx_tmp_workdir();
+ fsrv->out_dir_path = fsrv->nyx_tmp_workdir_path;
+
+ } else {
+
+ if (fsrv->out_dir_path == NULL) {
+
+ NYX_PRE_FATAL(fsrv, "Nyx workdir path not found...");
+
+ }
+
+ }
+
+ /* libnyx expects an absolute path */
+ char *outdir_path_absolute = realpath(fsrv->out_dir_path, NULL);
+ if (outdir_path_absolute == NULL) {
- char *x = alloc_printf("%s/workdir", fsrv->out_dir_path);
+ NYX_PRE_FATAL(fsrv, "Nyx workdir path cannot be resolved ...");
- if (fsrv->nyx_id == 0xFFFFFFFF) { FATAL("Nyx ID is not set..."); }
+ }
+
+ char *workdir_path = alloc_printf("%s/workdir", outdir_path_absolute);
+
+ if (fsrv->nyx_id == 0xFFFFFFFF) {
+
+ NYX_PRE_FATAL(fsrv, "Nyx ID is not set...");
+
+ }
if (fsrv->nyx_bind_cpu_id == 0xFFFFFFFF) {
- FATAL("Nyx CPU ID is not set...");
+ NYX_PRE_FATAL(fsrv, "Nyx CPU ID is not set...");
}
+ void *nyx_config = fsrv->nyx_handlers->nyx_config_load(fsrv->target_path);
+
+ fsrv->nyx_handlers->nyx_config_set_workdir_path(nyx_config, workdir_path);
+ fsrv->nyx_handlers->nyx_config_set_input_buffer_size(nyx_config, MAX_FILE);
+ fsrv->nyx_handlers->nyx_config_set_input_buffer_write_protection(nyx_config,
+ true);
+
if (fsrv->nyx_standalone) {
- fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new(
- fsrv->target_path, x, fsrv->nyx_bind_cpu_id, MAX_FILE, true);
+ fsrv->nyx_handlers->nyx_config_set_process_role(nyx_config, StandAlone);
} else {
if (fsrv->nyx_parent) {
- fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new_parent(
- fsrv->target_path, x, fsrv->nyx_bind_cpu_id, MAX_FILE, true);
+ fsrv->nyx_handlers->nyx_config_set_process_role(nyx_config, Parent);
} else {
- fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new_child(
- fsrv->target_path, x, fsrv->nyx_bind_cpu_id, fsrv->nyx_id);
+ fsrv->nyx_handlers->nyx_config_set_process_role(nyx_config, Child);
+
+ }
+
+ }
+
+ if (getenv("NYX_REUSE_SNAPSHOT") != NULL) {
+
+ if (access(getenv("NYX_REUSE_SNAPSHOT"), F_OK) == -1) {
+
+ NYX_PRE_FATAL(fsrv, "NYX_REUSE_SNAPSHOT path does not exist");
+
+ }
+
+ /* stupid sanity check to avoid passing an empty or invalid snapshot
+ * directory */
+ char *snapshot_file_path =
+ alloc_printf("%s/global.state", getenv("NYX_REUSE_SNAPSHOT"));
+ if (access(snapshot_file_path, R_OK) == -1) {
+
+ NYX_PRE_FATAL(
+ fsrv,
+ "NYX_REUSE_SNAPSHOT path does not contain a valid Nyx snapshot");
+
+ }
+
+ ck_free(snapshot_file_path);
+
+ /* another sanity check to avoid passing a snapshot directory that is
+ * located in the current workdir (the workdir will be wiped by libnyx on
+ * startup) */
+ char *workdir_snapshot_path =
+ alloc_printf("%s/workdir/snapshot", outdir_path_absolute);
+ char *reuse_snapshot_path_real =
+ realpath(getenv("NYX_REUSE_SNAPSHOT"), NULL);
+
+ if (strcmp(workdir_snapshot_path, reuse_snapshot_path_real) == 0) {
+
+ NYX_PRE_FATAL(fsrv,
+ "NYX_REUSE_SNAPSHOT path is located in current workdir "
+ "(use another output directory)");
}
+ ck_free(reuse_snapshot_path_real);
+ ck_free(workdir_snapshot_path);
+
+ fsrv->nyx_handlers->nyx_config_set_reuse_snapshot_path(
+ nyx_config, getenv("NYX_REUSE_SNAPSHOT"));
+
}
- ck_free(x);
+ fsrv->nyx_runner =
+ fsrv->nyx_handlers->nyx_new(nyx_config, fsrv->nyx_bind_cpu_id);
+
+ ck_free(workdir_path);
+ ck_free(outdir_path_absolute);
if (fsrv->nyx_runner == NULL) { FATAL("Something went wrong ..."); }
@@ -458,15 +667,13 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
switch (fsrv->nyx_handlers->nyx_exec(fsrv->nyx_runner)) {
case Abort:
- fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
- FATAL("Error: Nyx abort occured...");
+ NYX_PRE_FATAL(fsrv, "Error: Nyx abort occured...");
break;
case IoError:
- FATAL("Error: QEMU-Nyx has died...");
+ NYX_PRE_FATAL(fsrv, "Error: QEMU-Nyx has died...");
break;
case Error:
- fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
- FATAL("Error: Nyx runtime error has occured...");
+ NYX_PRE_FATAL(fsrv, "Error: Nyx runtime error has occured...");
break;
default:
break;
@@ -476,7 +683,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
/* autodict in Nyx mode */
if (!ignore_autodict) {
- x = alloc_printf("%s/workdir/dump/afl_autodict.txt", fsrv->out_dir_path);
+ char *x =
+ alloc_printf("%s/workdir/dump/afl_autodict.txt", fsrv->out_dir_path);
int nyx_autodict_fd = open(x, O_RDONLY);
ck_free(x);
@@ -489,8 +697,9 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
u8 *dict = ck_alloc(f_len);
if (dict == NULL) {
- FATAL("Could not allocate %u bytes of autodictionary memory",
- f_len);
+ NYX_PRE_FATAL(
+ fsrv, "Could not allocate %u bytes of autodictionary memory",
+ f_len);
}
@@ -507,7 +716,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
} else {
- FATAL(
+ NYX_PRE_FATAL(
+ fsrv,
"Reading autodictionary fail at position %u with %u bytes "
"left.",
offset, len);
@@ -688,70 +898,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
if (!getenv("LD_BIND_LAZY")) { setenv("LD_BIND_NOW", "1", 1); }
- /* Set sane defaults for ASAN if nothing else is specified. */
-
- if (!getenv("ASAN_OPTIONS"))
- setenv("ASAN_OPTIONS",
- "abort_on_error=1:"
- "detect_leaks=0:"
- "malloc_context_size=0:"
- "symbolize=0:"
- "allocator_may_return_null=1:"
- "detect_odr_violation=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0",
- 1);
-
- /* Set sane defaults for UBSAN if nothing else is specified. */
-
- if (!getenv("UBSAN_OPTIONS"))
- setenv("UBSAN_OPTIONS",
- "halt_on_error=1:"
- "abort_on_error=1:"
- "malloc_context_size=0:"
- "allocator_may_return_null=1:"
- "symbolize=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0",
- 1);
-
- /* Envs for QASan */
- setenv("QASAN_MAX_CALL_STACK", "0", 0);
- setenv("QASAN_SYMBOLIZE", "0", 0);
-
- /* MSAN is tricky, because it doesn't support abort_on_error=1 at this
- point. So, we do this in a very hacky way. */
-
- if (!getenv("MSAN_OPTIONS"))
- setenv("MSAN_OPTIONS",
- "exit_code=" STRINGIFY(MSAN_ERROR) ":"
- "symbolize=0:"
- "abort_on_error=1:"
- "malloc_context_size=0:"
- "allocator_may_return_null=1:"
- "msan_track_origins=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0",
- 1);
-
- /* LSAN, too, does not support abort_on_error=1. */
-
- if (!getenv("LSAN_OPTIONS"))
- setenv("LSAN_OPTIONS",
- "exitcode=" STRINGIFY(LSAN_ERROR) ":"
- "fast_unwind_on_malloc=0:"
- "symbolize=0:"
- "print_suppressions=0",
- 1);
+ /* Set sane defaults for sanitizers */
+ set_sanitizer_defaults();
fsrv->init_child_func(fsrv, argv);
@@ -793,7 +941,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
s32 tmp_pid = fsrv->fsrv_pid;
if (tmp_pid > 0) {
- kill(tmp_pid, fsrv->kill_signal);
+ kill(tmp_pid, fsrv->child_kill_signal);
fsrv->fsrv_pid = -1;
}
@@ -804,7 +952,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
s32 tmp_pid = fsrv->fsrv_pid;
if (tmp_pid > 0) {
- kill(tmp_pid, fsrv->kill_signal);
+ kill(tmp_pid, fsrv->child_kill_signal);
fsrv->fsrv_pid = -1;
}
@@ -839,7 +987,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) {
- // workaround for recent afl++ versions
+ // workaround for recent AFL++ versions
if ((status & FS_OPT_OLD_AFLPP_WORKAROUND) == FS_OPT_OLD_AFLPP_WORKAROUND)
status = (status & 0xf0ffffff);
@@ -911,7 +1059,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
FATAL(
"Target's coverage map size of %u is larger than the one this "
- "afl++ is set with (%u). Either set AFL_MAP_SIZE=%u and restart "
+ "AFL++ is set with (%u). Either set AFL_MAP_SIZE=%u and restart "
" afl-fuzz, or change MAP_SIZE_POW2 in config.h and recompile "
"afl-fuzz",
tmp_map_size, fsrv->map_size, tmp_map_size);
@@ -1078,7 +1226,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
" - Less likely, there is a horrible bug in the fuzzer. If other "
"options\n"
- " fail, poke <afl-users@googlegroups.com> for troubleshooting "
+ " fail, poke the Awesome Fuzzing Discord for troubleshooting "
"tips.\n");
} else {
@@ -1123,7 +1271,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
" - Less likely, there is a horrible bug in the fuzzer. If other "
"options\n"
- " fail, poke <afl-users@googlegroups.com> for troubleshooting "
+ " fail, poke the Awesome Fuzzing Discord for troubleshooting "
"tips.\n",
stringify_mem_size(val_buf, sizeof(val_buf), fsrv->mem_limit << 20),
fsrv->mem_limit - 1);
@@ -1173,7 +1321,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
" Retry with setting AFL_MAP_SIZE=10000000.\n\n"
"Otherwise there is a horrible bug in the fuzzer.\n"
- "Poke <afl-users@googlegroups.com> for troubleshooting tips.\n");
+ "Poke the Awesome Fuzzing Discord for troubleshooting tips.\n");
} else {
@@ -1222,7 +1370,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
" - Less likely, there is a horrible bug in the fuzzer. If other "
"options\n"
- " fail, poke <afl-users@googlegroups.com> for troubleshooting "
+ " fail, poke the Awesome Fuzzing Discord for troubleshooting "
"tips.\n",
getenv(DEFER_ENV_VAR)
? " - You are using deferred forkserver, but __AFL_INIT() is "
@@ -1242,11 +1390,11 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
void afl_fsrv_kill(afl_forkserver_t *fsrv) {
- if (fsrv->child_pid > 0) { kill(fsrv->child_pid, fsrv->kill_signal); }
+ if (fsrv->child_pid > 0) { kill(fsrv->child_pid, fsrv->child_kill_signal); }
if (fsrv->fsrv_pid > 0) {
- kill(fsrv->fsrv_pid, fsrv->kill_signal);
- if (waitpid(fsrv->fsrv_pid, NULL, 0) <= 0) { WARNF("error waitpid\n"); }
+ kill(fsrv->fsrv_pid, fsrv->fsrv_kill_signal);
+ waitpid(fsrv->fsrv_pid, NULL, 0);
}
@@ -1256,13 +1404,7 @@ void afl_fsrv_kill(afl_forkserver_t *fsrv) {
fsrv->child_pid = -1;
#ifdef __linux__
- if (fsrv->nyx_mode) {
-
- free(fsrv->nyx_aux_string);
- fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
-
- }
-
+ afl_nyx_runner_kill(fsrv);
#endif
}
@@ -1432,14 +1574,13 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
case Crash:
case Asan:
return FSRV_RUN_CRASH;
- case Timout:
+ case Timeout:
return FSRV_RUN_TMOUT;
case InvalidWriteToPayload:
/* ??? */
FATAL("FixMe: Nyx InvalidWriteToPayload handler is missing");
break;
case Abort:
- fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
FATAL("Error: Nyx abort occured...");
case IoError:
if (*stop_soon_p) {
@@ -1545,7 +1686,7 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
s32 tmp_pid = fsrv->child_pid;
if (tmp_pid > 0) {
- kill(tmp_pid, fsrv->kill_signal);
+ kill(tmp_pid, fsrv->child_kill_signal);
fsrv->child_pid = -1;
}
@@ -1605,7 +1746,7 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
/* Did we timeout? */
if (unlikely(fsrv->last_run_timed_out)) {
- fsrv->last_kill_signal = fsrv->kill_signal;
+ fsrv->last_kill_signal = fsrv->child_kill_signal;
return FSRV_RUN_TMOUT;
}
diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c
index 26e70d81..556bb5d1 100644
--- a/src/afl-fuzz-bitmap.c
+++ b/src/afl-fuzz-bitmap.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -457,9 +457,16 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
if (unlikely(len == 0)) { return 0; }
+ if (unlikely(fault == FSRV_RUN_TMOUT && afl->afl_env.afl_ignore_timeouts)) {
+
+ return 0;
+
+ }
+
u8 fn[PATH_MAX];
u8 *queue_fn = "";
- u8 new_bits = 0, keeping = 0, res, classified = 0, is_timeout = 0;
+ u8 new_bits = 0, keeping = 0, res, classified = 0, is_timeout = 0,
+ need_hash = 1;
s32 fd;
u64 cksum = 0;
@@ -469,10 +476,14 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
only be used for special schedules */
if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
+ classify_counts(&afl->fsrv);
+ classified = 1;
+ need_hash = 0;
+
cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
/* Saturated increment */
- if (afl->n_fuzz[cksum % N_FUZZ_SIZE] < 0xFFFFFFFF)
+ if (likely(afl->n_fuzz[cksum % N_FUZZ_SIZE] < 0xFFFFFFFF))
afl->n_fuzz[cksum % N_FUZZ_SIZE]++;
}
@@ -482,7 +493,17 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
/* Keep only if there are new bits in the map, add to queue for
future fuzzing, etc. */
- new_bits = has_new_bits_unclassified(afl, afl->virgin_bits);
+ if (likely(classified)) {
+
+ new_bits = has_new_bits(afl, afl->virgin_bits);
+
+ } else {
+
+ new_bits = has_new_bits_unclassified(afl, afl->virgin_bits);
+
+ if (unlikely(new_bits)) { classified = 1; }
+
+ }
if (likely(!new_bits)) {
@@ -491,8 +512,6 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
}
- classified = new_bits;
-
save_to_queue:
#ifndef SIMPLE_FILES
@@ -550,21 +569,25 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
}
- /* AFLFast schedule? update the new queue entry */
- if (cksum) {
+ if (unlikely(need_hash && new_bits)) {
+
+ /* due to classify counts we have to recalculate the checksum */
+ afl->queue_top->exec_cksum =
+ hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+ need_hash = 0;
+
+ }
+
+ /* For AFLFast schedules we update the new queue entry */
+ if (likely(cksum)) {
afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE;
afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1;
}
- /* 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);
-
/* Try to calibrate inline; this also calls update_bitmap_score() when
successful. */
-
res = calibrate_case(afl, afl->queue_top, mem, afl->queue_cycle - 1, 0);
if (unlikely(res == FSRV_RUN_ERROR)) {
@@ -598,7 +621,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
if (likely(!afl->non_instrumented_mode)) {
- if (!classified) {
+ if (unlikely(!classified)) {
classify_counts(&afl->fsrv);
classified = 1;
@@ -647,8 +670,19 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
if (afl->fsrv.exec_tmout < afl->hang_tmout) {
- u8 new_fault;
- len = write_to_testcase(afl, &mem, len, 0);
+ u8 new_fault;
+ u32 tmp_len = write_to_testcase(afl, &mem, len, 0);
+
+ if (likely(tmp_len)) {
+
+ len = tmp_len;
+
+ } else {
+
+ len = write_to_testcase(afl, &mem, len, 1);
+
+ }
+
new_fault = fuzz_run_target(afl, &afl->fsrv, afl->hang_tmout);
classify_counts(&afl->fsrv);
@@ -712,7 +746,12 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
if (likely(!afl->non_instrumented_mode)) {
- if (!classified) { classify_counts(&afl->fsrv); }
+ if (unlikely(!classified)) {
+
+ classify_counts(&afl->fsrv);
+ classified = 1;
+
+ }
simplify_trace(afl, afl->fsrv.trace_bits);
@@ -720,7 +759,12 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
}
- if (unlikely(!afl->saved_crashes)) { write_crash_readme(afl); }
+ if (unlikely(!afl->saved_crashes) &&
+ (afl->afl_env.afl_no_crash_readme != 1)) {
+
+ write_crash_readme(afl);
+
+ }
#ifndef SIMPLE_FILES
diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c
index 258d9ea7..3e6432ca 100644
--- a/src/afl-fuzz-cmplog.c
+++ b/src/afl-fuzz-cmplog.c
@@ -11,7 +11,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -33,23 +33,36 @@ void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) {
setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1);
- if (fsrv->qemu_mode) { setenv("AFL_DISABLE_LLVM_INSTRUMENTATION", "1", 0); }
+ if (fsrv->qemu_mode || fsrv->cs_mode) {
+
+ setenv("AFL_DISABLE_LLVM_INSTRUMENTATION", "1", 0);
+
+ }
if (!fsrv->qemu_mode && !fsrv->frida_mode && argv[0] != fsrv->cmplog_binary) {
- argv[0] = fsrv->cmplog_binary;
+ fsrv->target_path = argv[0] = fsrv->cmplog_binary;
}
- execv(argv[0], argv);
+ execv(fsrv->target_path, argv);
}
u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
- u8 fault;
+ u8 fault;
+ u32 tmp_len = write_to_testcase(afl, (void **)&out_buf, len, 0);
+
+ if (likely(tmp_len)) {
+
+ len = tmp_len;
- write_to_testcase(afl, (void **)&out_buf, len, 0);
+ } else {
+
+ len = write_to_testcase(afl, (void **)&out_buf, len, 1);
+
+ }
fault = fuzz_run_target(afl, &afl->cmplog_fsrv, afl->fsrv.exec_tmout);
diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c
index 535ffdc3..f6de11ae 100644
--- a/src/afl-fuzz-extras.c
+++ b/src/afl-fuzz-extras.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -57,7 +57,7 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len,
FILE *f;
u8 buf[MAX_LINE];
- u8 * lptr;
+ u8 *lptr;
u32 cur_line = 0;
u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX];
@@ -291,10 +291,10 @@ static void extras_check_and_sort(afl_state_t *afl, u32 min_len, u32 max_len,
void load_extras(afl_state_t *afl, u8 *dir) {
- DIR * d;
+ DIR *d;
struct dirent *de;
u32 min_len = MAX_DICT_FILE, max_len = 0, dict_level = 0;
- u8 * x;
+ u8 *x;
u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX];
@@ -330,7 +330,7 @@ void load_extras(afl_state_t *afl, u8 *dir) {
while ((de = readdir(d))) {
struct stat st;
- u8 * fn = alloc_printf("%s/%s", dir, de->d_name);
+ u8 *fn = alloc_printf("%s/%s", dir, de->d_name);
s32 fd;
if (lstat(fn, &st) || access(fn, R_OK)) {
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index 6a653a00..13802f40 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -24,7 +24,9 @@
*/
#include "afl-fuzz.h"
+#include "common.h"
#include <limits.h>
+#include <string.h>
#include "cmplog.h"
#ifdef HAVE_AFFINITY
@@ -146,6 +148,10 @@ void bind_to_free_cpu(afl_state_t *afl) {
}
+ } else {
+
+ OKF("CPU binding request using -b %d successful.", afl->cpu_to_bind);
+
}
return;
@@ -185,7 +191,7 @@ void bind_to_free_cpu(afl_state_t *afl) {
#if defined(__linux__)
- DIR * d;
+ DIR *d;
struct dirent *de;
d = opendir("/proc");
@@ -336,8 +342,8 @@ void bind_to_free_cpu(afl_state_t *afl) {
#elif defined(__sun)
kstat_named_t *n;
- kstat_ctl_t * m;
- kstat_t * k;
+ kstat_ctl_t *m;
+ kstat_t *k;
cpu_stat_t cs;
u32 ncpus;
@@ -653,7 +659,7 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
struct dirent **nl;
s32 nl_cnt, subdirs = 1;
u32 i;
- u8 * fn1, *dir = directory;
+ u8 *fn1, *dir = directory;
u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX];
/* Auto-detect non-in-place resumption attempts. */
@@ -710,12 +716,25 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
}
+ // if (getenv("MYTEST")) afl->in_place_resume = 1;
+
if (nl_cnt) {
- i = nl_cnt;
+ u32 done = 0;
+
+ if (unlikely(afl->in_place_resume)) {
+
+ i = nl_cnt;
+
+ } else {
+
+ i = 0;
+
+ }
+
do {
- --i;
+ if (unlikely(afl->in_place_resume)) { --i; }
struct stat st;
u8 dfn[PATH_MAX];
@@ -739,7 +758,7 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
free(nl[i]); /* not tracked */
read_testcases(afl, fn2);
ck_free(fn2);
- continue;
+ goto next_entry;
}
@@ -748,7 +767,7 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) {
ck_free(fn2);
- continue;
+ goto next_entry;
}
@@ -795,21 +814,23 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
}
- /*
- if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
+ next_entry:
+ if (unlikely(afl->in_place_resume)) {
- u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size,
- HASH_CONST); afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE;
- afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1;
+ if (unlikely(i == 0)) { done = 1; }
- }
+ } else {
+
+ if (unlikely(++i >= (u32)nl_cnt)) { done = 1; }
- */
+ }
- } while (i > 0);
+ } while (!done);
}
+ // if (getenv("MYTEST")) afl->in_place_resume = 0;
+
free(nl); /* not tracked */
if (!afl->queued_items && directory == NULL) {
@@ -853,7 +874,7 @@ void perform_dry_run(afl_state_t *afl) {
struct queue_entry *q;
u32 cal_failures = 0, idx;
- u8 * use_mem;
+ u8 *use_mem;
for (idx = 0; idx < afl->queued_items; idx++) {
@@ -891,8 +912,10 @@ void perform_dry_run(afl_state_t *afl) {
if (res == afl->crash_mode || res == FSRV_RUN_NOBITS) {
- SAYF(cGRA " len = %u, map size = %u, exec speed = %llu us\n" cRST,
- q->len, q->bitmap_size, q->exec_us);
+ SAYF(cGRA
+ " len = %u, map size = %u, exec speed = %llu us, hash = "
+ "%016llx\n" cRST,
+ q->len, q->bitmap_size, q->exec_us, q->exec_cksum);
}
@@ -989,7 +1012,7 @@ void perform_dry_run(afl_state_t *afl) {
" - Least likely, there is a horrible bug in the fuzzer. If "
"other options\n"
- " fail, poke <afl-users@googlegroups.com> for "
+ " fail, poke the Awesome Fuzzing Discord for "
"troubleshooting tips.\n",
stringify_mem_size(val_buf, sizeof(val_buf),
afl->fsrv.mem_limit << 20),
@@ -1018,7 +1041,7 @@ void perform_dry_run(afl_state_t *afl) {
" - Least likely, there is a horrible bug in the fuzzer. If "
"other options\n"
- " fail, poke <afl-users@googlegroups.com> for "
+ " fail, poke the Awesome Fuzzing Discord for "
"troubleshooting tips.\n");
}
@@ -1116,7 +1139,7 @@ void perform_dry_run(afl_state_t *afl) {
}
- if (q->var_behavior) {
+ if (unlikely(q->var_behavior && !afl->afl_env.afl_no_warn_instability)) {
WARNF("Instrumentation output varies across runs.");
@@ -1147,14 +1170,14 @@ void perform_dry_run(afl_state_t *afl) {
u32 duplicates = 0, i;
- for (idx = 0; idx < afl->queued_items; idx++) {
+ for (idx = 0; idx < afl->queued_items - 1; idx++) {
q = afl->queue_buf[idx];
if (!q || q->disabled || q->cal_failed || !q->exec_cksum) { continue; }
-
u32 done = 0;
+
for (i = idx + 1;
- i < afl->queued_items && !done && likely(afl->queue_buf[i]); i++) {
+ 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; }
@@ -1177,6 +1200,13 @@ void perform_dry_run(afl_state_t *afl) {
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) {
@@ -1190,7 +1220,14 @@ void perform_dry_run(afl_state_t *afl) {
q->disabled = 1;
q->perf_score = 0;
- done = 1;
+ 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
}
@@ -1457,7 +1494,7 @@ void find_timeout(afl_state_t *afl) {
static u8 delete_files(u8 *path, u8 *prefix) {
- DIR * d;
+ DIR *d;
struct dirent *d_ent;
d = opendir(path);
@@ -1585,7 +1622,7 @@ dir_cleanup_failed:
static void handle_existing_out_dir(afl_state_t *afl) {
FILE *f;
- u8 * fn = alloc_printf("%s/fuzzer_stats", afl->out_dir);
+ u8 *fn = alloc_printf("%s/fuzzer_stats", afl->out_dir);
/* See if the output directory is locked. If yes, bail out. If not,
create a lock that will persist for the lifetime of the process
@@ -1813,17 +1850,35 @@ static void handle_existing_out_dir(afl_state_t *afl) {
if (afl->file_extension) {
- fn = alloc_printf("%s/.cur_input.%s", afl->tmp_dir, afl->file_extension);
+ fn = alloc_printf("%s/.cur_input.%s", afl->out_dir, afl->file_extension);
} else {
- fn = alloc_printf("%s/.cur_input", afl->tmp_dir);
+ fn = alloc_printf("%s/.cur_input", afl->out_dir);
}
if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
ck_free(fn);
+ if (afl->afl_env.afl_tmpdir) {
+
+ if (afl->file_extension) {
+
+ fn = alloc_printf("%s/.cur_input.%s", afl->afl_env.afl_tmpdir,
+ afl->file_extension);
+
+ } else {
+
+ fn = alloc_printf("%s/.cur_input", afl->afl_env.afl_tmpdir);
+
+ }
+
+ if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
+ }
+
fn = alloc_printf("%s/fuzz_bitmap", afl->out_dir);
if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
ck_free(fn);
@@ -1844,6 +1899,10 @@ static void handle_existing_out_dir(afl_state_t *afl) {
}
+ fn = alloc_printf("%s/queue_data", afl->out_dir);
+ if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
fn = alloc_printf("%s/cmdline", afl->out_dir);
if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
ck_free(fn);
@@ -1878,9 +1937,9 @@ dir_cleanup_failed:
int check_main_node_exists(afl_state_t *afl) {
- DIR * sd;
+ DIR *sd;
struct dirent *sd_ent;
- u8 * fn;
+ u8 *fn;
sd = opendir(afl->sync_dir);
if (!sd) { return 0; }
@@ -2416,7 +2475,9 @@ void get_core_count(afl_state_t *afl) {
} else if ((s64)cur_runnable + 1 <= (s64)afl->cpu_core_count) {
- OKF("Try parallel jobs - see %s/parallel_fuzzing.md.", doc_path);
+ OKF("Try parallel jobs - see "
+ "%s/fuzzing_in_depth.md#c-using-multiple-cores",
+ doc_path);
}
@@ -2581,7 +2642,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
if (unlikely(!fname)) { FATAL("BUG: Binary name is NULL"); }
- u8 * env_path = 0;
+ u8 *env_path = 0;
struct stat st;
s32 fd;
@@ -2758,7 +2819,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
!afl->fsrv.nyx_mode &&
#endif
!afl->fsrv.cs_mode && !afl->non_instrumented_mode &&
- !memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
+ !afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
SAYF("\n" cLRD "[-] " cRST
"Looks like the target binary is not instrumented! The fuzzer depends "
@@ -2789,7 +2850,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
}
if ((afl->fsrv.cs_mode || afl->fsrv.qemu_mode || afl->fsrv.frida_mode) &&
- memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
+ afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
SAYF("\n" cLRD "[-] " cRST
"This program appears to be instrumented with afl-gcc, but is being "
@@ -2802,9 +2863,9 @@ void check_binary(afl_state_t *afl, u8 *fname) {
}
- if (memmem(f_data, f_len, "__asan_init", 11) ||
- memmem(f_data, f_len, "__msan_init", 11) ||
- memmem(f_data, f_len, "__lsan_init", 11)) {
+ if (afl_memmem(f_data, f_len, "__asan_init", 11) ||
+ afl_memmem(f_data, f_len, "__msan_init", 11) ||
+ afl_memmem(f_data, f_len, "__lsan_init", 11)) {
afl->fsrv.uses_asan = 1;
@@ -2812,7 +2873,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
/* Detect persistent & deferred init signatures in the binary. */
- if (memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG) + 1)) {
+ 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);
@@ -2839,7 +2900,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
}
if (afl->fsrv.frida_mode ||
- memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
+ afl_memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
OKF(cPIN "Deferred forkserver binary detected.");
setenv(DEFER_ENV_VAR, "1", 1);
@@ -2895,8 +2956,11 @@ void setup_signal_handlers(void) {
struct sigaction sa;
+ memset((void *)&sa, 0, sizeof(sa));
sa.sa_handler = NULL;
+#ifdef SA_RESTART
sa.sa_flags = SA_RESTART;
+#endif
sa.sa_sigaction = NULL;
sigemptyset(&sa.sa_mask);
diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c
index 9407adfb..64dbe7c6 100644
--- a/src/afl-fuzz-mutators.c
+++ b/src/afl-fuzz-mutators.c
@@ -10,7 +10,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -74,7 +74,7 @@ void setup_custom_mutators(afl_state_t *afl) {
/* Try mutator library first */
struct custom_mutator *mutator;
- u8 * fn = afl->afl_env.afl_custom_mutator_library;
+ u8 *fn = afl->afl_env.afl_custom_mutator_library;
u32 prev_mutator_count = 0;
if (fn) {
@@ -176,14 +176,22 @@ void destroy_custom_mutators(afl_state_t *afl) {
struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
- void * dh;
+ void *dh;
struct custom_mutator *mutator = ck_alloc(sizeof(struct custom_mutator));
- mutator->name = fn;
- if (memchr(fn, '/', strlen(fn)))
- mutator->name_short = strrchr(fn, '/') + 1;
- else
+ if (memchr(fn, '/', strlen(fn))) {
+
+ mutator->name_short = strdup(strrchr(fn, '/') + 1);
+
+ } else {
+
mutator->name_short = strdup(fn);
+
+ }
+
+ if (strlen(mutator->name_short) > 22) { mutator->name_short[21] = 0; }
+
+ mutator->name = fn;
ACTF("Loading custom mutator library from '%s'...", fn);
dh = dlopen(fn, RTLD_NOW);
@@ -211,8 +219,16 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
WARNF("Symbol 'afl_custom_mutator' not found.");
+ } else {
+
+ OKF("Found 'afl_custom_mutator'.");
+
}
+ } else {
+
+ OKF("Found 'afl_custom_mutator'.");
+
}
/* "afl_custom_introspection", optional */
@@ -222,6 +238,10 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
ACTF("optional symbol 'afl_custom_introspection' not found.");
+ } else {
+
+ OKF("Found 'afl_custom_introspection'.");
+
}
#endif
@@ -232,6 +252,10 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
ACTF("optional symbol 'afl_custom_fuzz_count' not found.");
+ } else {
+
+ OKF("Found 'afl_custom_fuzz_count'.");
+
}
/* "afl_custom_deinit", optional for backward compatibility */
@@ -248,6 +272,10 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
ACTF("optional symbol 'afl_custom_post_process' not found.");
+ } else {
+
+ OKF("Found 'afl_custom_post_process'.");
+
}
u8 notrim = 0;
@@ -258,6 +286,10 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
notrim = 1;
ACTF("optional symbol 'afl_custom_init_trim' not found.");
+ } else {
+
+ OKF("Found 'afl_custom_init_trim'.");
+
}
/* "afl_custom_trim", optional */
@@ -267,6 +299,10 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
notrim = 1;
ACTF("optional symbol 'afl_custom_trim' not found.");
+ } else {
+
+ OKF("Found 'afl_custom_trim'.");
+
}
/* "afl_custom_post_trim", optional */
@@ -276,16 +312,26 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
notrim = 1;
ACTF("optional symbol 'afl_custom_post_trim' not found.");
+ } else {
+
+ OKF("Found 'afl_custom_post_trim'.");
+
}
if (notrim) {
+ if (mutator->afl_custom_init_trim || mutator->afl_custom_trim ||
+ mutator->afl_custom_post_trim) {
+
+ WARNF(
+ "Custom mutator does not implement all three trim APIs, standard "
+ "trimming will be used.");
+
+ }
+
mutator->afl_custom_init_trim = NULL;
mutator->afl_custom_trim = NULL;
mutator->afl_custom_post_trim = NULL;
- ACTF(
- "Custom mutator does not implement all three trim APIs, standard "
- "trimming will be used.");
}
@@ -295,6 +341,10 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
ACTF("optional symbol 'afl_custom_havoc_mutation' not found.");
+ } else {
+
+ OKF("Found 'afl_custom_havoc_mutation'.");
+
}
/* "afl_custom_havoc_mutation", optional */
@@ -304,6 +354,10 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
ACTF("optional symbol 'afl_custom_havoc_mutation_probability' not found.");
+ } else {
+
+ OKF("Found 'afl_custom_havoc_mutation_probability'.");
+
}
/* "afl_custom_queue_get", optional */
@@ -312,6 +366,35 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
ACTF("optional symbol 'afl_custom_queue_get' not found.");
+ } else {
+
+ OKF("Found 'afl_custom_queue_get'.");
+
+ }
+
+ /* "afl_custom_splice_optout", optional, never called */
+ mutator->afl_custom_splice_optout = dlsym(dh, "afl_custom_splice_optout");
+ if (!mutator->afl_custom_splice_optout) {
+
+ ACTF("optional symbol 'afl_custom_splice_optout' not found.");
+
+ } else {
+
+ OKF("Found 'afl_custom_splice_optout'.");
+ afl->custom_splice_optout = 1;
+
+ }
+
+ /* "afl_custom_fuzz_send", optional */
+ mutator->afl_custom_fuzz_send = dlsym(dh, "afl_custom_fuzz_send");
+ if (!mutator->afl_custom_fuzz_send) {
+
+ ACTF("optional symbol 'afl_custom_fuzz_send' not found.");
+
+ } else {
+
+ OKF("Found 'afl_custom_fuzz_send'.");
+
}
/* "afl_custom_queue_new_entry", optional */
@@ -320,13 +403,21 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
ACTF("optional symbol 'afl_custom_queue_new_entry' not found");
+ } else {
+
+ OKF("Found 'afl_custom_queue_new_entry'.");
+
}
/* "afl_custom_describe", optional */
mutator->afl_custom_describe = dlsym(dh, "afl_custom_describe");
if (!mutator->afl_custom_describe) {
- ACTF("Symbol 'afl_custom_describe' not found.");
+ ACTF("optional symbol 'afl_custom_describe' not found.");
+
+ } else {
+
+ OKF("Found 'afl_custom_describe'.");
}
@@ -430,13 +521,21 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
retlen = write_to_testcase(afl, (void **)&retbuf, retlen, 0);
- fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
- ++afl->trim_execs;
+ if (unlikely(!retlen)) {
- if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; }
+ ++afl->trim_execs;
+
+ } else {
- classify_counts(&afl->fsrv);
- cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+ fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
+ ++afl->trim_execs;
+
+ if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; }
+
+ classify_counts(&afl->fsrv);
+ cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+
+ }
}
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
index 19f41ebe..5c71fc59 100644
--- a/src/afl-fuzz-one.c
+++ b/src/afl-fuzz-one.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -446,9 +446,12 @@ u8 fuzz_one_original(afl_state_t *afl) {
ACTF(
"Fuzzing test case #%u (%u total, %llu crashes saved, "
- "perf_score=%0.0f, exec_us=%llu, hits=%u, map=%u, ascii=%u)...",
+ "perf_score=%0.0f, weight=%0.0f, favorite=%u, was_fuzzed=%u, "
+ "exec_us=%llu, hits=%u, map=%u, ascii=%u)...",
afl->current_entry, afl->queued_items, afl->saved_crashes,
- afl->queue_cur->perf_score, afl->queue_cur->exec_us,
+ afl->queue_cur->perf_score, afl->queue_cur->weight,
+ afl->queue_cur->favored, afl->queue_cur->was_fuzzed,
+ afl->queue_cur->exec_us,
likely(afl->n_fuzz) ? afl->n_fuzz[afl->queue_cur->n_fuzz_entry] : 0,
afl->queue_cur->bitmap_size, afl->queue_cur->is_ascii);
fflush(stdout);
@@ -561,11 +564,11 @@ u8 fuzz_one_original(afl_state_t *afl) {
} else {
- if (afl->cmplog_lvl == 3 ||
- (afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) ||
- afl->queue_cur->favored ||
- !(afl->fsrv.total_execs % afl->queued_items) ||
- get_cur_time() - afl->last_find_time > 300000) { // 300 seconds
+ if (afl->queue_cur->favored || afl->cmplog_lvl == 3 ||
+ (afl->cmplog_lvl == 2 &&
+ (afl->queue_cur->tc_ref ||
+ afl->fsrv.total_execs % afl->queued_items <= 10)) ||
+ get_cur_time() - afl->last_find_time > 250000) { // 250 seconds
if (input_to_state_stage(afl, in_buf, out_buf, len)) {
@@ -584,7 +587,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
if it has gone through deterministic testing in earlier, resumed runs
(passed_det). */
- if (likely(afl->queue_cur->passed_det) || likely(afl->skip_deterministic) ||
+ if (likely(afl->skip_deterministic) || likely(afl->queue_cur->passed_det) ||
likely(perf_score <
(afl->queue_cur->depth * 30 <= afl->havoc_max_mult * 100
? afl->queue_cur->depth * 30
@@ -743,6 +746,9 @@ u8 fuzz_one_original(afl_state_t *afl) {
afl->stage_finds[STAGE_FLIP1] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP1] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Two walking bits. */
@@ -775,6 +781,9 @@ u8 fuzz_one_original(afl_state_t *afl) {
afl->stage_finds[STAGE_FLIP2] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP2] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Four walking bits. */
@@ -811,6 +820,9 @@ u8 fuzz_one_original(afl_state_t *afl) {
afl->stage_finds[STAGE_FLIP4] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP4] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Effector map setup. These macros calculate:
@@ -830,6 +842,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
eff_map = afl_realloc(AFL_BUF_PARAM(eff), EFF_ALEN(len));
if (unlikely(!eff_map)) { PFATAL("alloc"); }
+ memset(eff_map, 0, EFF_ALEN(len));
eff_map[0] = 1;
if (EFF_APOS(len - 1) != 0) {
@@ -919,6 +932,9 @@ u8 fuzz_one_original(afl_state_t *afl) {
afl->stage_finds[STAGE_FLIP8] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP8] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Two walking bytes. */
@@ -962,6 +978,9 @@ u8 fuzz_one_original(afl_state_t *afl) {
afl->stage_finds[STAGE_FLIP16] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP16] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
if (len < 4) { goto skip_bitflip; }
@@ -1005,6 +1024,9 @@ u8 fuzz_one_original(afl_state_t *afl) {
afl->stage_finds[STAGE_FLIP32] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP32] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
skip_bitflip:
@@ -1097,6 +1119,9 @@ skip_bitflip:
afl->stage_finds[STAGE_ARITH8] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_ARITH8] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* 16-bit arithmetics, both endians. */
@@ -1227,6 +1252,9 @@ skip_bitflip:
afl->stage_finds[STAGE_ARITH16] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_ARITH16] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* 32-bit arithmetics, both endians. */
@@ -1356,6 +1384,9 @@ skip_bitflip:
afl->stage_finds[STAGE_ARITH32] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_ARITH32] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
skip_arith:
@@ -1422,6 +1453,9 @@ skip_arith:
afl->stage_finds[STAGE_INTEREST8] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_INTEREST8] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Setting 16-bit integers, both endians. */
@@ -1510,6 +1544,9 @@ skip_arith:
afl->stage_finds[STAGE_INTEREST16] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_INTEREST16] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
if (len < 4) { goto skip_interest; }
@@ -1599,6 +1636,9 @@ skip_arith:
afl->stage_finds[STAGE_INTEREST32] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_INTEREST32] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
skip_interest:
@@ -1672,6 +1712,9 @@ skip_interest:
afl->stage_finds[STAGE_EXTRAS_UO] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_EXTRAS_UO] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Insertion of user-supplied extras. */
@@ -1728,6 +1771,9 @@ skip_interest:
afl->stage_finds[STAGE_EXTRAS_UI] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_EXTRAS_UI] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
skip_user_extras:
@@ -1786,6 +1832,9 @@ skip_user_extras:
afl->stage_finds[STAGE_EXTRAS_AO] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_EXTRAS_AO] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Insertion of auto extras. */
@@ -1842,6 +1891,9 @@ skip_user_extras:
afl->stage_finds[STAGE_EXTRAS_AI] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_EXTRAS_AI] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
skip_extras:
@@ -1860,9 +1912,11 @@ custom_mutator_stage:
afl->stage_name = "custom mutator";
afl->stage_short = "custom";
- afl->stage_max = HAVOC_CYCLES * perf_score / afl->havoc_div / 100;
+ afl->stage_cur = 0;
afl->stage_val_type = STAGE_VAL_NONE;
bool has_custom_fuzz = false;
+ u32 shift = unlikely(afl->custom_only) ? 7 : 8;
+ afl->stage_max = (HAVOC_CYCLES * perf_score / afl->havoc_div) >> shift;
if (afl->stage_max < HAVOC_MIN) { afl->stage_max = HAVOC_MIN; }
@@ -1879,6 +1933,7 @@ custom_mutator_stage:
if (el->afl_custom_fuzz) {
afl->current_custom_fuzz = el;
+ afl->stage_name = el->name_short;
if (el->afl_custom_fuzz_count) {
@@ -1901,11 +1956,12 @@ custom_mutator_stage:
struct queue_entry *target = NULL;
u32 tid;
- u8 * new_buf = NULL;
+ u8 *new_buf = NULL;
u32 target_len = 0;
/* check if splicing makes sense yet (enough entries) */
- if (likely(afl->ready_for_splicing_count > 1)) {
+ if (likely(!afl->custom_splice_optout &&
+ afl->ready_for_splicing_count > 1)) {
/* Pick a random other queue entry for passing to external API
that has the necessary length */
@@ -1935,7 +1991,8 @@ custom_mutator_stage:
if (unlikely(!mutated_buf)) {
- FATAL("Error in custom_fuzz. Size returned: %zu", mutated_size);
+ // FATAL("Error in custom_fuzz. Size returned: %zu", mutated_size);
+ break;
}
@@ -1987,22 +2044,27 @@ custom_mutator_stage:
new_hit_cnt = afl->queued_items + afl->saved_crashes;
afl->stage_finds[STAGE_CUSTOM_MUTATOR] += new_hit_cnt - orig_hit_cnt;
- afl->stage_cycles[STAGE_CUSTOM_MUTATOR] += afl->stage_max;
+ afl->stage_cycles[STAGE_CUSTOM_MUTATOR] += afl->stage_cur;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
+
+ /****************
+ * RANDOM HAVOC *
+ ****************/
+
+havoc_stage:
- if (likely(afl->custom_only)) {
+ if (unlikely(afl->custom_only)) {
+ /* Force UI update */
+ show_stats(afl);
/* Skip other stages */
ret_val = 0;
goto abandon_entry;
}
- /****************
- * RANDOM HAVOC *
- ****************/
-
-havoc_stage:
-
afl->stage_cur_byte = -1;
/* The havoc stage mutation code is also invoked when splicing files; if the
@@ -2012,8 +2074,9 @@ havoc_stage:
afl->stage_name = "havoc";
afl->stage_short = "havoc";
- afl->stage_max = (doing_det ? HAVOC_CYCLES_INIT : HAVOC_CYCLES) *
- perf_score / afl->havoc_div / 100;
+ afl->stage_max = ((doing_det ? HAVOC_CYCLES_INIT : HAVOC_CYCLES) *
+ perf_score / afl->havoc_div) >>
+ 8;
} else {
@@ -2022,11 +2085,11 @@ havoc_stage:
snprintf(afl->stage_name_buf, STAGE_BUF_SIZE, "splice %u", splice_cycle);
afl->stage_name = afl->stage_name_buf;
afl->stage_short = "splice";
- afl->stage_max = SPLICE_HAVOC * perf_score / afl->havoc_div / 100;
+ afl->stage_max = (SPLICE_HAVOC * perf_score / afl->havoc_div) >> 8;
}
- if (afl->stage_max < HAVOC_MIN) { afl->stage_max = HAVOC_MIN; }
+ if (unlikely(afl->stage_max < HAVOC_MIN)) { afl->stage_max = HAVOC_MIN; }
temp_len = len;
@@ -2110,7 +2173,7 @@ havoc_stage:
if (el->stacked_custom &&
rand_below(afl, 100) < el->stacked_custom_prob) {
- u8 * custom_havoc_buf = NULL;
+ u8 *custom_havoc_buf = NULL;
size_t new_len = el->afl_custom_havoc_mutation(
el->data, out_buf, temp_len, &custom_havoc_buf, MAX_FILE);
if (unlikely(!custom_havoc_buf)) {
@@ -2585,7 +2648,7 @@ havoc_stage:
snprintf(afl->m_tmp, sizeof(afl->m_tmp), " SUBBYTE_");
strcat(afl->mutation, afl->m_tmp);
#endif
- out_buf[rand_below(afl, temp_len)]++;
+ out_buf[rand_below(afl, temp_len)]--;
break;
}
@@ -2823,7 +2886,7 @@ havoc_stage:
/* Get the testcase for splicing. */
struct queue_entry *target = afl->queue_buf[tid];
u32 new_len = target->len;
- u8 * new_buf = queue_testcase_get(afl, target);
+ u8 *new_buf = queue_testcase_get(afl, target);
if ((temp_len >= 2 && r % 2) || temp_len + HAVOC_BLK_XL >= MAX_FILE) {
@@ -2925,11 +2988,17 @@ havoc_stage:
afl->stage_finds[STAGE_HAVOC] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_HAVOC] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
} else {
afl->stage_finds[STAGE_SPLICE] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_SPLICE] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
}
@@ -2951,7 +3020,7 @@ retry_splicing:
struct queue_entry *target;
u32 tid, split_at;
- u8 * new_buf;
+ u8 *new_buf;
s32 f_diff, l_diff;
/* First of all, if we've modified in_buf for havoc, let's clean that
@@ -3411,6 +3480,9 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
afl->stage_finds[STAGE_FLIP1] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP1] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Two walking bits. */
@@ -3442,6 +3514,9 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
afl->stage_finds[STAGE_FLIP2] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP2] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Four walking bits. */
@@ -3477,6 +3552,9 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
afl->stage_finds[STAGE_FLIP4] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP4] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Effector map setup. These macros calculate:
@@ -3496,6 +3574,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
eff_map = afl_realloc(AFL_BUF_PARAM(eff), EFF_ALEN(len));
if (unlikely(!eff_map)) { PFATAL("alloc"); }
+ memset(eff_map, 0, EFF_ALEN(len));
eff_map[0] = 1;
if (EFF_APOS(len - 1) != 0) {
@@ -3584,6 +3663,9 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
afl->stage_finds[STAGE_FLIP8] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP8] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Two walking bytes. */
@@ -3626,6 +3708,9 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
afl->stage_finds[STAGE_FLIP16] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP16] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
if (len < 4) { goto skip_bitflip; }
@@ -3668,6 +3753,9 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
afl->stage_finds[STAGE_FLIP32] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP32] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
skip_bitflip:
@@ -3758,6 +3846,9 @@ skip_bitflip:
afl->stage_finds[STAGE_ARITH8] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_ARITH8] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* 16-bit arithmetics, both endians. */
@@ -3884,6 +3975,9 @@ skip_bitflip:
afl->stage_finds[STAGE_ARITH16] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_ARITH16] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* 32-bit arithmetics, both endians. */
@@ -4009,6 +4103,9 @@ skip_bitflip:
afl->stage_finds[STAGE_ARITH32] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_ARITH32] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
skip_arith:
@@ -4074,6 +4171,9 @@ skip_arith:
afl->stage_finds[STAGE_INTEREST8] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_INTEREST8] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Setting 16-bit integers, both endians. */
@@ -4160,6 +4260,9 @@ skip_arith:
afl->stage_finds[STAGE_INTEREST16] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_INTEREST16] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
if (len < 4) { goto skip_interest; }
@@ -4247,6 +4350,9 @@ skip_arith:
afl->stage_finds[STAGE_INTEREST32] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_INTEREST32] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
skip_interest:
@@ -4320,6 +4426,9 @@ skip_interest:
afl->stage_finds[STAGE_EXTRAS_UO] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_EXTRAS_UO] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Insertion of user-supplied extras. */
@@ -4376,6 +4485,9 @@ skip_interest:
afl->stage_finds[STAGE_EXTRAS_UI] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_EXTRAS_UI] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
skip_user_extras:
@@ -4435,6 +4547,9 @@ skip_user_extras:
afl->stage_finds[STAGE_EXTRAS_AO] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_EXTRAS_AO] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Insertion of auto extras. */
@@ -4491,6 +4606,9 @@ skip_user_extras:
afl->stage_finds[STAGE_EXTRAS_AI] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_EXTRAS_AI] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
skip_extras:
@@ -4516,8 +4634,9 @@ pacemaker_fuzzing:
afl->stage_name = MOpt_globals.havoc_stagename;
afl->stage_short = MOpt_globals.havoc_stagenameshort;
- afl->stage_max = (doing_det ? HAVOC_CYCLES_INIT : HAVOC_CYCLES) *
- perf_score / afl->havoc_div / 100;
+ afl->stage_max = ((doing_det ? HAVOC_CYCLES_INIT : HAVOC_CYCLES) *
+ perf_score / afl->havoc_div) >>
+ 7;
} else {
@@ -4527,7 +4646,7 @@ pacemaker_fuzzing:
MOpt_globals.splice_stageformat, splice_cycle);
afl->stage_name = afl->stage_name_buf;
afl->stage_short = MOpt_globals.splice_stagenameshort;
- afl->stage_max = SPLICE_HAVOC * perf_score / afl->havoc_div / 100;
+ afl->stage_max = (SPLICE_HAVOC * perf_score / afl->havoc_div) >> 8;
}
@@ -5164,7 +5283,7 @@ pacemaker_fuzzing:
/* Get the testcase for splicing. */
struct queue_entry *target = afl->queue_buf[tid];
u32 new_len = target->len;
- u8 * new_buf = queue_testcase_get(afl, target);
+ u8 *new_buf = queue_testcase_get(afl, target);
if ((temp_len >= 2 && rand_below(afl, 2)) ||
temp_len + HAVOC_BLK_XL >= MAX_FILE) {
@@ -5316,11 +5435,17 @@ pacemaker_fuzzing:
afl->stage_finds[STAGE_HAVOC] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_HAVOC] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
} else {
afl->stage_finds[STAGE_SPLICE] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_SPLICE] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
}
@@ -5340,7 +5465,7 @@ pacemaker_fuzzing:
struct queue_entry *target;
u32 tid, split_at;
- u8 * new_buf;
+ u8 *new_buf;
s32 f_diff, l_diff;
/* First of all, if we've modified in_buf for havoc, let's clean that
@@ -5572,6 +5697,7 @@ pacemaker_fuzzing:
} /* block */
+ ++afl->queue_cur->fuzz_level;
return ret_val;
}
@@ -5681,13 +5807,11 @@ void pso_updating(afl_state_t *afl) {
}
-/* larger change for MOpt implementation: the original fuzz_one was renamed
- to fuzz_one_original. All documentation references to fuzz_one therefore
- mean fuzz_one_original */
-
+/* The entry point for the mutator, choosing the default mutator, and/or MOpt
+ depending on the configuration. */
u8 fuzz_one(afl_state_t *afl) {
- int key_val_lv_1 = 0, key_val_lv_2 = 0;
+ int key_val_lv_1 = -1, key_val_lv_2 = -1;
#ifdef _AFL_DOCUMENT_MUTATIONS
@@ -5707,7 +5831,12 @@ u8 fuzz_one(afl_state_t *afl) {
#endif
- // if limit_time_sig == -1 then both are run after each other
+ /*
+ -L command line paramter => limit_time_sig value
+ limit_time_sig == 0 then run the default mutator
+ limit_time_sig > 0 then run MOpt
+ limit_time_sig < 0 both are run
+ */
if (afl->limit_time_sig <= 0) { key_val_lv_1 = fuzz_one_original(afl); }
@@ -5729,6 +5858,9 @@ u8 fuzz_one(afl_state_t *afl) {
}
+ if (unlikely(key_val_lv_1 == -1)) { key_val_lv_1 = 0; }
+ if (likely(key_val_lv_2 == -1)) { key_val_lv_2 = 0; }
+
return (key_val_lv_1 | key_val_lv_2);
}
diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c
index 65501c8c..7dad0770 100644
--- a/src/afl-fuzz-python.c
+++ b/src/afl-fuzz-python.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -28,6 +28,36 @@
/* Python stuff */
#ifdef USE_PYTHON
+// Tries to cast a python bytearray or bytes to a char ptr
+static inline bool py_bytes(PyObject *py_value, /* out */ char **bytes,
+ /* out */ size_t *size) {
+
+ if (!py_value) { return false; }
+
+ *bytes = PyByteArray_AsString(py_value);
+ if (*bytes) {
+
+ // we got a bytearray
+ *size = PyByteArray_Size(py_value);
+
+ } else {
+
+ *bytes = PyBytes_AsString(py_value);
+ if (!*bytes) {
+
+ // No valid type returned.
+ return false;
+
+ }
+
+ *size = PyBytes_Size(py_value);
+
+ }
+
+ return true;
+
+}
+
static void *unsupported(afl_state_t *afl, unsigned int seed) {
(void)afl;
@@ -93,12 +123,22 @@ static size_t fuzz_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf,
if (py_value != NULL) {
- mutated_size = PyByteArray_Size(py_value);
+ char *bytes;
+ if (!py_bytes(py_value, &bytes, &mutated_size)) {
+
+ FATAL("Python mutator fuzz() should return a bytearray or bytes");
+
+ }
+
+ if (mutated_size) {
+
+ *out_buf = afl_realloc(BUF_PARAMS(fuzz), mutated_size);
+ if (unlikely(!*out_buf)) { PFATAL("alloc"); }
+
+ memcpy(*out_buf, bytes, mutated_size);
- *out_buf = afl_realloc(BUF_PARAMS(fuzz), mutated_size);
- if (unlikely(!*out_buf)) { PFATAL("alloc"); }
+ }
- memcpy(*out_buf, PyByteArray_AsString(py_value), mutated_size);
Py_DECREF(py_value);
return mutated_size;
@@ -111,7 +151,7 @@ static size_t fuzz_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf,
}
-static const char *custom_describe_py(void * py_mutator,
+static const char *custom_describe_py(void *py_mutator,
size_t max_description_len) {
PyObject *py_args, *py_value;
@@ -162,7 +202,7 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
py->py_module = PyImport_Import(py_name);
Py_DECREF(py_name);
- PyObject * py_module = py->py_module;
+ PyObject *py_module = py->py_module;
PyObject **py_functions = py->py_functions;
// initialize the post process buffer; ensures it's always valid
@@ -179,11 +219,14 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
if (py_module != NULL) {
- u8 py_notrim = 0, py_idx;
- /* init, required */
+ u8 py_notrim = 0;
py_functions[PY_FUNC_INIT] = PyObject_GetAttrString(py_module, "init");
- if (!py_functions[PY_FUNC_INIT])
- FATAL("init function not found in python module");
+ if (!py_functions[PY_FUNC_INIT]) {
+
+ WARNF("init function not found in python module");
+
+ }
+
py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "fuzz");
if (!py_functions[PY_FUNC_FUZZ])
py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "mutate");
@@ -191,8 +234,6 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
PyObject_GetAttrString(py_module, "describe");
py_functions[PY_FUNC_FUZZ_COUNT] =
PyObject_GetAttrString(py_module, "fuzz_count");
- if (!py_functions[PY_FUNC_FUZZ])
- WARNF("fuzz function not found in python module");
py_functions[PY_FUNC_POST_PROCESS] =
PyObject_GetAttrString(py_module, "post_process");
py_functions[PY_FUNC_INIT_TRIM] =
@@ -206,6 +247,11 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
PyObject_GetAttrString(py_module, "havoc_mutation_probability");
py_functions[PY_FUNC_QUEUE_GET] =
PyObject_GetAttrString(py_module, "queue_get");
+ py_functions[PY_FUNC_FUZZ_SEND] =
+ PyObject_GetAttrString(py_module, "fuzz_send");
+ py_functions[PY_FUNC_SPLICE_OPTOUT] =
+ PyObject_GetAttrString(py_module, "splice_optout");
+ if (py_functions[PY_FUNC_SPLICE_OPTOUT]) { afl->custom_splice_optout = 1; }
py_functions[PY_FUNC_QUEUE_NEW_ENTRY] =
PyObject_GetAttrString(py_module, "queue_new_entry");
py_functions[PY_FUNC_INTROSPECTION] =
@@ -214,36 +260,6 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
if (!py_functions[PY_FUNC_DEINIT])
WARNF("deinit function not found in python module");
- for (py_idx = 0; py_idx < PY_FUNC_COUNT; ++py_idx) {
-
- if (!py_functions[py_idx] || !PyCallable_Check(py_functions[py_idx])) {
-
- if (py_idx >= PY_FUNC_INIT_TRIM && py_idx <= PY_FUNC_TRIM) {
-
- // Implementing the trim API is optional for now
- if (PyErr_Occurred()) { PyErr_Print(); }
- py_notrim = 1;
-
- } else if (py_idx >= PY_OPTIONAL) {
-
- // Only _init and _deinit are not optional currently
-
- if (PyErr_Occurred()) { PyErr_Print(); }
-
- } else {
-
- fprintf(stderr,
- "Cannot find/call function with index %d in external "
- "Python module.\n",
- py_idx);
- return NULL;
-
- }
-
- }
-
- }
-
if (py_notrim) {
py_functions[PY_FUNC_INIT_TRIM] = NULL;
@@ -296,6 +312,8 @@ static void init_py(afl_state_t *afl, py_mutator_t *py_mutator,
(void)afl;
+ if (py_mutator->py_functions[PY_FUNC_INIT] == NULL) { return; }
+
PyObject *py_args, *py_value;
/* Provide the init function a seed for the Python RNG */
@@ -352,16 +370,34 @@ void deinit_py(void *py_mutator) {
}
+void splice_optout_py(void *py_mutator) {
+
+ // this is never called
+ (void)(py_mutator);
+
+}
+
struct custom_mutator *load_custom_mutator_py(afl_state_t *afl,
- char * module_name) {
+ char *module_name) {
struct custom_mutator *mutator;
mutator = ck_alloc(sizeof(struct custom_mutator));
-
mutator->name = module_name;
ACTF("Loading Python mutator library from '%s'...", module_name);
+ if (memchr(module_name, '/', strlen(module_name))) {
+
+ mutator->name_short = strdup(strrchr(module_name, '/') + 1);
+
+ } else {
+
+ mutator->name_short = strdup(module_name);
+
+ }
+
+ if (strlen(mutator->name_short) > 22) { mutator->name_short[21] = 0; }
+
py_mutator_t *py_mutator;
py_mutator = init_py_module(afl, module_name);
mutator->data = py_mutator;
@@ -426,6 +462,19 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl,
}
+ if (py_functions[PY_FUNC_FUZZ_SEND]) {
+
+ mutator->afl_custom_fuzz_send = fuzz_send_py;
+
+ }
+
+ if (py_functions[PY_FUNC_SPLICE_OPTOUT]) {
+
+ mutator->afl_custom_splice_optout = splice_optout_py;
+ afl->custom_splice_optout = 1;
+
+ }
+
if (py_functions[PY_FUNC_QUEUE_NEW_ENTRY]) {
mutator->afl_custom_queue_new_entry = queue_new_entry_py;
@@ -457,7 +506,7 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl,
size_t post_process_py(void *py_mutator, u8 *buf, size_t buf_size,
u8 **out_buf) {
- PyObject * py_args, *py_value;
+ PyObject *py_args, *py_value;
py_mutator_t *py = (py_mutator_t *)py_mutator;
// buffer returned previously must be released; initialized during init
@@ -495,7 +544,16 @@ size_t post_process_py(void *py_mutator, u8 *buf, size_t buf_size,
Py_DECREF(py_value);
- *out_buf = (u8 *)py->post_process_buf.buf;
+ if (unlikely(py->post_process_buf.len == 0)) {
+
+ *out_buf = NULL;
+
+ } else {
+
+ *out_buf = (u8 *)py->post_process_buf.buf;
+
+ }
+
return py->post_process_buf.len;
} else {
@@ -625,7 +683,7 @@ s32 post_trim_py(void *py_mutator, u8 success) {
size_t trim_py(void *py_mutator, u8 **out_buf) {
PyObject *py_args, *py_value;
- size_t ret;
+ size_t trimmed_size;
py_args = PyTuple_New(0);
py_value = PyObject_CallObject(
@@ -634,10 +692,21 @@ size_t trim_py(void *py_mutator, u8 **out_buf) {
if (py_value != NULL) {
- ret = PyByteArray_Size(py_value);
- *out_buf = afl_realloc(BUF_PARAMS(trim), ret);
- if (unlikely(!*out_buf)) { PFATAL("alloc"); }
- memcpy(*out_buf, PyByteArray_AsString(py_value), ret);
+ char *bytes;
+ if (!py_bytes(py_value, &bytes, &trimmed_size)) {
+
+ FATAL("Python mutator fuzz() should return a bytearray");
+
+ }
+
+ if (trimmed_size) {
+
+ *out_buf = afl_realloc(BUF_PARAMS(trim), trimmed_size);
+ if (unlikely(!*out_buf)) { PFATAL("alloc"); }
+ memcpy(*out_buf, bytes, trimmed_size);
+
+ }
+
Py_DECREF(py_value);
} else {
@@ -647,7 +716,7 @@ size_t trim_py(void *py_mutator, u8 **out_buf) {
}
- return ret;
+ return trimmed_size;
}
@@ -692,7 +761,13 @@ size_t havoc_mutation_py(void *py_mutator, u8 *buf, size_t buf_size,
if (py_value != NULL) {
- mutated_size = PyByteArray_Size(py_value);
+ char *bytes;
+ if (!py_bytes(py_value, &bytes, &mutated_size)) {
+
+ FATAL("Python mutator fuzz() should return a bytearray");
+
+ }
+
if (mutated_size <= buf_size) {
/* We reuse the input buf here. */
@@ -706,7 +781,7 @@ size_t havoc_mutation_py(void *py_mutator, u8 *buf, size_t buf_size,
}
- memcpy(*out_buf, PyByteArray_AsString(py_value), mutated_size);
+ if (mutated_size) { memcpy(*out_buf, bytes, mutated_size); }
Py_DECREF(py_value);
return mutated_size;
@@ -762,7 +837,17 @@ const char *introspection_py(void *py_mutator) {
} else {
- return PyByteArray_AsString(py_value);
+ char *ret;
+ size_t len;
+ if (!py_bytes(py_value, &ret, &len)) {
+
+ FATAL(
+ "Python mutator introspection call returned illegal type (expected "
+ "bytes or bytearray)");
+
+ }
+
+ return ret;
}
@@ -817,6 +902,29 @@ u8 queue_get_py(void *py_mutator, const u8 *filename) {
}
+void fuzz_send_py(void *py_mutator, const u8 *buf, size_t buf_size) {
+
+ PyObject *py_args, *py_value;
+
+ py_args = PyTuple_New(1);
+ py_value = PyByteArray_FromStringAndSize(buf, buf_size);
+ if (!py_value) {
+
+ Py_DECREF(py_args);
+ FATAL("Failed to convert arguments");
+
+ }
+
+ PyTuple_SetItem(py_args, 0, py_value);
+
+ py_value = PyObject_CallObject(
+ ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_FUZZ_SEND], py_args);
+ Py_DECREF(py_args);
+
+ if (py_value != NULL) { Py_DECREF(py_value); }
+
+}
+
u8 queue_new_entry_py(void *py_mutator, const u8 *filename_new_queue,
const u8 *filename_orig_queue) {
diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c
index 713c7447..b10bf749 100644
--- a/src/afl-fuzz-queue.c
+++ b/src/afl-fuzz-queue.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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:
@@ -27,17 +27,35 @@
#include <ctype.h>
#include <math.h>
+#ifdef _STANDALONE_MODULE
+void minimize_bits(afl_state_t *afl, u8 *dst, u8 *src) {
+
+ return;
+
+}
+
+void run_afl_custom_queue_new_entry(afl_state_t *afl, struct queue_entry *q,
+ u8 *a, u8 *b) {
+
+ return;
+
+}
+
+#endif
+
/* select next queue entry based on alias algo - fast! */
inline u32 select_next_queue_entry(afl_state_t *afl) {
u32 s = rand_below(afl, afl->queued_items);
double p = rand_next_percent(afl);
+
/*
fprintf(stderr, "select: p=%f s=%u ... p < prob[s]=%f ? s=%u : alias[%u]=%u"
" ==> %u\n", p, s, afl->alias_probability[s], s, s, afl->alias_table[s], p <
afl->alias_probability[s] ? s : afl->alias_table[s]);
*/
+
return (p < afl->alias_probability[s] ? s : afl->alias_table[s]);
}
@@ -51,13 +69,15 @@ double compute_weight(afl_state_t *afl, struct queue_entry *q,
if (likely(afl->schedule >= FAST && afl->schedule <= RARE)) {
u32 hits = afl->n_fuzz[q->n_fuzz_entry];
- if (likely(hits)) { weight *= log10(hits) + 1; }
+ if (likely(hits)) { weight /= (log10(hits) + 1); }
}
if (likely(afl->schedule < RARE)) { weight *= (avg_exec_us / q->exec_us); }
weight *= (log(q->bitmap_size) / avg_bitmap_size);
weight *= (1 + (q->tc_ref / avg_top_size));
+
+ if (unlikely(weight < 0.1)) { weight = 0.1; }
if (unlikely(q->favored)) { weight *= 5; }
if (unlikely(!q->was_fuzzed)) { weight *= 2; }
@@ -69,25 +89,28 @@ double compute_weight(afl_state_t *afl, struct queue_entry *q,
void create_alias_table(afl_state_t *afl) {
- u32 n = afl->queued_items, i = 0, a, g;
+ u32 n = afl->queued_items, i = 0, nSmall = 0, nLarge = n - 1;
double sum = 0;
+ double *P = (double *)afl_realloc(AFL_BUF_PARAM(out), n * sizeof(double));
+ u32 *Small = (int *)afl_realloc(AFL_BUF_PARAM(out_scratch), n * sizeof(u32));
+ u32 *Large = (int *)afl_realloc(AFL_BUF_PARAM(in_scratch), n * sizeof(u32));
+
afl->alias_table =
(u32 *)afl_realloc((void **)&afl->alias_table, n * sizeof(u32));
afl->alias_probability = (double *)afl_realloc(
(void **)&afl->alias_probability, n * sizeof(double));
- double *P = (double *)afl_realloc(AFL_BUF_PARAM(out), n * sizeof(double));
- int * S = (u32 *)afl_realloc(AFL_BUF_PARAM(out_scratch), n * sizeof(u32));
- int * L = (u32 *)afl_realloc(AFL_BUF_PARAM(in_scratch), n * sizeof(u32));
- if (!P || !S || !L || !afl->alias_table || !afl->alias_probability) {
+ if (!P || !Small || !Large || !afl->alias_table || !afl->alias_probability) {
FATAL("could not acquire memory for alias table");
}
- memset((void *)afl->alias_table, 0, n * sizeof(u32));
memset((void *)afl->alias_probability, 0, n * sizeof(double));
+ memset((void *)afl->alias_table, 0, n * sizeof(u32));
+ memset((void *)Small, 0, n * sizeof(u32));
+ memset((void *)Large, 0, n * sizeof(u32));
if (likely(afl->schedule < RARE)) {
@@ -131,10 +154,32 @@ void create_alias_table(afl_state_t *afl) {
}
+ if (unlikely(afl->schedule == MMOPT) && afl->queued_discovered) {
+
+ u32 cnt = afl->queued_discovered >= 5 ? 5 : afl->queued_discovered;
+
+ for (i = n - cnt; i < n; i++) {
+
+ struct queue_entry *q = afl->queue_buf[i];
+
+ if (likely(!q->disabled)) { q->weight *= 2.0; }
+
+ }
+
+ }
+
for (i = 0; i < n; i++) {
// weight is always 0 for disabled entries
- P[i] = (afl->queue_buf[i]->weight * n) / sum;
+ if (unlikely(afl->queue_buf[i]->disabled)) {
+
+ P[i] = 0;
+
+ } else {
+
+ P[i] = (afl->queue_buf[i]->weight * n) / sum;
+
+ }
}
@@ -144,60 +189,81 @@ void create_alias_table(afl_state_t *afl) {
struct queue_entry *q = afl->queue_buf[i];
- if (likely(!q->disabled)) { q->perf_score = calculate_score(afl, q); }
+ if (likely(!q->disabled)) {
+
+ q->perf_score = calculate_score(afl, q);
+ sum += q->perf_score;
- sum += q->perf_score;
+ }
}
for (i = 0; i < n; i++) {
// perf_score is always 0 for disabled entries
- P[i] = (afl->queue_buf[i]->perf_score * n) / sum;
+ if (unlikely(afl->queue_buf[i]->disabled)) {
+
+ P[i] = 0;
+
+ } else {
+
+ P[i] = (afl->queue_buf[i]->perf_score * n) / sum;
+
+ }
}
}
- int nS = 0, nL = 0, s;
- for (s = (s32)n - 1; s >= 0; --s) {
+ // Done collecting weightings in P, now create the arrays.
- if (P[s] < 1) {
+ for (s32 j = (s32)(n - 1); j >= 0; j--) {
- S[nS++] = s;
+ if (P[j] < 1) {
+
+ Small[nSmall++] = (u32)j;
} else {
- L[nL++] = s;
+ Large[nLarge--] = (u32)j;
}
}
- while (nS && nL) {
+ while (nSmall && nLarge != n - 1) {
+
+ u32 small = Small[--nSmall];
+ u32 large = Large[++nLarge];
+
+ afl->alias_probability[small] = P[small];
+ afl->alias_table[small] = large;
- a = S[--nS];
- g = L[--nL];
- afl->alias_probability[a] = P[a];
- afl->alias_table[a] = g;
- P[g] = P[g] + P[a] - 1;
- if (P[g] < 1) {
+ P[large] = P[large] - (1 - P[small]);
- S[nS++] = g;
+ if (P[large] < 1) {
+
+ Small[nSmall++] = large;
} else {
- L[nL++] = g;
+ Large[nLarge--] = large;
}
}
- while (nL)
- afl->alias_probability[L[--nL]] = 1;
+ while (nSmall) {
- while (nS)
- afl->alias_probability[S[--nS]] = 1;
+ afl->alias_probability[Small[--nSmall]] = 1;
+
+ }
+
+ while (nLarge != n - 1) {
+
+ afl->alias_probability[Large[++nLarge]] = 1;
+
+ }
afl->reinit_table = 0;
@@ -232,7 +298,7 @@ void create_alias_table(afl_state_t *afl) {
*/
/*
fprintf(stderr, " entry alias probability perf_score weight
- filename\n"); for (u32 i = 0; i < n; ++i) fprintf(stderr, " %5u %5u %11u
+ filename\n"); for (i = 0; i < n; ++i) fprintf(stderr, " %5u %5u %11u
%0.9f %0.9f %s\n", i, afl->alias_table[i], afl->alias_probability[i],
afl->queue_buf[i]->perf_score, afl->queue_buf[i]->weight,
afl->queue_buf[i]->fname);
@@ -246,11 +312,11 @@ void create_alias_table(afl_state_t *afl) {
void mark_as_det_done(afl_state_t *afl, struct queue_entry *q) {
- u8 fn[PATH_MAX];
- s32 fd;
+ char fn[PATH_MAX];
+ s32 fd;
snprintf(fn, PATH_MAX, "%s/queue/.state/deterministic_done/%s", afl->out_dir,
- strrchr(q->fname, '/') + 1);
+ strrchr((char *)q->fname, '/') + 1);
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
@@ -265,10 +331,10 @@ void mark_as_det_done(afl_state_t *afl, struct queue_entry *q) {
void mark_as_variable(afl_state_t *afl, struct queue_entry *q) {
- u8 fn[PATH_MAX];
- u8 ldest[PATH_MAX];
+ char fn[PATH_MAX];
+ char ldest[PATH_MAX];
- u8 *fn_name = strrchr(q->fname, '/') + 1;
+ char *fn_name = strrchr((char *)q->fname, '/') + 1;
sprintf(ldest, "../../%s", fn_name);
sprintf(fn, "%s/queue/.state/variable_behavior/%s", afl->out_dir, fn_name);
@@ -292,12 +358,12 @@ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) {
if (likely(state == q->fs_redundant)) { return; }
- u8 fn[PATH_MAX];
+ char fn[PATH_MAX];
q->fs_redundant = state;
sprintf(fn, "%s/queue/.state/redundant_edges/%s", afl->out_dir,
- strrchr(q->fname, '/') + 1);
+ strrchr((char *)q->fname, '/') + 1);
if (state) {
@@ -408,16 +474,16 @@ u8 check_if_text_buf(u8 *buf, u32 len) {
static u8 check_if_text(afl_state_t *afl, struct queue_entry *q) {
- if (q->len < AFL_TXT_MIN_LEN) return 0;
+ if (q->len < AFL_TXT_MIN_LEN || q->len < AFL_TXT_MAX_LEN) return 0;
- u8 * buf;
+ u8 *buf;
int fd;
u32 len = q->len, offset = 0, ascii = 0, utf8 = 0;
ssize_t comp;
if (len >= MAX_FILE) len = MAX_FILE - 1;
- if ((fd = open(q->fname, O_RDONLY)) < 0) return 0;
- buf = afl_realloc(AFL_BUF_PARAM(in_scratch), len + 1);
+ if ((fd = open((char *)q->fname, O_RDONLY)) < 0) return 0;
+ buf = (u8 *)afl_realloc(AFL_BUF_PARAM(in_scratch), len + 1);
comp = read(fd, buf, len);
close(fd);
if (comp != (ssize_t)len) return 0;
@@ -519,7 +585,8 @@ static u8 check_if_text(afl_state_t *afl, struct queue_entry *q) {
void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
- struct queue_entry *q = ck_alloc(sizeof(struct queue_entry));
+ struct queue_entry *q =
+ (struct queue_entry *)ck_alloc(sizeof(struct queue_entry));
q->fname = fname;
q->len = len;
@@ -553,13 +620,30 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
afl->cycles_wo_finds = 0;
- struct queue_entry **queue_buf = afl_realloc(
+ struct queue_entry **queue_buf = (struct queue_entry **)afl_realloc(
AFL_BUF_PARAM(queue), afl->queued_items * sizeof(struct queue_entry *));
if (unlikely(!queue_buf)) { PFATAL("alloc"); }
queue_buf[afl->queued_items - 1] = q;
q->id = afl->queued_items - 1;
- afl->last_find_time = get_cur_time();
+ u64 cur_time = get_cur_time();
+
+ if (likely(afl->start_time) &&
+ unlikely(afl->longest_find_time < cur_time - afl->last_find_time)) {
+
+ if (unlikely(!afl->last_find_time)) {
+
+ afl->longest_find_time = cur_time - afl->start_time;
+
+ } else {
+
+ afl->longest_find_time = cur_time - afl->last_find_time;
+
+ }
+
+ }
+
+ afl->last_find_time = cur_time;
if (afl->custom_mutators_count) {
@@ -573,7 +657,11 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
}
/* only redqueen currently uses is_ascii */
- if (afl->shm.cmplog_mode) q->is_ascii = check_if_text(afl, q);
+ if (unlikely(afl->shm.cmplog_mode && !q->is_ascii)) {
+
+ q->is_ascii = check_if_text(afl, q);
+
+ }
}
@@ -703,7 +791,7 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) {
if (!q->trace_mini) {
u32 len = (afl->fsrv.map_size >> 3);
- q->trace_mini = ck_alloc(len);
+ q->trace_mini = (u8 *)ck_alloc(len);
minimize_bits(afl, q->trace_mini, afl->fsrv.trace_bits);
}
@@ -795,8 +883,14 @@ void cull_queue(afl_state_t *afl) {
u32 calculate_score(afl_state_t *afl, struct queue_entry *q) {
- u32 avg_exec_us = afl->total_cal_us / afl->total_cal_cycles;
- u32 avg_bitmap_size = afl->total_bitmap_size / afl->total_bitmap_entries;
+ u32 cal_cycles = afl->total_cal_cycles;
+ u32 bitmap_entries = afl->total_bitmap_entries;
+
+ if (unlikely(!cal_cycles)) { cal_cycles = 1; }
+ if (unlikely(!bitmap_entries)) { bitmap_entries = 1; }
+
+ u32 avg_exec_us = afl->total_cal_us / cal_cycles;
+ u32 avg_bitmap_size = afl->total_bitmap_size / bitmap_entries;
u32 perf_score = 100;
/* Adjust score based on execution speed of this path, compared to the
@@ -1000,10 +1094,16 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) {
break;
case LIN:
+ // Don't modify perf_score for unfuzzed seeds
+ if (!q->fuzz_level) break;
+
factor = q->fuzz_level / (afl->n_fuzz[q->n_fuzz_entry] + 1);
break;
case QUAD:
+ // Don't modify perf_score for unfuzzed seeds
+ if (!q->fuzz_level) break;
+
factor =
q->fuzz_level * q->fuzz_level / (afl->n_fuzz[q->n_fuzz_entry] + 1);
break;
@@ -1083,19 +1183,19 @@ inline void queue_testcase_retake(afl_state_t *afl, struct queue_entry *q,
if (len != old_len) {
afl->q_testcase_cache_size = afl->q_testcase_cache_size + len - old_len;
- q->testcase_buf = realloc(q->testcase_buf, len);
+ q->testcase_buf = (u8 *)realloc(q->testcase_buf, len);
if (unlikely(!q->testcase_buf)) {
- PFATAL("Unable to malloc '%s' with len %u", q->fname, len);
+ PFATAL("Unable to malloc '%s' with len %u", (char *)q->fname, len);
}
}
- int fd = open(q->fname, O_RDONLY);
+ int fd = open((char *)q->fname, O_RDONLY);
- if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", q->fname); }
+ if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", (char *)q->fname); }
ck_read(fd, q->testcase_buf, len, q->fname);
close(fd);
@@ -1115,7 +1215,7 @@ inline void queue_testcase_retake_mem(afl_state_t *afl, struct queue_entry *q,
if (likely(len != old_len)) {
- u8 *ptr = realloc(q->testcase_buf, len);
+ u8 *ptr = (u8 *)realloc(q->testcase_buf, len);
if (likely(ptr)) {
@@ -1147,23 +1247,23 @@ inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) {
if (unlikely(q == afl->queue_cur)) {
- buf = afl_realloc((void **)&afl->testcase_buf, len);
+ buf = (u8 *)afl_realloc((void **)&afl->testcase_buf, len);
} else {
- buf = afl_realloc((void **)&afl->splicecase_buf, len);
+ buf = (u8 *)afl_realloc((void **)&afl->splicecase_buf, len);
}
if (unlikely(!buf)) {
- PFATAL("Unable to malloc '%s' with len %u", q->fname, len);
+ PFATAL("Unable to malloc '%s' with len %u", (char *)q->fname, len);
}
- int fd = open(q->fname, O_RDONLY);
+ int fd = open((char *)q->fname, O_RDONLY);
- if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", q->fname); }
+ if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", (char *)q->fname); }
ck_read(fd, buf, len, q->fname);
close(fd);
@@ -1207,7 +1307,7 @@ inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) {
do_once = 1;
// release unneeded memory
- afl->q_testcase_cache = ck_realloc(
+ afl->q_testcase_cache = (struct queue_entry **)ck_realloc(
afl->q_testcase_cache,
(afl->q_testcase_max_cache_entries + 1) * sizeof(size_t));
@@ -1254,15 +1354,15 @@ inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) {
/* Map the test case into memory. */
- int fd = open(q->fname, O_RDONLY);
+ int fd = open((char *)q->fname, O_RDONLY);
- if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", q->fname); }
+ if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", (char *)q->fname); }
- q->testcase_buf = malloc(len);
+ q->testcase_buf = (u8 *)malloc(len);
if (unlikely(!q->testcase_buf)) {
- PFATAL("Unable to malloc '%s' with len %u", q->fname, len);
+ PFATAL("Unable to malloc '%s' with len %u", (char *)q->fname, len);
}
@@ -1325,11 +1425,11 @@ inline void queue_testcase_store_mem(afl_state_t *afl, struct queue_entry *q,
/* Map the test case into memory. */
- q->testcase_buf = malloc(len);
+ q->testcase_buf = (u8 *)malloc(len);
if (unlikely(!q->testcase_buf)) {
- PFATAL("Unable to malloc '%s' with len %u", q->fname, len);
+ PFATAL("Unable to malloc '%s' with len %u", (char *)q->fname, len);
}
diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c
index 2dbad5cf..41644cb9 100644
--- a/src/afl-fuzz-redqueen.c
+++ b/src/afl-fuzz-redqueen.c
@@ -11,7 +11,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -28,8 +28,8 @@
#include "afl-fuzz.h"
#include "cmplog.h"
-//#define _DEBUG
-//#define CMPLOG_INTROSPECTION
+// #define _DEBUG
+// #define CMPLOG_INTROSPECTION
// CMP attribute enum
enum {
@@ -167,6 +167,25 @@ static u8 get_exec_checksum(afl_state_t *afl, u8 *buf, u32 len, u64 *cksum) {
}
+/* replace everything with different values */
+static void random_replace(afl_state_t *afl, u8 *buf, u32 len) {
+
+ for (u32 i = 0; i < len; i++) {
+
+ u8 c;
+
+ do {
+
+ c = rand_below(afl, 256);
+
+ } while (c == buf[i]);
+
+ buf[i] = c;
+
+ }
+
+}
+
/* replace everything with different values but stay in the same type */
static void type_replace(afl_state_t *afl, u8 *buf, u32 len) {
@@ -266,10 +285,10 @@ static void type_replace(afl_state_t *afl, u8 *buf, u32 len) {
static u8 colorization(afl_state_t *afl, u8 *buf, u32 len,
struct tainted **taints) {
- struct range * ranges = add_range(NULL, 0, len - 1), *rng;
+ struct range *ranges = add_range(NULL, 0, len - 1), *rng;
struct tainted *taint = NULL;
- u8 * backup = ck_alloc_nozero(len);
- u8 * changed = ck_alloc_nozero(len);
+ u8 *backup = ck_alloc_nozero(len);
+ u8 *changed = ck_alloc_nozero(len);
#if defined(_DEBUG) || defined(CMPLOG_INTROSPECTION)
u64 start_time = get_cur_time();
@@ -293,7 +312,15 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len,
memcpy(backup, buf, len);
memcpy(changed, buf, len);
- type_replace(afl, changed, len);
+ if (afl->cmplog_random_colorization) {
+
+ random_replace(afl, changed, len);
+
+ } else {
+
+ type_replace(afl, changed, len);
+
+ }
while ((rng = pop_biggest_range(&ranges)) != NULL &&
afl->stage_cur < afl->stage_max) {
@@ -352,7 +379,7 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len,
}
- if (++afl->stage_cur % screen_update == 0) { show_stats(afl); };
+ if (unlikely(++afl->stage_cur % screen_update == 0)) { show_stats(afl); };
}
@@ -544,7 +571,7 @@ static u8 its_fuzz(afl_state_t *afl, u8 *buf, u32 len, u8 *status) {
}
-//#ifdef CMPLOG_SOLVE_TRANSFORM
+// #ifdef CMPLOG_SOLVE_TRANSFORM
static int strntoll(const char *str, size_t sz, char **end, int base,
long long *out) {
@@ -575,7 +602,7 @@ static int strntoull(const char *str, size_t sz, char **end, int base,
char buf[64];
unsigned long long ret;
- const char * beg = str;
+ const char *beg = str;
if (!str || !sz) { return 1; }
@@ -744,7 +771,7 @@ static void to_base64(u8 *src, u8 *dst, u32 dst_len) {
#endif
-//#endif
+// #endif
static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
u64 pattern, u64 repl, u64 o_pattern,
@@ -755,15 +782,15 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
u64 *buf_64 = (u64 *)&buf[idx];
u32 *buf_32 = (u32 *)&buf[idx];
u16 *buf_16 = (u16 *)&buf[idx];
- u8 * buf_8 = &buf[idx];
+ u8 *buf_8 = &buf[idx];
u64 *o_buf_64 = (u64 *)&orig_buf[idx];
u32 *o_buf_32 = (u32 *)&orig_buf[idx];
u16 *o_buf_16 = (u16 *)&orig_buf[idx];
- u8 * o_buf_8 = &orig_buf[idx];
+ u8 *o_buf_8 = &orig_buf[idx];
u32 its_len = MIN(len - idx, taint_len);
- if (afl->fsrv.total_execs - last_update > screen_update) {
+ if (unlikely(afl->fsrv.total_execs - last_update > screen_update)) {
show_stats(afl);
last_update = afl->fsrv.total_execs;
@@ -776,11 +803,11 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
// o_pattern, pattern, repl, changed_val, idx, taint_len,
// hshape, attr);
- //#ifdef CMPLOG_SOLVE_TRANSFORM
- // reverse atoi()/strnu?toll() is expensive, so we only to it in lvl 3
+ // #ifdef CMPLOG_SOLVE_TRANSFORM
+ // reverse atoi()/strnu?toll() is expensive, so we only to it in lvl 3
if (afl->cmplog_enable_transform && (lvl & LVL3)) {
- u8 * endptr;
+ u8 *endptr;
u8 use_num = 0, use_unum = 0;
unsigned long long unum;
long long num;
@@ -1008,7 +1035,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
} else {
- diff = 0;
+ o_diff = 0;
}
@@ -1093,7 +1120,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
}
- //#endif
+ // #endif
// we only allow this for ascii2integer (above) so leave if this is the case
if (unlikely(pattern == o_pattern)) { return 0; }
@@ -1248,7 +1275,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
// 16 = modified float, 32 = modified integer (modified = wont match
// in original buffer)
- //#ifdef CMPLOG_SOLVE_ARITHMETIC
+ // #ifdef CMPLOG_SOLVE_ARITHMETIC
if (!afl->cmplog_enable_arith || lvl < LVL3 || attr == IS_TRANSFORM) {
return 0;
@@ -1413,8 +1440,8 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
}
- //#endif /*
- // CMPLOG_SOLVE_ARITHMETIC
+ // #endif /*
+ // CMPLOG_SOLVE_ARITHMETIC
return 0;
@@ -1428,7 +1455,7 @@ static u8 cmp_extend_encodingN(afl_state_t *afl, struct cmp_header *h,
u32 taint_len, u8 *orig_buf, u8 *buf, u8 *cbuf,
u32 len, u8 do_reverse, u8 lvl, u8 *status) {
- if (afl->fsrv.total_execs - last_update > screen_update) {
+ if (unlikely(afl->fsrv.total_execs - last_update > screen_update)) {
show_stats(afl);
last_update = afl->fsrv.total_execs;
@@ -1597,6 +1624,8 @@ static void try_to_add_to_dictN(afl_state_t *afl, u128 v, u8 size) {
}
+ if (cons_0 > 1 || cons_ff > 1) { return; }
+
}
maybe_add_auto(afl, (u8 *)&v + off, size);
@@ -1613,7 +1642,7 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
u32 len, u32 lvl, struct tainted *taint) {
struct cmp_header *h = &afl->shm.cmp_map->headers[key];
- struct tainted * t;
+ struct tainted *t;
u32 i, j, idx, taint_len, loggeds;
u32 have_taint = 1;
u8 status = 0, found_one = 0;
@@ -1919,11 +1948,11 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
#ifndef CMPLOG_COMBINE
(void)(cbuf);
#endif
- //#ifndef CMPLOG_SOLVE_TRANSFORM
- // (void)(changed_val);
- //#endif
+ // #ifndef CMPLOG_SOLVE_TRANSFORM
+ // (void)(changed_val);
+ // #endif
- if (afl->fsrv.total_execs - last_update > screen_update) {
+ if (unlikely(afl->fsrv.total_execs - last_update > screen_update)) {
show_stats(afl);
last_update = afl->fsrv.total_execs;
@@ -2389,7 +2418,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
}
- //#endif
+ // #endif
return 0;
@@ -2398,7 +2427,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
u32 len, u8 lvl, struct tainted *taint) {
- struct tainted * t;
+ struct tainted *t;
struct cmp_header *h = &afl->shm.cmp_map->headers[key];
u32 i, j, idx, have_taint = 1, taint_len, loggeds;
u8 status = 0, found_one = 0;
@@ -2789,9 +2818,9 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len) {
} else if ((lvl & LVL1)
- //#ifdef CMPLOG_SOLVE_TRANSFORM
+ // #ifdef CMPLOG_SOLVE_TRANSFORM
|| ((lvl & LVL3) && afl->cmplog_enable_transform)
- //#endif
+ // #endif
) {
if (unlikely(rtn_fuzz(afl, k, orig_buf, buf, cbuf, len, lvl, taint))) {
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index 09e773f0..ac4fb4a9 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -10,7 +10,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -76,29 +76,13 @@ fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) {
u32 __attribute__((hot))
write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
-#ifdef _AFL_DOCUMENT_MUTATIONS
- s32 doc_fd;
- char fn[PATH_MAX];
- snprintf(fn, PATH_MAX, "%s/mutations/%09u:%s", afl->out_dir,
- afl->document_counter++,
- describe_op(afl, 0, NAME_MAX - strlen("000000000:")));
-
- 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);
- close(doc_fd);
-
- }
-
-#endif
+ u8 sent = 0;
if (unlikely(afl->custom_mutators_count)) {
ssize_t new_size = len;
- u8 * new_mem = *mem;
- u8 * new_buf = NULL;
+ u8 *new_mem = *mem;
+ u8 *new_buf = NULL;
LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
@@ -107,19 +91,38 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
new_size =
el->afl_custom_post_process(el->data, new_mem, new_size, &new_buf);
- if (unlikely(!new_buf && new_size <= 0)) {
+ if (unlikely(!new_buf || new_size <= 0)) {
- FATAL("Custom_post_process failed (ret: %lu)",
- (long unsigned)new_size);
+ new_size = 0;
+ new_buf = new_mem;
+ // FATAL("Custom_post_process failed (ret: %lu)", (long
+ // unsigned)new_size);
- }
+ } else {
+
+ new_mem = new_buf;
- new_mem = new_buf;
+ }
}
});
+ if (unlikely(!new_size)) {
+
+ // perform dummy runs (fix = 1), but skip all others
+ if (fix) {
+
+ new_size = len;
+
+ } else {
+
+ return 0;
+
+ }
+
+ }
+
if (unlikely(new_size < afl->min_length && !fix)) {
new_size = afl->min_length;
@@ -130,15 +133,58 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
}
- if (new_mem != *mem) {
+ if (new_mem != *mem && new_mem != NULL && new_size > 0) {
+
+ new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), new_size);
+ if (unlikely(!new_buf)) { PFATAL("alloc"); }
+ memcpy(new_buf, new_mem, new_size);
- *mem = new_mem;
+ /* if AFL_POST_PROCESS_KEEP_ORIGINAL is set then save the original memory
+ prior post-processing in new_mem to restore it later */
+ if (unlikely(afl->afl_env.afl_post_process_keep_original)) {
+
+ new_mem = *mem;
+
+ }
+
+ *mem = new_buf;
+ afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
}
- /* everything as planned. use the potentially new data. */
- afl_fsrv_write_to_testcase(&afl->fsrv, *mem, new_size);
- len = new_size;
+ if (unlikely(afl->custom_mutators_count)) {
+
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (el->afl_custom_fuzz_send) {
+
+ el->afl_custom_fuzz_send(el->data, *mem, new_size);
+ sent = 1;
+
+ }
+
+ });
+
+ }
+
+ if (likely(!sent)) {
+
+ /* everything as planned. use the potentially new data. */
+ afl_fsrv_write_to_testcase(&afl->fsrv, *mem, new_size);
+
+ if (likely(!afl->afl_env.afl_post_process_keep_original)) {
+
+ len = new_size;
+
+ } else {
+
+ /* restore the original memory which was saved in new_mem */
+ *mem = new_mem;
+ afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
+
+ }
+
+ }
} else {
@@ -152,11 +198,48 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
}
- /* boring uncustom. */
- afl_fsrv_write_to_testcase(&afl->fsrv, *mem, len);
+ if (unlikely(afl->custom_mutators_count)) {
+
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (el->afl_custom_fuzz_send) {
+
+ el->afl_custom_fuzz_send(el->data, *mem, len);
+ sent = 1;
+
+ }
+
+ });
+
+ }
+
+ if (likely(!sent)) {
+
+ /* boring uncustom. */
+ afl_fsrv_write_to_testcase(&afl->fsrv, *mem, len);
+
+ }
}
+#ifdef _AFL_DOCUMENT_MUTATIONS
+ s32 doc_fd;
+ char fn[PATH_MAX];
+ snprintf(fn, PATH_MAX, "%s/mutations/%09u:%s", afl->out_dir,
+ afl->document_counter++,
+ describe_op(afl, 0, NAME_MAX - strlen("000000000:")));
+
+ 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);
+ close(doc_fd);
+
+ }
+
+#endif
+
return len;
}
@@ -177,7 +260,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at,
if (unlikely(!mem_trimmed)) { PFATAL("alloc"); }
ssize_t new_size = len - skip_len;
- u8 * new_mem = mem;
+ u8 *new_mem = mem;
bool post_process_skipped = true;
@@ -211,14 +294,18 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at,
new_size =
el->afl_custom_post_process(el->data, new_mem, new_size, &new_buf);
- if (unlikely(!new_buf || new_size <= 0)) {
+ if (unlikely(!new_buf && new_size <= 0)) {
- FATAL("Custom_post_process failed (ret: %lu)",
- (long unsigned)new_size);
+ new_size = 0;
+ new_buf = new_mem;
+ // FATAL("Custom_post_process failed (ret: %lu)", (long
+ // unsigned)new_size);
- }
+ } else {
- new_mem = new_buf;
+ new_mem = new_buf;
+
+ }
}
@@ -344,7 +431,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
++q->cal_failed;
afl->stage_name = "calibration";
- afl->stage_max = afl->afl_env.afl_cal_fast ? 3 : CAL_CYCLES;
+ afl->stage_max = afl->afl_env.afl_cal_fast ? CAL_CYCLES_FAST : CAL_CYCLES;
/* Make sure the forkserver is up before we do anything, and let's not
count its spin-up time toward binary calibration. */
@@ -464,7 +551,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
}
- if (unlikely(!var_detected)) {
+ if (unlikely(!var_detected && !afl->afl_env.afl_no_warn_instability)) {
// note: from_queue seems to only be set during initialization
if (afl->afl_env.afl_no_ui || from_queue) {
@@ -577,7 +664,7 @@ abort_calibration:
void sync_fuzzers(afl_state_t *afl) {
- DIR * sd;
+ DIR *sd;
struct dirent *sd_ent;
u32 sync_cnt = 0, synced = 0, entries = 0;
u8 path[PATH_MAX + 1 + NAME_MAX];
@@ -973,7 +1060,11 @@ common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
u8 fault;
- len = write_to_testcase(afl, (void **)&out_buf, len, 0);
+ if (unlikely(len = write_to_testcase(afl, (void **)&out_buf, len, 0)) == 0) {
+
+ return 0;
+
+ }
fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c
index 98217438..5e736029 100644
--- a/src/afl-fuzz-state.c
+++ b/src/afl-fuzz-state.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -23,6 +23,8 @@
*/
+#include <signal.h>
+#include <limits.h>
#include "afl-fuzz.h"
#include "envs.h"
@@ -99,8 +101,10 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) {
afl->hang_tmout = EXEC_TIMEOUT;
afl->exit_on_time = 0;
afl->stats_update_freq = 1;
+ afl->stats_file_update_freq_msecs = STATS_UPDATE_SEC * 1000;
afl->stats_avg_exec = 0;
afl->skip_deterministic = 1;
+ afl->sync_time = SYNC_TIME;
afl->cmplog_lvl = 2;
afl->min_length = 1;
afl->max_length = MAX_FILE;
@@ -202,6 +206,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
afl->afl_env.afl_no_affinity =
get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+ } else if (!strncmp(env, "AFL_NO_WARN_INSTABILITY",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_no_warn_instability =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
} else if (!strncmp(env, "AFL_TRY_AFFINITY",
afl_environment_variable_len)) {
@@ -264,6 +275,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
afl->afl_env.afl_cmplog_only_new =
get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+ } else if (!strncmp(env, "AFL_NO_STARTUP_CALIBRATION",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_no_startup_calibration =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
} else if (!strncmp(env, "AFL_NO_UI", afl_environment_variable_len)) {
afl->afl_env.afl_no_ui =
@@ -283,6 +301,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
afl->afl_env.afl_ignore_problems =
get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+ } else if (!strncmp(env, "AFL_IGNORE_TIMEOUTS",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_ignore_timeouts =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
} else if (!strncmp(env, "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES",
afl_environment_variable_len)) {
@@ -369,6 +394,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
afl->afl_env.afl_statsd =
get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+ } else if (!strncmp(env, "AFL_POST_PROCESS_KEEP_ORIGINAL",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_post_process_keep_original =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
} else if (!strncmp(env, "AFL_TMPDIR",
afl_environment_variable_len)) {
@@ -479,7 +511,14 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
afl_environment_variable_len)) {
- afl->afl_env.afl_kill_signal =
+ afl->afl_env.afl_child_kill_signal =
+ (u8 *)get_afl_env(afl_environment_variables[i]);
+
+ } else if (!strncmp(env, "AFL_FORK_SERVER_KILL_SIGNAL",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_fsrv_kill_signal =
(u8 *)get_afl_env(afl_environment_variables[i]);
} else if (!strncmp(env, "AFL_TARGET_ENV",
@@ -509,13 +548,49 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
afl->afl_env.afl_pizza_mode =
atoi((u8 *)get_afl_env(afl_environment_variables[i]));
- if (afl->afl_env.afl_pizza_mode == 0) {
- afl->afl_env.afl_pizza_mode = 1;
+ } else if (!strncmp(env, "AFL_NO_CRASH_README",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_no_crash_readme =
+ atoi((u8 *)get_afl_env(afl_environment_variables[i]));
+
+ } else if (!strncmp(env, "AFL_SYNC_TIME",
+
+ afl_environment_variable_len)) {
+
+ int time = atoi((u8 *)get_afl_env(afl_environment_variables[i]));
+ if (time > 0) {
+
+ afl->sync_time = time * (60 * 1000LL);
+
+ } else {
+
+ WARNF(
+ "incorrect value for AFL_SYNC_TIME environment variable, "
+ "used default value %lld instead.",
+ afl->sync_time / 60 / 1000);
+
+ }
+
+ } else if (!strncmp(env, "AFL_FUZZER_STATS_UPDATE_INTERVAL",
+
+ afl_environment_variable_len)) {
+
+ u64 stats_update_freq_sec =
+ strtoull(get_afl_env(afl_environment_variables[i]), NULL, 0);
+ if (stats_update_freq_sec >= UINT_MAX ||
+ 0 == stats_update_freq_sec) {
+
+ WARNF(
+ "Incorrect value given to AFL_FUZZER_STATS_UPDATE_INTERVAL, "
+ "using default of %d seconds\n",
+ STATS_UPDATE_SEC);
} else {
- afl->pizza_is_served = 1;
+ afl->stats_file_update_freq_msecs = stats_update_freq_sec * 1000;
}
@@ -580,6 +655,16 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
}
+ if (afl->afl_env.afl_pizza_mode > 0) {
+
+ afl->pizza_is_served = 1;
+
+ } else if (afl->afl_env.afl_pizza_mode < 0) {
+
+ OKF("Pizza easter egg mode is now disabled.");
+
+ }
+
if (issue_detected) { sleep(2); }
}
@@ -628,8 +713,17 @@ void afl_states_stop(void) {
LIST_FOREACH(&afl_states, afl_state_t, {
- if (el->fsrv.child_pid > 0) kill(el->fsrv.child_pid, el->fsrv.kill_signal);
- if (el->fsrv.fsrv_pid > 0) kill(el->fsrv.fsrv_pid, el->fsrv.kill_signal);
+ /* NOTE: We need to make sure that the parent (the forkserver) reap the
+ * child (see below). */
+ if (el->fsrv.child_pid > 0)
+ kill(el->fsrv.child_pid, el->fsrv.child_kill_signal);
+ if (el->fsrv.fsrv_pid > 0) {
+
+ kill(el->fsrv.fsrv_pid, el->fsrv.fsrv_kill_signal);
+ /* Make sure the forkserver does not end up as zombie. */
+ waitpid(el->fsrv.fsrv_pid, NULL, 0);
+
+ }
});
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
index 5b237748..07157bf7 100644
--- a/src/afl-fuzz-stats.c
+++ b/src/afl-fuzz-stats.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -59,10 +59,10 @@ void write_setup_file(afl_state_t *afl, u32 argc, char **argv) {
if (i) fprintf(f, " ");
#ifdef __ANDROID__
- if (memchr(argv[i], '\'', sizeof(argv[i]))) {
+ if (memchr(argv[i], '\'', strlen(argv[i]))) {
#else
- if (index(argv[i], '\'')) {
+ if (strchr(argv[i], '\'')) {
#endif
@@ -94,7 +94,7 @@ void load_stats_file(afl_state_t *afl) {
FILE *f;
u8 buf[MAX_LINE];
- u8 * lptr;
+ u8 *lptr;
u8 fn[PATH_MAX];
u32 lineno = 0;
snprintf(fn, PATH_MAX, "%s/fuzzer_stats", afl->out_dir);
@@ -251,6 +251,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
"fuzzer_pid : %u\n"
"cycles_done : %llu\n"
"cycles_wo_finds : %llu\n"
+ "time_wo_finds : %llu\n"
"execs_done : %llu\n"
"execs_per_sec : %0.02f\n"
"execs_ps_last_min : %0.02f\n"
@@ -291,6 +292,11 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
(afl->start_time - afl->prev_run_time) / 1000, cur_time / 1000,
(afl->prev_run_time + cur_time - afl->start_time) / 1000, (u32)getpid(),
afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->cycles_wo_finds,
+ afl->longest_find_time > cur_time - afl->last_find_time
+ ? afl->longest_find_time / 1000
+ : ((afl->start_time == 0 || afl->last_find_time == 0)
+ ? 0
+ : (cur_time - afl->last_find_time) / 1000),
afl->fsrv.total_execs,
afl->fsrv.total_execs /
((double)(afl->prev_run_time + get_cur_time() - afl->start_time) /
@@ -365,6 +371,39 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
}
+#ifdef INTROSPECTION
+void write_queue_stats(afl_state_t *afl) {
+
+ FILE *f;
+ u8 *fn = alloc_printf("%s/queue_data", afl->out_dir);
+ if ((f = fopen(fn, "w")) != NULL) {
+
+ u32 id;
+ fprintf(f,
+ "# filename, length, exec_us, selected, skipped, mutations, finds, "
+ "crashes, timeouts, bitmap_size, perf_score, weight, colorized, "
+ "favored, disabled\n");
+ for (id = 0; id < afl->queued_items; ++id) {
+
+ struct queue_entry *q = afl->queue_buf[id];
+ fprintf(f, "\"%s\",%u,%llu,%u,%u,%llu,%u,%u,%u,%u,%.3f,%.3f,%u,%u,%u\n",
+ q->fname, q->len, q->exec_us, q->stats_selected, q->stats_skipped,
+ q->stats_mutated, q->stats_finds, q->stats_crashes,
+ q->stats_tmouts, q->bitmap_size, q->perf_score, q->weight,
+ q->colorized, q->favored, q->disabled);
+
+ }
+
+ fclose(f);
+
+ }
+
+ ck_free(fn);
+
+}
+
+#endif
+
/* Update the plot file if there is a reason to. */
void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
@@ -578,9 +617,10 @@ void show_stats_normal(afl_state_t *afl) {
/* Roughly every minute, update fuzzer stats and save auto tokens. */
- if (unlikely(!afl->non_instrumented_mode &&
- (afl->force_ui_update ||
- cur_ms - afl->stats_last_stats_ms > STATS_UPDATE_SEC * 1000))) {
+ if (unlikely(
+ !afl->non_instrumented_mode &&
+ (afl->force_ui_update || cur_ms - afl->stats_last_stats_ms >
+ afl->stats_file_update_freq_msecs))) {
afl->stats_last_stats_ms = cur_ms;
write_stats_file(afl, t_bytes, t_byte_ratio, stab_ratio,
@@ -613,6 +653,18 @@ void show_stats_normal(afl_state_t *afl) {
}
+ /* Every now and then, write queue data. */
+
+ if (unlikely(afl->force_ui_update ||
+ cur_ms - afl->stats_last_queue_ms > QUEUE_UPDATE_SEC * 1000)) {
+
+ afl->stats_last_queue_ms = cur_ms;
+#ifdef INTROSPECTION
+ write_queue_stats(afl);
+#endif
+
+ }
+
/* Honor AFL_EXIT_WHEN_DONE and AFL_BENCH_UNTIL_CRASH. */
if (unlikely(!afl->non_instrumented_mode && afl->cycles_wo_finds > 100 &&
@@ -624,9 +676,14 @@ void show_stats_normal(afl_state_t *afl) {
/* AFL_EXIT_ON_TIME. */
- if (unlikely(afl->last_find_time && !afl->non_instrumented_mode &&
- afl->afl_env.afl_exit_on_time &&
- (cur_ms - afl->last_find_time) > afl->exit_on_time)) {
+ /* If no coverage was found yet, check whether run time is greater than
+ * exit_on_time. */
+
+ if (unlikely(!afl->non_instrumented_mode && afl->afl_env.afl_exit_on_time &&
+ ((afl->last_find_time &&
+ (cur_ms - afl->last_find_time) > afl->exit_on_time) ||
+ (!afl->last_find_time &&
+ (cur_ms - afl->start_time) > afl->exit_on_time)))) {
afl->stop_soon = 2;
@@ -696,20 +753,20 @@ void show_stats_normal(afl_state_t *afl) {
#ifdef __linux__
if (afl->fsrv.nyx_mode) {
- sprintf(banner + banner_pad,
- "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s] - Nyx",
- afl->crash_mode ? cPIN "peruvian were-rabbit"
- : cYEL "american fuzzy lop",
- si, afl->use_banner, afl->power_name);
+ snprintf(banner + banner_pad, sizeof(banner) - banner_pad,
+ "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s] - Nyx",
+ afl->crash_mode ? cPIN "peruvian were-rabbit"
+ : cYEL "american fuzzy lop",
+ si, afl->use_banner, afl->power_name);
} else {
#endif
- sprintf(banner + banner_pad,
- "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s]",
- afl->crash_mode ? cPIN "peruvian were-rabbit"
- : cYEL "american fuzzy lop",
- si, afl->use_banner, afl->power_name);
+ snprintf(banner + banner_pad, sizeof(banner) - banner_pad,
+ "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s]",
+ afl->crash_mode ? cPIN "peruvian were-rabbit"
+ : cYEL "american fuzzy lop",
+ si, afl->use_banner, afl->power_name);
#ifdef __linux__
@@ -761,26 +818,26 @@ void show_stats_normal(afl_state_t *afl) {
} else
- /* Subsequent cycles, but we're still making finds. */
- if (afl->cycles_wo_finds < 25 || min_wo_finds < 30) {
+ /* Subsequent cycles, but we're still making finds. */
+ if (afl->cycles_wo_finds < 25 || min_wo_finds < 30) {
- strcpy(tmp, cYEL);
+ strcpy(tmp, cYEL);
- } else
+ } else
/* No finds for a long time and no test cases to try. */
if (afl->cycles_wo_finds > 100 && !afl->pending_not_fuzzed &&
min_wo_finds > 120) {
- strcpy(tmp, cLGN);
+ strcpy(tmp, cLGN);
- /* Default: cautiously OK to stop? */
+ /* Default: cautiously OK to stop? */
- } else {
+ } else {
- strcpy(tmp, cLBL);
+ strcpy(tmp, cLBL);
- }
+ }
}
@@ -1399,6 +1456,18 @@ void show_stats_pizza(afl_state_t *afl) {
}
+ /* Every now and then, write queue data. */
+
+ if (unlikely(afl->force_ui_update ||
+ cur_ms - afl->stats_last_queue_ms > QUEUE_UPDATE_SEC * 1000)) {
+
+ afl->stats_last_queue_ms = cur_ms;
+#ifdef INTROSPECTION
+ write_queue_stats(afl);
+#endif
+
+ }
+
/* Honor AFL_EXIT_WHEN_DONE and AFL_BENCH_UNTIL_CRASH. */
if (unlikely(!afl->non_instrumented_mode && afl->cycles_wo_finds > 100 &&
@@ -1410,9 +1479,14 @@ void show_stats_pizza(afl_state_t *afl) {
/* AFL_EXIT_ON_TIME. */
- if (unlikely(afl->last_find_time && !afl->non_instrumented_mode &&
- afl->afl_env.afl_exit_on_time &&
- (cur_ms - afl->last_find_time) > afl->exit_on_time)) {
+ /* If no coverage was found yet, check whether run time is greater than
+ * exit_on_time. */
+
+ if (unlikely(!afl->non_instrumented_mode && afl->afl_env.afl_exit_on_time &&
+ ((afl->last_find_time &&
+ (cur_ms - afl->last_find_time) > afl->exit_on_time) ||
+ (!afl->last_find_time &&
+ (cur_ms - afl->start_time) > afl->exit_on_time)))) {
afl->stop_soon = 2;
@@ -1483,20 +1557,22 @@ void show_stats_pizza(afl_state_t *afl) {
#ifdef __linux__
if (afl->fsrv.nyx_mode) {
- sprintf(banner + banner_pad,
- "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s] - Nyx",
- afl->crash_mode ? cPIN "Mozzarbella Pizzeria table booking system"
- : cYEL "Mozzarbella Pizzeria management system",
- si, afl->use_banner, afl->power_name);
+ snprintf(banner + banner_pad, sizeof(banner) - banner_pad,
+ "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s] - Nyx",
+ afl->crash_mode ? cPIN
+ "Mozzarbella Pizzeria table booking system"
+ : cYEL "Mozzarbella Pizzeria management system",
+ si, afl->use_banner, afl->power_name);
} else {
#endif
- sprintf(banner + banner_pad,
- "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s]",
- afl->crash_mode ? cPIN "Mozzarbella Pizzeria table booking system"
- : cYEL "Mozzarbella Pizzeria management system",
- si, afl->use_banner, afl->power_name);
+ snprintf(banner + banner_pad, sizeof(banner) - banner_pad,
+ "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s]",
+ afl->crash_mode ? cPIN
+ "Mozzarbella Pizzeria table booking system"
+ : cYEL "Mozzarbella Pizzeria management system",
+ si, afl->use_banner, afl->power_name);
#ifdef __linux__
@@ -1548,26 +1624,26 @@ void show_stats_pizza(afl_state_t *afl) {
} else
- /* Subsequent cycles, but we're still making finds. */
- if (afl->cycles_wo_finds < 25 || min_wo_finds < 30) {
+ /* Subsequent cycles, but we're still making finds. */
+ if (afl->cycles_wo_finds < 25 || min_wo_finds < 30) {
- strcpy(tmp, cYEL);
+ strcpy(tmp, cYEL);
- } else
+ } else
/* No finds for a long time and no test cases to try. */
if (afl->cycles_wo_finds > 100 && !afl->pending_not_fuzzed &&
min_wo_finds > 120) {
- strcpy(tmp, cLGN);
+ strcpy(tmp, cLGN);
- /* Default: cautiously OK to stop? */
+ /* Default: cautiously OK to stop? */
- } else {
+ } else {
- strcpy(tmp, cLBL);
+ strcpy(tmp, cLBL);
- }
+ }
}
@@ -1727,10 +1803,10 @@ void show_stats_pizza(afl_state_t *afl) {
/* Show a warning about slow execution. */
- if (afl->stats_avg_exec < 100) {
+ if (afl->stats_avg_exec < 20) {
sprintf(tmp, "%s/sec (%s)", u_stringify_float(IB(0), afl->stats_avg_exec),
- afl->stats_avg_exec < 20 ? "zzzz..." : "Gennarino is at it again!");
+ "zzzz...");
SAYF(bV bSTOP " pizza making speed : " cLRD
"%-22s ",
@@ -2105,7 +2181,9 @@ void show_init_stats(afl_state_t *afl) {
? 50000
: 10000)) {
- WARNF(cLRD "The target binary is pretty slow! See %s/perf_tips.md.",
+ WARNF(cLRD
+ "The target binary is pretty slow! See "
+ "%s/fuzzing_in_depth.md#i-improve-the-speed",
doc_path);
}
@@ -2134,13 +2212,17 @@ void show_init_stats(afl_state_t *afl) {
if (max_len > 50 * 1024) {
- WARNF(cLRD "Some test cases are huge (%s) - see %s/perf_tips.md!",
+ WARNF(cLRD
+ "Some test cases are huge (%s) - see "
+ "%s/fuzzing_in_depth.md#i-improve-the-speed",
stringify_mem_size(IB(0), max_len), doc_path);
} else if (max_len > 10 * 1024) {
- WARNF("Some test cases are big (%s) - see %s/perf_tips.md.",
- stringify_mem_size(IB(0), max_len), doc_path);
+ WARNF(
+ "Some test cases are big (%s) - see "
+ "%s/fuzzing_in_depth.md#i-improve-the-speed",
+ stringify_mem_size(IB(0), max_len), doc_path);
}
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index c5ab364a..4134b99e 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -25,6 +25,7 @@
#include "afl-fuzz.h"
#include "cmplog.h"
+#include "common.h"
#include <limits.h>
#include <stdlib.h>
#ifndef USEMMAP
@@ -123,7 +124,8 @@ static void usage(u8 *argv0, int more_help) {
"\n%s [ options ] -- /path/to/fuzzed_app [ ... ]\n\n"
"Required parameters:\n"
- " -i dir - input directory with test cases\n"
+ " -i dir - input directory with test cases (or '-' to resume, "
+ "also see AFL_AUTORESUME)\n"
" -o dir - output directory for fuzzer findings\n\n"
"Execution control settings:\n"
@@ -164,16 +166,16 @@ static void usage(u8 *argv0, int more_help) {
" pacemaker mode (minutes of no new finds). 0 = "
"immediately,\n"
" -1 = immediately and together with normal mutation.\n"
- " See docs/README.MOpt.md\n"
" -c program - enable CmpLog by specifying a binary compiled for "
"it.\n"
- " if using QEMU/FRIDA or if you the fuzzing target is "
- "compiled"
+ " if using QEMU/FRIDA or the fuzzing target is "
+ "compiled\n"
" for CmpLog then just use -c 0.\n"
- " -l cmplog_opts - CmpLog configuration values (e.g. \"2AT\"):\n"
+ " -l cmplog_opts - CmpLog configuration values (e.g. \"2ATR\"):\n"
" 1=small files, 2=larger files (default), 3=all "
"files,\n"
- " A=arithmetic solving, T=transformational solving.\n\n"
+ " A=arithmetic solving, T=transformational solving,\n"
+ " R=random colorization bytes.\n\n"
"Fuzzing behavior settings:\n"
" -Z - sequential queue selection instead of weighted "
"random\n"
@@ -192,9 +194,9 @@ static void usage(u8 *argv0, int more_help) {
"executions.\n\n"
"Other stuff:\n"
- " -M/-S id - distributed mode (see docs/parallel_fuzzing.md)\n"
- " -M auto-sets -D, -Z (use -d to disable -D) and no "
- "trimming\n"
+ " -M/-S id - distributed mode (-M sets -Z and disables trimming)\n"
+ " see docs/fuzzing_in_depth.md#c-using-multiple-cores\n"
+ " for effective recommendations for parallel fuzzing.\n"
" -F path - sync to a foreign fuzzer queue directory (requires "
"-M, can\n"
" be specified up to %u times)\n"
@@ -208,7 +210,8 @@ static void usage(u8 *argv0, int more_help) {
" -b cpu_id - bind the fuzzing process to the specified CPU core "
"(0-...)\n"
" -e ext - file extension for the fuzz test input file (if "
- "needed)\n\n",
+ "needed)\n"
+ "\n",
argv0, EXEC_TIMEOUT, MEM_LIMIT, MAX_FILE, FOREIGN_SYNCS_MAX);
if (more_help > 1) {
@@ -248,19 +251,27 @@ static void usage(u8 *argv0, int more_help) {
"AFL_DISABLE_TRIM: disable the trimming of test cases\n"
"AFL_DUMB_FORKSRV: use fork server without feedback from target\n"
"AFL_EXIT_WHEN_DONE: exit when all inputs are run and no new finds are found\n"
- "AFL_EXIT_ON_TIME: exit when no new coverage finds are made within the specified time period\n"
- "AFL_EXPAND_HAVOC_NOW: immediately enable expand havoc mode (default: after 60 minutes and a cycle without finds)\n"
+ "AFL_EXIT_ON_TIME: exit when no new coverage is found within the specified time\n"
+ "AFL_EXPAND_HAVOC_NOW: immediately enable expand havoc mode (default: after 60\n"
+ " minutes and a cycle without finds)\n"
"AFL_FAST_CAL: limit the calibration stage to three cycles for speedup\n"
"AFL_FORCE_UI: force showing the status screen (for virtual consoles)\n"
- "AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in milliseconds)\n"
+ "AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in ms)\n"
"AFL_HANG_TMOUT: override timeout value (in milliseconds)\n"
"AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: don't warn about core dump handlers\n"
+ "AFL_IGNORE_PROBLEMS: do not abort fuzzing if an incorrect setup is detected\n"
+ "AFL_IGNORE_PROBLEMS_COVERAGE: if set in addition to AFL_IGNORE_PROBLEMS - also\n"
+ " ignore those libs for coverage\n"
+ "AFL_IGNORE_TIMEOUTS: do not process or save any timeouts\n"
"AFL_IGNORE_UNKNOWN_ENVS: don't warn on unknown env vars\n"
- "AFL_IGNORE_PROBLEMS: do not abort fuzzing if an incorrect setup is detected during a run\n"
"AFL_IMPORT_FIRST: sync and import test cases from other fuzzer instances first\n"
"AFL_INPUT_LEN_MIN/AFL_INPUT_LEN_MAX: like -g/-G set min/max fuzz length produced\n"
"AFL_PIZZA_MODE: 1 - enforce pizza mode, 0 - disable for April 1st\n"
- "AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc. (default: SIGKILL)\n"
+ "AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc.\n"
+ " (default: SIGKILL)\n"
+ "AFL_FORK_SERVER_KILL_SIGNAL: Kill signal for the fork server on termination\n"
+ " (default: SIGTERM). If unset and AFL_KILL_SIGNAL is\n"
+ " set, that value will be used.\n"
"AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
" the target was compiled for\n"
"AFL_MAX_DET_EXTRAS: if more entries are in the dictionary list than this value\n"
@@ -273,6 +284,7 @@ static void usage(u8 *argv0, int more_help) {
"AFL_NO_CPU_RED: avoid red color for showing very high cpu usage\n"
"AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n"
"AFL_NO_SNAPSHOT: do not use the snapshot feature (if the snapshot lkm is loaded)\n"
+ "AFL_NO_STARTUP_CALIBRATION: no initial seed calibration, start fuzzing at once\n"
"AFL_NO_UI: switch status screen off\n"
DYN_COLOR
@@ -283,6 +295,8 @@ static void usage(u8 *argv0, int more_help) {
PERSISTENT_MSG
+ "AFL_POST_PROCESS_KEEP_ORIGINAL: save the file as it was prior post-processing to the queue,\n"
+ " but execute the post-processed one\n"
"AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
"AFL_TARGET_ENV: pass extra environment variables to target\n"
"AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n"
@@ -295,12 +309,16 @@ static void usage(u8 *argv0, int more_help) {
"AFL_STATSD_TAGS_FLAVOR: set statsd tags format (default: disable tags)\n"
" Supported formats are: 'dogstatsd', 'librato',\n"
" 'signalfx' and 'influxdb'\n"
+ "AFL_SYNC_TIME: sync time between fuzzing instances (in minutes)\n"
+ "AFL_NO_CRASH_README: do not create a README in the crashes directory\n"
"AFL_TESTCACHE_SIZE: use a cache for testcases, improves performance (in MB)\n"
"AFL_TMPDIR: directory to use for input file generation (ramdisk recommended)\n"
"AFL_EARLY_FORKSERVER: force an early forkserver in an afl-clang-fast/\n"
" afl-clang-lto/afl-gcc-fast target\n"
"AFL_PERSISTENT: enforce persistent mode (if __AFL_LOOP is in a shared lib\n"
- "AFL_DEFER_FORKSRV: enforced deferred forkserver (__AFL_INIT is in a .so\n"
+ "AFL_DEFER_FORKSRV: enforced deferred forkserver (__AFL_INIT is in a .so)\n"
+ "AFL_FUZZER_STATS_UPDATE_INTERVAL: interval to update fuzzer_stats file in seconds, "
+ "(default: 60, minimum: 1)\n"
"\n"
);
@@ -313,7 +331,7 @@ static void usage(u8 *argv0, int more_help) {
}
#ifdef USE_PYTHON
- SAYF("Compiled with %s module support, see docs/custom_mutator.md\n",
+ SAYF("Compiled with %s module support, see docs/custom_mutators.md\n",
(char *)PYTHON_VERSION);
#else
SAYF("Compiled without Python module support.\n");
@@ -381,9 +399,9 @@ static int stricmp(char const *a, char const *b) {
static void fasan_check_afl_preload(char *afl_preload) {
char first_preload[PATH_MAX + 1] = {0};
- char * separator = strchr(afl_preload, ':');
+ char *separator = strchr(afl_preload, ':');
size_t first_preload_len = PATH_MAX;
- char * basename;
+ char *basename;
char clang_runtime_prefix[] = "libclang_rt.asan";
if (separator != NULL && (separator - afl_preload) < PATH_MAX) {
@@ -422,82 +440,19 @@ static void fasan_check_afl_preload(char *afl_preload) {
}
- #ifdef __linux__
- #include <dlfcn.h>
-
-nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) {
-
- void * handle;
- nyx_plugin_handler_t *plugin = calloc(1, sizeof(nyx_plugin_handler_t));
-
- ACTF("Trying to load libnyx.so plugin...");
- handle = dlopen((char *)libnyx_binary, RTLD_NOW);
- if (!handle) { goto fail; }
-
- plugin->nyx_new = dlsym(handle, "nyx_new");
- if (plugin->nyx_new == NULL) { goto fail; }
-
- plugin->nyx_new_parent = dlsym(handle, "nyx_new_parent");
- if (plugin->nyx_new_parent == NULL) { goto fail; }
-
- plugin->nyx_new_child = dlsym(handle, "nyx_new_child");
- if (plugin->nyx_new_child == NULL) { goto fail; }
-
- plugin->nyx_shutdown = dlsym(handle, "nyx_shutdown");
- if (plugin->nyx_shutdown == NULL) { goto fail; }
-
- plugin->nyx_option_set_reload_mode =
- dlsym(handle, "nyx_option_set_reload_mode");
- if (plugin->nyx_option_set_reload_mode == NULL) { goto fail; }
-
- plugin->nyx_option_set_timeout = dlsym(handle, "nyx_option_set_timeout");
- if (plugin->nyx_option_set_timeout == NULL) { goto fail; }
-
- plugin->nyx_option_apply = dlsym(handle, "nyx_option_apply");
- if (plugin->nyx_option_apply == NULL) { goto fail; }
-
- plugin->nyx_set_afl_input = dlsym(handle, "nyx_set_afl_input");
- if (plugin->nyx_set_afl_input == NULL) { goto fail; }
-
- plugin->nyx_exec = dlsym(handle, "nyx_exec");
- if (plugin->nyx_exec == NULL) { goto fail; }
-
- plugin->nyx_get_bitmap_buffer = dlsym(handle, "nyx_get_bitmap_buffer");
- if (plugin->nyx_get_bitmap_buffer == NULL) { goto fail; }
-
- plugin->nyx_get_bitmap_buffer_size =
- dlsym(handle, "nyx_get_bitmap_buffer_size");
- if (plugin->nyx_get_bitmap_buffer_size == NULL) { goto fail; }
-
- plugin->nyx_get_aux_string = dlsym(handle, "nyx_get_aux_string");
- if (plugin->nyx_get_aux_string == NULL) { goto fail; }
-
- OKF("libnyx plugin is ready!");
- return plugin;
-
-fail:
-
- FATAL("failed to load libnyx: %s\n", dlerror());
- free(plugin);
- return NULL;
-
-}
-
- #endif
-
/* Main entry point */
int main(int argc, char **argv_orig, char **envp) {
s32 opt, auto_sync = 0 /*, user_set_cache = 0*/;
u64 prev_queued = 0;
- u32 sync_interval_cnt = 0, seek_to = 0, show_help = 0,
+ u32 sync_interval_cnt = 0, seek_to = 0, show_help = 0, default_output = 1,
map_size = get_map_size();
u8 *extras_dir[4];
u8 mem_limit_given = 0, exit_1 = 0, debug = 0,
extras_dir_cnt = 0 /*, have_p = 0*/;
- char * afl_preload;
- char * frida_afl_preload = NULL;
+ char *afl_preload;
+ char *frida_afl_preload = NULL;
char **use_argv;
struct timeval tv;
@@ -792,6 +747,7 @@ int main(int argc, char **argv_orig, char **envp) {
afl->fsrv.out_file = ck_strdup(optarg);
afl->fsrv.use_stdin = 0;
+ default_output = 0;
break;
case 'x': /* dictionary */
@@ -1104,6 +1060,10 @@ int main(int argc, char **argv_orig, char **envp) {
case 'T':
afl->cmplog_enable_transform = 1;
break;
+ case 'r':
+ case 'R':
+ afl->cmplog_random_colorization = 1;
+ break;
default:
FATAL("Unknown option value '%c' in -l %s", *c, optarg);
@@ -1282,6 +1242,13 @@ int main(int argc, char **argv_orig, char **envp) {
}
+ if (afl->is_main_node == 1 && afl->schedule != FAST &&
+ afl->schedule != EXPLORE) {
+
+ FATAL("-M is compatible only with fast and explore -p power schedules");
+
+ }
+
if (optind == argc || !afl->in_dir || !afl->out_dir || show_help) {
usage(argv[0], show_help);
@@ -1314,28 +1281,26 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->fsrv.mem_limit && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260;
- OKF("afl++ is maintained by Marc \"van Hauser\" Heuse, Heiko \"hexcoder\" "
- "Eißfeldt, Andrea Fioraldi and Dominik Maier");
- OKF("afl++ is open source, get it at "
+ OKF("AFL++ is maintained by Marc \"van Hauser\" Heuse, Dominik Maier, Andrea "
+ "Fioraldi and Heiko \"hexcoder\" Eißfeldt");
+ OKF("AFL++ is open source, get it at "
"https://github.com/AFLplusplus/AFLplusplus");
- OKF("NOTE: This is v3.x which changes defaults and behaviours - see "
- "README.md");
+ OKF("NOTE: AFL++ >= v3 has changed defaults and behaviours - see README.md");
#ifdef __linux__
if (afl->fsrv.nyx_mode) {
- OKF("afl++ Nyx mode is enabled (developed and mainted by Sergej Schumilo)");
+ OKF("AFL++ Nyx mode is enabled (developed and mainted by Sergej Schumilo)");
OKF("Nyx is open source, get it at https://github.com/Nyx-Fuzz");
}
#endif
- if (afl->sync_id && afl->is_main_node &&
- afl->afl_env.afl_custom_mutator_only) {
+ if (!afl->skip_deterministic && afl->afl_env.afl_custom_mutator_only) {
- WARNF(
- "Using -M main node with the AFL_CUSTOM_MUTATOR_ONLY mutator options "
- "will result in no deterministic mutations being done!");
+ FATAL(
+ "Using -D determinstic fuzzing is incompatible with "
+ "AFL_CUSTOM_MUTATOR_ONLY!");
}
@@ -1355,8 +1320,15 @@ int main(int argc, char **argv_orig, char **envp) {
#endif
- afl->fsrv.kill_signal =
- parse_afl_kill_signal_env(afl->afl_env.afl_kill_signal, SIGKILL);
+ configure_afl_kill_signals(&afl->fsrv, afl->afl_env.afl_child_kill_signal,
+ afl->afl_env.afl_fsrv_kill_signal,
+ (afl->fsrv.qemu_mode || afl->unicorn_mode
+ #ifdef __linux__
+ || afl->fsrv.nyx_mode
+ #endif
+ )
+ ? SIGKILL
+ : SIGTERM);
setup_signal_handlers();
check_asan_opts(afl);
@@ -1467,7 +1439,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->shm.cmplog_mode &&
(!strcmp("-", afl->cmplog_binary) || !strcmp("0", afl->cmplog_binary))) {
- afl->cmplog_binary = argv[optind];
+ afl->cmplog_binary = strdup(argv[optind]);
}
@@ -1774,16 +1746,6 @@ int main(int argc, char **argv_orig, char **envp) {
check_if_tty(afl);
if (afl->afl_env.afl_force_ui) { afl->not_on_tty = 0; }
- if (afl->afl_env.afl_custom_mutator_only) {
-
- /* This ensures we don't proceed to havoc/splice */
- afl->custom_only = 1;
-
- /* Ensure we also skip all deterministic steps */
- afl->skip_deterministic = 1;
-
- }
-
get_core_count(afl);
atexit(at_exit);
@@ -1832,8 +1794,107 @@ int main(int argc, char **argv_orig, char **envp) {
printf("DEBUG: rand %06d is %u\n", counter, rand_below(afl, 65536));
#endif
+ if (!getenv("AFL_CUSTOM_INFO_PROGRAM")) {
+
+ setenv("AFL_CUSTOM_INFO_PROGRAM", argv[optind], 1);
+
+ }
+
+ if (!getenv("AFL_CUSTOM_INFO_PROGRAM_INPUT") && afl->fsrv.out_file) {
+
+ setenv("AFL_CUSTOM_INFO_PROGRAM_INPUT", afl->fsrv.out_file, 1);
+
+ }
+
+ if (!getenv("AFL_CUSTOM_INFO_PROGRAM_ARGV")) {
+
+ u8 envbuf[8096] = "", tmpbuf[8096] = "";
+ for (s32 i = optind + 1; i < argc; ++i) {
+
+ strcpy(tmpbuf, envbuf);
+ if (strchr(argv[i], ' ') && !strchr(argv[i], '"') &&
+ !strchr(argv[i], '\'')) {
+
+ if (!strchr(argv[i], '\'')) {
+
+ snprintf(envbuf, sizeof(tmpbuf), "%s '%s'", tmpbuf, argv[i]);
+
+ } else {
+
+ snprintf(envbuf, sizeof(tmpbuf), "%s \"%s\"", tmpbuf, argv[i]);
+
+ }
+
+ } else {
+
+ snprintf(envbuf, sizeof(tmpbuf), "%s %s", tmpbuf, argv[i]);
+
+ }
+
+ }
+
+ setenv("AFL_CUSTOM_INFO_PROGRAM_ARGV", envbuf + 1, 1);
+
+ }
+
+ if (!getenv("AFL_CUSTOM_INFO_OUT")) {
+
+ setenv("AFL_CUSTOM_INFO_OUT", afl->out_dir, 1); // same as __AFL_OUT_DIR
+
+ }
+
setup_custom_mutators(afl);
+ if (afl->afl_env.afl_custom_mutator_only) {
+
+ if (!afl->custom_mutators_count) {
+
+ if (afl->shm.cmplog_mode) {
+
+ WARNF(
+ "No custom mutator loaded, using AFL_CUSTOM_MUTATOR_ONLY is "
+ "pointless and only allowed now to allow experiments with CMPLOG.");
+
+ } else {
+
+ FATAL(
+ "No custom mutator loaded but AFL_CUSTOM_MUTATOR_ONLY specified.");
+
+ }
+
+ }
+
+ /* This ensures we don't proceed to havoc/splice */
+ afl->custom_only = 1;
+
+ /* Ensure we also skip all deterministic steps */
+ afl->skip_deterministic = 1;
+
+ }
+
+ if (afl->limit_time_sig > 0 && afl->custom_mutators_count) {
+
+ if (afl->custom_only) {
+
+ FATAL("Custom mutators are incompatible with MOpt (-L)");
+
+ }
+
+ u32 custom_fuzz = 0;
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (el->afl_custom_fuzz) { custom_fuzz = 1; }
+
+ });
+
+ if (custom_fuzz) {
+
+ WARNF("afl_custom_fuzz is incompatible with MOpt (-L)");
+
+ }
+
+ }
+
write_setup_file(afl, argc, argv);
setup_cmdline_file(afl, argv + optind);
@@ -1890,6 +1951,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (aa_loc && !afl->fsrv.out_file) {
afl->fsrv.use_stdin = 0;
+ default_output = 0;
if (afl->file_extension) {
@@ -1984,6 +2046,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->non_instrumented_mode || afl->fsrv.qemu_mode ||
afl->fsrv.frida_mode || afl->fsrv.cs_mode || afl->unicorn_mode) {
+ u32 old_map_size = map_size;
map_size = afl->fsrv.real_map_size = afl->fsrv.map_size = MAP_SIZE;
afl->virgin_bits = ck_realloc(afl->virgin_bits, map_size);
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, map_size);
@@ -1995,6 +2058,18 @@ int main(int argc, char **argv_orig, char **envp) {
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;
@@ -2022,6 +2097,7 @@ int main(int argc, char **argv_orig, char **envp) {
OKF("Re-initializing maps to %u bytes", new_map_size);
+ u32 old_map_size = map_size;
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
@@ -2034,6 +2110,18 @@ int main(int argc, char **argv_orig, char **envp) {
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;
@@ -2059,6 +2147,7 @@ int main(int argc, char **argv_orig, char **envp) {
afl->cmplog_fsrv.qemu_mode = afl->fsrv.qemu_mode;
afl->cmplog_fsrv.frida_mode = afl->fsrv.frida_mode;
afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary;
+ afl->cmplog_fsrv.target_path = afl->fsrv.target_path;
afl->cmplog_fsrv.init_child_func = cmplog_exec_child;
if ((map_size <= DEFAULT_SHMEM_SIZE ||
@@ -2083,6 +2172,7 @@ int main(int argc, char **argv_orig, char **envp) {
OKF("Re-initializing maps to %u bytes due cmplog", new_map_size);
+ u32 old_map_size = map_size;
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
@@ -2095,6 +2185,18 @@ int main(int argc, char **argv_orig, char **envp) {
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);
afl_shm_deinit(&afl->shm);
@@ -2129,6 +2231,24 @@ int main(int argc, char **argv_orig, char **envp) {
}
+ if (afl->fsrv.out_file && afl->fsrv.use_shmem_fuzz) {
+
+ unlink(afl->fsrv.out_file);
+ afl->fsrv.out_file = NULL;
+ afl->fsrv.use_stdin = 0;
+ close(afl->fsrv.out_fd);
+ afl->fsrv.out_fd = -1;
+
+ if (!afl->unicorn_mode && !afl->fsrv.use_stdin && !default_output) {
+
+ WARNF(
+ "You specified -f or @@ on the command line but the target harness "
+ "specified fuzz cases via shmem, switching to shmem!");
+
+ }
+
+ }
+
deunicode_extras(afl);
dedup_extras(afl);
if (afl->extras_cnt) { OKF("Loaded a total of %u extras.", afl->extras_cnt); }
@@ -2148,7 +2268,16 @@ int main(int argc, char **argv_orig, char **envp) {
memset(afl->virgin_tmout, 255, map_size);
memset(afl->virgin_crash, 255, map_size);
- perform_dry_run(afl);
+ if (likely(!afl->afl_env.afl_no_startup_calibration)) {
+
+ perform_dry_run(afl);
+
+ } else {
+
+ ACTF("skipping initial seed calibration due option override");
+ usleep(1000);
+
+ }
if (afl->q_testcase_max_cache_entries) {
@@ -2167,14 +2296,6 @@ int main(int argc, char **argv_orig, char **envp) {
if (!afl->pending_not_fuzzed || !valid_seeds) {
- #ifdef __linux__
- if (afl->fsrv.nyx_mode) {
-
- afl->fsrv.nyx_handlers->nyx_shutdown(afl->fsrv.nyx_runner);
-
- }
-
- #endif
FATAL("We need at least one valid input seed that does not crash!");
}
@@ -2233,8 +2354,10 @@ int main(int argc, char **argv_orig, char **envp) {
// real start time, we reset, so this works correctly with -V
afl->start_time = get_cur_time();
- u32 runs_in_current_cycle = (u32)-1;
- u32 prev_queued_items = 0;
+ #ifdef INTROSPECTION
+ u32 prev_saved_crashes = 0, prev_saved_tmouts = 0;
+ #endif
+ u32 prev_queued_items = 0, runs_in_current_cycle = (u32)-1;
u8 skipped_fuzz;
#ifdef INTROSPECTION
@@ -2262,6 +2385,12 @@ int main(int argc, char **argv_orig, char **envp) {
(!afl->queue_cycle && afl->afl_env.afl_import_first)) &&
afl->sync_id)) {
+ if (!afl->queue_cycle && afl->afl_env.afl_import_first) {
+
+ OKF("Syncing queues from other fuzzer instances first ...");
+
+ }
+
sync_fuzzers(afl);
}
@@ -2405,10 +2534,22 @@ int main(int argc, char **argv_orig, char **envp) {
}
#ifdef INTROSPECTION
- fprintf(afl->introspection_file,
- "CYCLE cycle=%llu cycle_wo_finds=%llu expand_havoc=%u queue=%u\n",
- afl->queue_cycle, afl->cycles_wo_finds, afl->expand_havoc,
- afl->queued_items);
+ {
+
+ u64 cur_time = get_cur_time();
+ fprintf(afl->introspection_file,
+ "CYCLE cycle=%llu cycle_wo_finds=%llu time_wo_finds=%llu "
+ "expand_havoc=%u queue=%u\n",
+ afl->queue_cycle, afl->cycles_wo_finds,
+ afl->longest_find_time > cur_time - afl->last_find_time
+ ? afl->longest_find_time / 1000
+ : ((afl->start_time == 0 || afl->last_find_time == 0)
+ ? 0
+ : (cur_time - afl->last_find_time) / 1000),
+ afl->expand_havoc, afl->queued_items);
+
+ }
+
#endif
if (afl->cycle_schedules) {
@@ -2479,27 +2620,70 @@ int main(int argc, char **argv_orig, char **envp) {
}
- afl->current_entry = select_next_queue_entry(afl);
+ do {
+
+ afl->current_entry = select_next_queue_entry(afl);
+
+ } while (unlikely(afl->current_entry >= afl->queued_items));
+
afl->queue_cur = afl->queue_buf[afl->current_entry];
}
skipped_fuzz = fuzz_one(afl);
+ #ifdef INTROSPECTION
+ ++afl->queue_cur->stats_selected;
+
+ if (unlikely(skipped_fuzz)) {
+
+ ++afl->queue_cur->stats_skipped;
+
+ } else {
+
+ if (unlikely(afl->queued_items > prev_queued_items)) {
+
+ afl->queue_cur->stats_finds += afl->queued_items - prev_queued_items;
+ prev_queued_items = afl->queued_items;
+
+ }
+
+ if (unlikely(afl->saved_crashes > prev_saved_crashes)) {
+
+ afl->queue_cur->stats_crashes +=
+ afl->saved_crashes - prev_saved_crashes;
+ prev_saved_crashes = afl->saved_crashes;
+
+ }
+
+ if (unlikely(afl->saved_tmouts > prev_saved_tmouts)) {
+
+ afl->queue_cur->stats_tmouts += afl->saved_tmouts - prev_saved_tmouts;
+ prev_saved_tmouts = afl->saved_tmouts;
+
+ }
+
+ }
+
+ #endif
if (unlikely(!afl->stop_soon && exit_1)) { afl->stop_soon = 2; }
if (unlikely(afl->old_seed_selection)) {
while (++afl->current_entry < afl->queued_items &&
- afl->queue_buf[afl->current_entry]->disabled)
- ;
+ afl->queue_buf[afl->current_entry]->disabled) {};
if (unlikely(afl->current_entry >= afl->queued_items ||
afl->queue_buf[afl->current_entry] == NULL ||
- afl->queue_buf[afl->current_entry]->disabled))
+ afl->queue_buf[afl->current_entry]->disabled)) {
+
afl->queue_cur = NULL;
- else
+
+ } else {
+
afl->queue_cur = afl->queue_buf[afl->current_entry];
+ }
+
}
} while (skipped_fuzz && afl->queue_cur && !afl->stop_soon);
@@ -2511,7 +2695,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (unlikely(afl->is_main_node)) {
if (unlikely(get_cur_time() >
- (SYNC_TIME >> 1) + afl->last_sync_time)) {
+ (afl->sync_time >> 1) + afl->last_sync_time)) {
if (!(sync_interval_cnt++ % (SYNC_INTERVAL / 3))) {
@@ -2523,7 +2707,7 @@ int main(int argc, char **argv_orig, char **envp) {
} else {
- if (unlikely(get_cur_time() > SYNC_TIME + afl->last_sync_time)) {
+ if (unlikely(get_cur_time() > afl->sync_time + afl->last_sync_time)) {
if (!(sync_interval_cnt++ % SYNC_INTERVAL)) { sync_fuzzers(afl); }
@@ -2544,11 +2728,12 @@ int main(int argc, char **argv_orig, char **envp) {
stop_fuzzing:
afl->force_ui_update = 1; // ensure the screen is reprinted
+ afl->stop_soon = 1; // ensure everything is written
show_stats(afl); // print the screen one last time
write_bitmap(afl);
save_auto(afl);
- if (afl->afl_env.afl_pizza_mode) {
+ if (afl->pizza_is_served) {
SAYF(CURSOR_SHOW cLRD "\n\n+++ Baking aborted %s +++\n" cRST,
afl->stop_soon == 2 ? "programmatically" : "by the chef");
diff --git a/src/afl-gotcpu.c b/src/afl-gotcpu.c
index 539206ce..4f851099 100644
--- a/src/afl-gotcpu.c
+++ b/src/afl-gotcpu.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -19,7 +19,8 @@
This tool provides a fairly accurate measurement of CPU preemption rate.
It is meant to complement the quick-and-dirty load average widget shown
- in the afl-fuzz UI. See docs/parallel_fuzzing.md for more info.
+ in the afl-fuzz UI. See docs/fuzzing_in_depth.md#c-using-multiple-cores
+ for more info.
For some work loads, the tool may actually suggest running more instances
than you have CPU cores. This can happen if the tested program is spending
@@ -91,7 +92,7 @@ static u32 measure_preemption(u32 target_ms) {
volatile u32 v1, v2 = 0;
u64 st_t, en_t, st_c, en_c, real_delta, slice_delta;
- s32 loop_repeats = 0;
+ // s32 loop_repeats = 0;
st_t = get_cur_time_us();
st_c = get_cpu_usage_us();
@@ -112,7 +113,7 @@ repeat_loop:
if (en_t - st_t < target_ms * 1000) {
- loop_repeats++;
+ // loop_repeats++;
goto repeat_loop;
}
@@ -173,7 +174,12 @@ int main(int argc, char **argv) {
if (c == NULL) PFATAL("cpuset_create failed");
cpuset_set(i, c);
- #elif defined(__APPLE__)
+ #elif defined(__APPLE__) && defined(__x86_64__)
+ // the api is not workable on arm64, core's principle
+ // differs significantly hive of core per type vs individual ones.
+ // Possible TODO: For arm64 is to slightly change the meaning
+ // of gotcpu since it makes no sense on this platform
+ // but rather just displaying current policy ?
thread_affinity_policy_data_t c = {i};
thread_port_t native_thread = pthread_mach_thread_np(pthread_self());
if (thread_policy_set(native_thread, THREAD_AFFINITY_POLICY,
@@ -208,7 +214,13 @@ int main(int argc, char **argv) {
#if defined(__linux__)
if (sched_setaffinity(0, sizeof(c), &c)) {
- PFATAL("sched_setaffinity failed for cpu %d", i);
+ const char *error_code = "Unkown error code";
+ if (errno == EFAULT) error_code = "EFAULT";
+ if (errno == EINVAL) error_code = "EINVAL";
+ if (errno == EPERM) error_code = "EPERM";
+ if (errno == ESRCH) error_code = "ESRCH";
+
+ PFATAL("sched_setaffinity failed for cpu %d, error: %s", i, error_code);
}
diff --git a/src/afl-ld-lto.c b/src/afl-ld-lto.c
index 5797def8..420dd817 100644
--- a/src/afl-ld-lto.c
+++ b/src/afl-ld-lto.c
@@ -2,14 +2,14 @@
american fuzzy lop++ - wrapper for llvm 11+ lld
-----------------------------------------------
- Written by Marc Heuse <mh@mh-sec.de> for afl++
+ Written by Marc Heuse <mh@mh-sec.de> for AFL++
Maintained by Marc Heuse <mh@mh-sec.de>,
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>
Andrea Fioraldi <andreafioraldi@gmail.com>
Dominik Maier <domenukk@gmail.com>
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -210,7 +210,7 @@ static void edit_params(int argc, char **argv) {
if (strcmp(argv[i], "--afl") == 0) {
- if (!be_quiet) OKF("afl++ test command line flag detected, exiting.");
+ if (!be_quiet) OKF("AFL++ test command line flag detected, exiting.");
exit(0);
}
diff --git a/src/afl-sharedmem.c b/src/afl-sharedmem.c
index b48c6fb3..a2c81586 100644
--- a/src/afl-sharedmem.c
+++ b/src/afl-sharedmem.c
@@ -11,7 +11,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
diff --git a/src/afl-showmap.c b/src/afl-showmap.c
index 3fdbe8fe..9c029035 100644
--- a/src/afl-showmap.c
+++ b/src/afl-showmap.c
@@ -12,7 +12,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -30,8 +30,10 @@
*/
#define AFL_MAIN
+#define AFL_SHOWMAP
#include "config.h"
+#include "afl-fuzz.h"
#include "types.h"
#include "debug.h"
#include "alloc-inl.h"
@@ -62,10 +64,14 @@
#include <sys/types.h>
#include <sys/resource.h>
+static afl_state_t *afl;
+
static char *stdin_file; /* stdin file */
static u8 *in_dir = NULL, /* input folder */
- *out_file = NULL, *at_file = NULL; /* Substitution string for @@ */
+ *out_file = NULL, /* output file or directory */
+ *at_file = NULL, /* Substitution string for @@ */
+ *in_filelist = NULL; /* input file list */
static u8 outfile[PATH_MAX];
@@ -98,7 +104,7 @@ static volatile u8 stop_soon, /* Ctrl-C pressed? */
static sharedmem_t shm;
static afl_forkserver_t *fsrv;
-static sharedmem_t * shm_fuzz;
+static sharedmem_t *shm_fuzz;
/* Classify tuple counts. Instead of mapping to individual bits, as in
afl-fuzz.c, we map to more user-friendly numbers between 1 and 8. */
@@ -129,16 +135,48 @@ static void kill_child() {
timed_out = 1;
if (fsrv->child_pid > 0) {
- kill(fsrv->child_pid, fsrv->kill_signal);
+ kill(fsrv->child_pid, fsrv->child_kill_signal);
fsrv->child_pid = -1;
}
}
-static void classify_counts(afl_forkserver_t *fsrv) {
+/* dummy functions */
+u32 write_to_testcase(afl_state_t *afl, void **mem, u32 a, u32 b) {
+
+ (void)afl;
+ (void)mem;
+ return a + b;
+
+}
+
+void show_stats(afl_state_t *afl) {
+
+ (void)afl;
+
+}
+
+void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) {
- u8 * mem = fsrv->trace_bits;
+ (void)afl;
+ (void)q;
+
+}
+
+fsrv_run_result_t fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv,
+ u32 i) {
+
+ (void)afl;
+ (void)fsrv;
+ (void)i;
+ return 0;
+
+}
+
+void classify_counts(afl_forkserver_t *fsrv) {
+
+ u8 *mem = fsrv->trace_bits;
const u8 *map = binary_mode ? count_class_binary : count_class_human;
u32 i = map_size;
@@ -166,7 +204,7 @@ static void classify_counts(afl_forkserver_t *fsrv) {
}
static sharedmem_t *deinit_shmem(afl_forkserver_t *fsrv,
- sharedmem_t * shm_fuzz) {
+ sharedmem_t *shm_fuzz) {
afl_shm_deinit(shm_fuzz);
fsrv->support_shmem_fuzz = 0;
@@ -308,12 +346,73 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
}
+void pre_afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *mem, u32 len) {
+
+ static u8 buf[MAX_FILE];
+ u32 sent = 0;
+
+ if (unlikely(afl->custom_mutators_count)) {
+
+ ssize_t new_size = len;
+ u8 *new_mem = mem;
+ u8 *new_buf = NULL;
+
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (el->afl_custom_post_process) {
+
+ new_size =
+ el->afl_custom_post_process(el->data, new_mem, new_size, &new_buf);
+
+ if (unlikely(!new_buf || new_size <= 0)) {
+
+ return;
+
+ } else {
+
+ new_mem = new_buf;
+ len = new_size;
+
+ }
+
+ }
+
+ });
+
+ if (new_mem != mem && new_mem != NULL) {
+
+ mem = buf;
+ memcpy(mem, new_mem, new_size);
+
+ }
+
+ if (unlikely(afl->custom_mutators_count)) {
+
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (el->afl_custom_fuzz_send) {
+
+ el->afl_custom_fuzz_send(el->data, mem, len);
+ sent = 1;
+
+ }
+
+ });
+
+ }
+
+ }
+
+ if (likely(!sent)) { afl_fsrv_write_to_testcase(fsrv, mem, len); }
+
+}
+
/* Execute target application. */
static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem,
u32 len) {
- afl_fsrv_write_to_testcase(fsrv, mem, len);
+ pre_afl_fsrv_write_to_testcase(fsrv, mem, len);
if (!quiet_mode) { SAYF("-- Program output begins --\n" cRST); }
@@ -434,6 +533,23 @@ static u32 read_file(u8 *in_file) {
}
+#ifdef __linux__
+/* Execute the target application with an empty input (in Nyx mode). */
+static void showmap_run_target_nyx_mode(afl_forkserver_t *fsrv) {
+
+ afl_fsrv_write_to_testcase(fsrv, NULL, 0);
+
+ if (afl_fsrv_run_target(fsrv, fsrv->exec_tmout, &stop_soon) ==
+ FSRV_RUN_ERROR) {
+
+ FATAL("Error running target in Nyx mode");
+
+ }
+
+}
+
+#endif
+
/* Execute target application. */
static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) {
@@ -515,11 +631,11 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) {
it.it_value.tv_sec = (fsrv->exec_tmout / 1000);
it.it_value.tv_usec = (fsrv->exec_tmout % 1000) * 1000;
- }
+ signal(SIGALRM, kill_child);
- signal(SIGALRM, kill_child);
+ setitimer(ITIMER_REAL, &it, NULL);
- setitimer(ITIMER_REAL, &it, NULL);
+ }
if (waitpid(fsrv->child_pid, &status, 0) <= 0) { FATAL("waitpid() failed"); }
@@ -597,49 +713,8 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
char *afl_preload;
char *frida_afl_preload = NULL;
- setenv("ASAN_OPTIONS",
- "abort_on_error=1:"
- "detect_leaks=0:"
- "allocator_may_return_null=1:"
- "symbolize=0:"
- "detect_odr_violation=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0",
- 0);
-
- setenv("LSAN_OPTIONS",
- "exitcode=" STRINGIFY(LSAN_ERROR) ":"
- "fast_unwind_on_malloc=0:"
- "symbolize=0:"
- "print_suppressions=0",
- 0);
-
- setenv("UBSAN_OPTIONS",
- "halt_on_error=1:"
- "abort_on_error=1:"
- "malloc_context_size=0:"
- "allocator_may_return_null=1:"
- "symbolize=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0",
- 0);
-
- setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
- "abort_on_error=1:"
- "msan_track_origins=0"
- "allocator_may_return_null=1:"
- "symbolize=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0", 0);
+
+ set_sanitizer_defaults();
if (get_afl_env("AFL_PRELOAD")) {
@@ -695,7 +770,11 @@ static void setup_signal_handlers(void) {
struct sigaction sa;
sa.sa_handler = NULL;
+#ifdef SA_RESTART
sa.sa_flags = SA_RESTART;
+#else
+ sa.sa_flags = 0;
+#endif
sa.sa_sigaction = NULL;
sigemptyset(&sa.sa_mask);
@@ -785,6 +864,8 @@ u32 execute_testcases(u8 *dir) {
ck_free(in_data);
++done;
+ if (child_crashed && debug) { WARNF("crashed: %s", fn2); }
+
if (collect_coverage)
analyze_results(fsrv);
else
@@ -799,6 +880,103 @@ u32 execute_testcases(u8 *dir) {
}
+u32 execute_testcases_filelist(u8 *fn) {
+
+ u32 done = 0;
+ u8 buf[4096];
+ u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX];
+ FILE *f;
+
+ if (!be_quiet) { ACTF("Reading from '%s'...", fn); }
+
+ if ((f = fopen(fn, "r")) == NULL) { FATAL("could not open '%s'", fn); }
+
+ while (fgets(buf, sizeof(buf), f) != NULL) {
+
+ struct stat st;
+ u8 *fn2 = buf, *fn3;
+
+ while (*fn2 == ' ') {
+
+ ++fn2;
+
+ }
+
+ while (*fn2 &&
+ (fn2[strlen(fn2) - 1] == '\r' || fn2[strlen(fn2) - 1] == '\n' ||
+ fn2[strlen(fn2) - 1] == ' ')) {
+
+ fn2[strlen(fn2) - 1] = 0;
+
+ }
+
+ if (debug) { printf("Getting coverage for '%s'\n", fn2); }
+
+ if (!*fn2) { continue; }
+
+ if (lstat(fn2, &st) || access(fn2, R_OK)) {
+
+ WARNF("Unable to access '%s'", fn2);
+ continue;
+
+ }
+
+ ++done;
+
+ if (!S_ISREG(st.st_mode) || !st.st_size) { continue; }
+
+ if ((fn3 = strrchr(fn2, '/'))) {
+
+ ++fn3;
+
+ } else {
+
+ fn3 = fn2;
+
+ }
+
+ if (st.st_size > MAX_FILE && !be_quiet && !quiet_mode) {
+
+ WARNF("Test case '%s' is too big (%s, limit is %s), partial reading", fn2,
+ stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size),
+ stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE));
+
+ }
+
+ if (!collect_coverage) {
+
+ snprintf(outfile, sizeof(outfile), "%s/%s", out_file, fn3);
+
+ }
+
+ if (read_file(fn2)) {
+
+ if (wait_for_gdb) {
+
+ fprintf(stderr, "exec: gdb -p %d\n", fsrv->child_pid);
+ fprintf(stderr, "exec: kill -CONT %d\n", getpid());
+ kill(0, SIGSTOP);
+
+ }
+
+ showmap_run_target_forkserver(fsrv, in_data, in_len);
+ ck_free(in_data);
+
+ if (child_crashed && debug) { WARNF("crashed: %s", fn2); }
+
+ if (collect_coverage)
+ analyze_results(fsrv);
+ else
+ tcnt = write_results_to_file(fsrv, outfile);
+
+ }
+
+ }
+
+ return done;
+
+}
+
/* Show banner. */
static void show_banner(void) {
@@ -820,8 +998,8 @@ static void usage(u8 *argv0) {
" -o file - file to write the trace data to\n\n"
"Execution control settings:\n"
- " -t msec - timeout for each run (none)\n"
- " -m megs - memory limit for child process (%u MB)\n"
+ " -t msec - timeout for each run (default: 1000ms)\n"
+ " -m megs - memory limit for child process (default: none)\n"
#if defined(__linux__) && defined(__aarch64__)
" -A - use binary-only instrumentation (ARM CoreSight mode)\n"
#endif
@@ -832,6 +1010,7 @@ static void usage(u8 *argv0) {
" -W - use qemu-based instrumentation with Wine (Wine mode)\n"
" (Not necessary, here for consistency with other afl-* "
"tools)\n"
+ " -X - use Nyx mode\n"
#endif
"\n"
"Other settings:\n"
@@ -840,6 +1019,7 @@ static void usage(u8 *argv0) {
" With -C, -o is a file, without -C it must be a "
"directory\n"
" and each bitmap will be written there individually.\n"
+ " -I filelist - alternatively to -i, -I is a list of files\n"
" -C - collect coverage, writes all edges to -o and gives a "
"summary\n"
" Must be combined with -i.\n"
@@ -852,6 +1032,10 @@ static void usage(u8 *argv0) {
"This tool displays raw tuple data captured by AFL instrumentation.\n"
"For additional help, consult %s/README.md.\n\n"
+ "If you use -i/-I mode, then custom mutator post_process send send "
+ "functionality\n"
+ "is supported.\n\n"
+
"Environment variables used:\n"
"LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n"
"AFL_CMIN_CRASHES_ONLY: (cmin_mode) only write tuples for crashing "
@@ -863,15 +1047,22 @@ static void usage(u8 *argv0) {
"AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during "
"startup (in milliseconds)\n"
"AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, "
- "etc. (default: SIGKILL)\n"
+ "etc.\n"
+ " (default: SIGKILL)\n"
+ "AFL_FORK_SERVER_KILL_SIGNAL: Kill signal for the fork server on "
+ "termination\n"
+ " (default: SIGTERM). If unset and "
+ "AFL_KILL_SIGNAL is\n"
+ " set, that value will be used.\n"
"AFL_MAP_SIZE: the shared memory size for that target. must be >= the "
- "size the target was compiled for\n"
+ "size the\n"
+ " target was compiled for\n"
"AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
- "AFL_PRINT_FILENAMES: If set, the filename currently processed will be "
- "printed to stdout\n"
+ "AFL_PRINT_FILENAMES: Print the queue entry currently processed will to "
+ "stdout\n"
"AFL_QUIET: do not print extra informational output\n"
"AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n",
- argv0, MEM_LIMIT, doc_path);
+ argv0, doc_path);
exit(1);
@@ -903,7 +1094,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (getenv("AFL_QUIET") != NULL) { be_quiet = true; }
- while ((opt = getopt(argc, argv, "+i:o:f:m:t:AeqCZOH:QUWbcrsh")) > 0) {
+ while ((opt = getopt(argc, argv, "+i:I:o:f:m:t:AeqCZOH:QUWbcrshXY")) > 0) {
switch (opt) {
@@ -921,6 +1112,11 @@ int main(int argc, char **argv_orig, char **envp) {
in_dir = optarg;
break;
+ case 'I':
+ if (in_filelist) { FATAL("Multiple -I options not supported"); }
+ in_filelist = optarg;
+ break;
+
case 'o':
if (out_file) { FATAL("Multiple -o options not supported"); }
@@ -1007,6 +1203,16 @@ int main(int argc, char **argv_orig, char **envp) {
}
+ } else {
+
+ // The forkserver code does not have a way to completely
+ // disable the timeout, so we'll use a very, very long
+ // timeout instead.
+ WARNF(
+ "Setting an execution timeout of 120 seconds ('none' is not "
+ "allowed).");
+ fsrv->exec_tmout = 120 * 1000;
+
}
break;
@@ -1081,6 +1287,23 @@ int main(int argc, char **argv_orig, char **envp) {
break;
+ case 'Y': // fallthrough
+#ifdef __linux__
+ case 'X': /* NYX mode */
+
+ if (fsrv->nyx_mode) { FATAL("Multiple -X options not supported"); }
+
+ fsrv->nyx_mode = 1;
+ fsrv->nyx_parent = true;
+ fsrv->nyx_standalone = true;
+
+ break;
+#else
+ case 'X':
+ FATAL("Nyx mode is only availabe on linux...");
+ break;
+#endif
+
case 'b':
/* Secret undocumented mode. Writes output in raw binary format
@@ -1116,10 +1339,12 @@ int main(int argc, char **argv_orig, char **envp) {
if (optind == argc || !out_file) { usage(argv[0]); }
- if (in_dir) {
+ if (in_dir && in_filelist) { FATAL("you can only specify either -i or -I"); }
+
+ if (in_dir || in_filelist) {
if (!out_file && !collect_coverage)
- FATAL("for -i you need to specify either -C and/or -o");
+ FATAL("for -i/-I you need to specify either -C and/or -o");
}
@@ -1152,7 +1377,21 @@ int main(int argc, char **argv_orig, char **envp) {
set_up_environment(fsrv, argv);
+#ifdef __linux__
+ if (!fsrv->nyx_mode) {
+
+ fsrv->target_path = find_binary(argv[optind]);
+
+ } else {
+
+ fsrv->target_path = ck_strdup(argv[optind]);
+
+ }
+
+#else
fsrv->target_path = find_binary(argv[optind]);
+#endif
+
fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
if (!quiet_mode) {
@@ -1162,7 +1401,7 @@ int main(int argc, char **argv_orig, char **envp) {
}
- if (in_dir) {
+ if (in_dir || in_filelist) {
/* If we don't have a file name chosen yet, use a safe default. */
u8 *use_dir = ".";
@@ -1182,6 +1421,14 @@ int main(int argc, char **argv_orig, char **envp) {
// If @@ are in the target args, replace them and also set use_stdin=false.
detect_file_args(argv + optind, stdin_file, &fsrv->use_stdin);
+ fsrv->dev_null_fd = open("/dev/null", O_RDWR);
+ if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
+
+ fsrv->out_file = stdin_file;
+ fsrv->out_fd =
+ open(stdin_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+ if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", stdin_file); }
+
} else {
// If @@ are in the target args, replace them and also set use_stdin=false.
@@ -1208,13 +1455,75 @@ int main(int argc, char **argv_orig, char **envp) {
use_argv =
get_cs_argv(argv[0], &fsrv->target_path, argc - optind, argv + optind);
+#ifdef __linux__
+
+ } else if (fsrv->nyx_mode) {
+
+ use_argv = ck_alloc(sizeof(char *) * (1));
+ use_argv[0] = argv[0];
+
+ fsrv->nyx_id = 0;
+
+ u8 *libnyx_binary = find_afl_binary(use_argv[0], "libnyx.so");
+ fsrv->nyx_handlers = afl_load_libnyx_plugin(libnyx_binary);
+ if (fsrv->nyx_handlers == NULL) {
+
+ FATAL("failed to initialize libnyx.so...");
+
+ }
+
+ fsrv->nyx_use_tmp_workdir = true;
+ fsrv->nyx_bind_cpu_id = 0;
+#endif
+
} else {
use_argv = argv + optind;
}
+ afl = calloc(1, sizeof(afl_state_t));
+
+ if (getenv("AFL_FORKSRV_INIT_TMOUT")) {
+
+ s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT"));
+ if (forksrv_init_tmout < 1) {
+
+ FATAL("Bad value specified for AFL_FORKSRV_INIT_TMOUT");
+
+ }
+
+ fsrv->init_tmout = (u32)forksrv_init_tmout;
+
+ }
+
+ if (getenv("AFL_CRASH_EXITCODE")) {
+
+ long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10);
+ if ((!exitcode && (errno == EINVAL || errno == ERANGE)) ||
+ exitcode < -127 || exitcode > 128) {
+
+ FATAL("Invalid crash exitcode, expected -127 to 128, but got %s",
+ getenv("AFL_CRASH_EXITCODE"));
+
+ }
+
+ fsrv->uses_crash_exitcode = true;
+ // WEXITSTATUS is 8 bit unsigned
+ fsrv->crash_exitcode = (u8)exitcode;
+
+ }
+
+#ifdef __linux__
+ if (!fsrv->nyx_mode && (in_dir || in_filelist)) {
+
+ (void)check_binary_signatures(fsrv->target_path);
+
+ }
+
+#else
if (in_dir) { (void)check_binary_signatures(fsrv->target_path); }
+#endif
shm_fuzz = ck_alloc(sizeof(sharedmem_t));
@@ -1234,11 +1543,29 @@ int main(int argc, char **argv_orig, char **envp) {
fsrv->shmem_fuzz_len = (u32 *)map;
fsrv->shmem_fuzz = map + sizeof(u32);
+ configure_afl_kill_signals(fsrv, NULL, NULL,
+ (fsrv->qemu_mode || unicorn_mode
+#ifdef __linux__
+ || fsrv->nyx_mode
+#endif
+ )
+ ? SIGKILL
+ : SIGTERM);
+
if (!fsrv->cs_mode && !fsrv->qemu_mode && !unicorn_mode) {
u32 save_be_quiet = be_quiet;
be_quiet = !debug;
- fsrv->map_size = 4194304; // dummy temporary value
+ if (map_size > 4194304) {
+
+ fsrv->map_size = map_size;
+
+ } else {
+
+ fsrv->map_size = 4194304; // dummy temporary value
+
+ }
+
u32 new_map_size =
afl_fsrv_get_mapsize(fsrv, use_argv, &stop_soon,
(get_afl_env("AFL_DEBUG_CHILD") ||
@@ -1247,9 +1574,6 @@ int main(int argc, char **argv_orig, char **envp) {
: 0);
be_quiet = save_be_quiet;
- fsrv->kill_signal =
- parse_afl_kill_signal_env(getenv("AFL_KILL_SIGNAL"), SIGKILL);
-
if (new_map_size) {
// only reinitialize when it makes sense
@@ -1257,7 +1581,7 @@ int main(int argc, char **argv_orig, char **envp) {
(new_map_size > map_size && new_map_size - map_size > MAP_SIZE)) {
if (!be_quiet)
- ACTF("Aquired new map size for target: %u bytes\n", new_map_size);
+ ACTF("Acquired new map size for target: %u bytes\n", new_map_size);
afl_shm_deinit(&shm);
afl_fsrv_kill(fsrv);
@@ -1272,28 +1596,66 @@ int main(int argc, char **argv_orig, char **envp) {
fsrv->map_size = map_size;
+ } else {
+
+ afl_fsrv_start(fsrv, use_argv, &stop_soon,
+ (get_afl_env("AFL_DEBUG_CHILD") ||
+ get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
+ ? 1
+ : 0);
+
}
- if (in_dir) {
+ if (in_dir || in_filelist) {
+
+ afl->fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY);
+ afl->afl_env.afl_custom_mutator_library =
+ getenv("AFL_CUSTOM_MUTATOR_LIBRARY");
+ afl->afl_env.afl_python_module = getenv("AFL_PYTHON_MODULE");
+ setup_custom_mutators(afl);
+
+ } else {
+
+ if (getenv("AFL_CUSTOM_MUTATOR_LIBRARY") || getenv("AFL_PYTHON_MODULE")) {
+
+ WARNF(
+ "Custom mutator environment detected, this is only supported in "
+ "-i/-I mode!\n");
+
+ }
+
+ }
+
+ if (in_dir || in_filelist) {
DIR *dir_in, *dir_out = NULL;
+ u8 *dn = NULL;
if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = true;
- fsrv->dev_null_fd = open("/dev/null", O_RDWR);
- if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
+ if (in_filelist) {
- // if a queue subdirectory exists switch to that
- u8 *dn = alloc_printf("%s/queue", in_dir);
- if ((dir_in = opendir(dn)) != NULL) {
+ if (!be_quiet) ACTF("Reading from file list '%s'...", in_filelist);
+
+ } else {
- closedir(dir_in);
- in_dir = dn;
+ // if a queue subdirectory exists switch to that
+ dn = alloc_printf("%s/queue", in_dir);
- } else
+ if ((dir_in = opendir(dn)) != NULL) {
- ck_free(dn);
- if (!be_quiet) ACTF("Reading from directory '%s'...", in_dir);
+ closedir(dir_in);
+ in_dir = dn;
+
+ } else {
+
+ ck_free(dn);
+
+ }
+
+ if (!be_quiet) ACTF("Reading from directory '%s'...", in_dir);
+
+ }
if (!collect_coverage) {
@@ -1317,10 +1679,6 @@ int main(int argc, char **argv_orig, char **envp) {
}
atexit(at_exit_handler);
- fsrv->out_file = stdin_file;
- fsrv->out_fd =
- open(stdin_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
- if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); }
if (get_afl_env("AFL_DEBUG")) {
@@ -1336,50 +1694,26 @@ int main(int argc, char **argv_orig, char **envp) {
}
- if (getenv("AFL_FORKSRV_INIT_TMOUT")) {
-
- s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT"));
- if (forksrv_init_tmout < 1) {
-
- FATAL("Bad value specified for AFL_FORKSRV_INIT_TMOUT");
-
- }
-
- fsrv->init_tmout = (u32)forksrv_init_tmout;
+ map_size = fsrv->map_size;
- }
+ if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz)
+ shm_fuzz = deinit_shmem(fsrv, shm_fuzz);
- if (getenv("AFL_CRASH_EXITCODE")) {
+ if (in_dir) {
- long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10);
- if ((!exitcode && (errno == EINVAL || errno == ERANGE)) ||
- exitcode < -127 || exitcode > 128) {
+ if (execute_testcases(in_dir) == 0) {
- FATAL("Invalid crash exitcode, expected -127 to 128, but got %s",
- getenv("AFL_CRASH_EXITCODE"));
+ FATAL("could not read input testcases from %s", in_dir);
}
- fsrv->uses_crash_exitcode = true;
- // WEXITSTATUS is 8 bit unsigned
- fsrv->crash_exitcode = (u8)exitcode;
-
- }
-
- afl_fsrv_start(fsrv, use_argv, &stop_soon,
- (get_afl_env("AFL_DEBUG_CHILD") ||
- get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
- ? 1
- : 0);
+ } else {
- map_size = fsrv->map_size;
+ if (execute_testcases_filelist(in_filelist) == 0) {
- if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz)
- shm_fuzz = deinit_shmem(fsrv, shm_fuzz);
-
- if (execute_testcases(in_dir) == 0) {
+ FATAL("could not read input testcases from %s", in_filelist);
- FATAL("could not read input testcases from %s", in_dir);
+ }
}
@@ -1399,7 +1733,20 @@ int main(int argc, char **argv_orig, char **envp) {
if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz)
shm_fuzz = deinit_shmem(fsrv, shm_fuzz);
- showmap_run_target(fsrv, use_argv);
+#ifdef __linux__
+ if (!fsrv->nyx_mode) {
+
+#endif
+ showmap_run_target(fsrv, use_argv);
+#ifdef __linux__
+
+ } else {
+
+ showmap_run_target_nyx_mode(fsrv);
+
+ }
+
+#endif
tcnt = write_results_to_file(fsrv, out_file);
if (!quiet_mode) {
diff --git a/src/afl-tmin.c b/src/afl-tmin.c
index 1bf4af38..e7442d1d 100644
--- a/src/afl-tmin.c
+++ b/src/afl-tmin.c
@@ -12,7 +12,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -86,7 +86,7 @@ static volatile u8 stop_soon; /* Ctrl-C pressed? */
static afl_forkserver_t *fsrv;
static sharedmem_t shm;
-static sharedmem_t * shm_fuzz;
+static sharedmem_t *shm_fuzz;
/*
* forkserver section
@@ -113,7 +113,7 @@ static void kill_child() {
if (fsrv->child_pid > 0) {
- kill(fsrv->child_pid, fsrv->kill_signal);
+ kill(fsrv->child_pid, fsrv->child_kill_signal);
fsrv->child_pid = -1;
}
@@ -121,7 +121,7 @@ static void kill_child() {
}
static sharedmem_t *deinit_shmem(afl_forkserver_t *fsrv,
- sharedmem_t * shm_fuzz) {
+ sharedmem_t *shm_fuzz) {
afl_shm_deinit(shm_fuzz);
fsrv->support_shmem_fuzz = 0;
@@ -642,7 +642,7 @@ 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;
@@ -674,27 +674,6 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
/* Set sane defaults... */
- x = get_afl_env("ASAN_OPTIONS");
-
- if (x) {
-
- if (!strstr(x, "abort_on_error=1")) {
-
- FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!");
-
- }
-
-#ifndef ASAN_BUILD
- if (!getenv("AFL_DEBUG") && !strstr(x, "symbolize=0")) {
-
- FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!");
-
- }
-
-#endif
-
- }
-
x = get_afl_env("MSAN_OPTIONS");
if (x) {
@@ -706,69 +685,9 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
}
- if (!strstr(x, "symbolize=0")) {
-
- FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!");
-
- }
-
}
- x = get_afl_env("LSAN_OPTIONS");
-
- if (x) {
-
- if (!strstr(x, "symbolize=0")) {
-
- FATAL("Custom LSAN_OPTIONS set without symbolize=0 - please fix!");
-
- }
-
- }
-
- setenv("ASAN_OPTIONS",
- "abort_on_error=1:"
- "detect_leaks=0:"
- "allocator_may_return_null=1:"
- "symbolize=0:"
- "detect_odr_violation=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0",
- 0);
-
- setenv("UBSAN_OPTIONS",
- "halt_on_error=1:"
- "abort_on_error=1:"
- "malloc_context_size=0:"
- "allocator_may_return_null=1:"
- "symbolize=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0",
- 0);
-
- setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
- "abort_on_error=1:"
- "msan_track_origins=0"
- "allocator_may_return_null=1:"
- "symbolize=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0", 0);
-
- setenv("LSAN_OPTIONS",
- "exitcode=" STRINGIFY(LSAN_ERROR) ":"
- "fast_unwind_on_malloc=0:"
- "symbolize=0:"
- "print_suppressions=0",
- 0);
+ set_sanitizer_defaults();
if (get_afl_env("AFL_PRELOAD")) {
@@ -824,7 +743,11 @@ static void setup_signal_handlers(void) {
struct sigaction sa;
sa.sa_handler = NULL;
+#ifdef SA_RESTART
sa.sa_flags = SA_RESTART;
+#else
+ sa.sa_flags = 0;
+#endif
sa.sa_sigaction = NULL;
sigemptyset(&sa.sa_mask);
@@ -866,6 +789,7 @@ static void usage(u8 *argv0) {
"mode)\n"
" (Not necessary, here for consistency with other afl-* "
"tools)\n"
+ " -X - use Nyx mode\n"
#endif
"\n"
@@ -879,8 +803,12 @@ static void usage(u8 *argv0) {
"Environment variables used:\n"
"AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n"
- "AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in milliseconds)\n"
- "AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc. (default: SIGKILL)\n"
+ "AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in ms)\n"
+ "AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc.\n"
+ " (default: SIGKILL)\n"
+ "AFL_FORK_SERVER_KILL_SIGNAL: Kill signal for the fork server on termination\n"
+ " (default: SIGTERM). If unset and AFL_KILL_SIGNAL is\n"
+ " set, that value will be used.\n"
"AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
" the target was compiled for\n"
"AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
@@ -918,7 +846,7 @@ int main(int argc, char **argv_orig, char **envp) {
SAYF(cCYA "afl-tmin" VERSION cRST " by Michal Zalewski\n");
- while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeAOQUWHh")) > 0) {
+ while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeAOQUWXYHh")) > 0) {
switch (opt) {
@@ -1076,6 +1004,23 @@ int main(int argc, char **argv_orig, char **envp) {
break;
+ case 'Y': // fallthough
+#ifdef __linux__
+ case 'X': /* NYX mode */
+
+ if (fsrv->nyx_mode) { FATAL("Multiple -X options not supported"); }
+
+ fsrv->nyx_mode = 1;
+ fsrv->nyx_parent = true;
+ fsrv->nyx_standalone = true;
+
+ break;
+#else
+ case 'X':
+ FATAL("Nyx mode is only availabe on linux...");
+ break;
+#endif
+
case 'H': /* Hang Mode */
/* Minimizes a testcase to the minimum that still times out */
@@ -1141,7 +1086,21 @@ int main(int argc, char **argv_orig, char **envp) {
set_up_environment(fsrv, argv);
+#ifdef __linux__
+ if (!fsrv->nyx_mode) {
+
+ fsrv->target_path = find_binary(argv[optind]);
+
+ } else {
+
+ fsrv->target_path = ck_strdup(argv[optind]);
+
+ }
+
+#else
fsrv->target_path = find_binary(argv[optind]);
+#endif
+
fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
detect_file_args(argv + optind, out_file, &fsrv->use_stdin);
signal(SIGALRM, kill_child);
@@ -1165,6 +1124,26 @@ int main(int argc, char **argv_orig, char **envp) {
use_argv =
get_cs_argv(argv[0], &fsrv->target_path, argc - optind, argv + optind);
+#ifdef __linux__
+
+ } else if (fsrv->nyx_mode) {
+
+ fsrv->nyx_id = 0;
+
+ u8 *libnyx_binary = find_afl_binary(argv[0], "libnyx.so");
+ fsrv->nyx_handlers = afl_load_libnyx_plugin(libnyx_binary);
+ if (fsrv->nyx_handlers == NULL) {
+
+ FATAL("failed to initialize libnyx.so...");
+
+ }
+
+ fsrv->nyx_use_tmp_workdir = true;
+ fsrv->nyx_bind_cpu_id = 0;
+
+ use_argv = argv + optind;
+#endif
+
} else {
use_argv = argv + optind;
@@ -1195,8 +1174,8 @@ int main(int argc, char **argv_orig, char **envp) {
}
- fsrv->kill_signal =
- parse_afl_kill_signal_env(getenv("AFL_KILL_SIGNAL"), SIGKILL);
+ configure_afl_kill_signals(
+ fsrv, NULL, NULL, (fsrv->qemu_mode || unicorn_mode) ? SIGKILL : SIGTERM);
if (getenv("AFL_CRASH_EXITCODE")) {
@@ -1234,7 +1213,12 @@ int main(int argc, char **argv_orig, char **envp) {
fsrv->shmem_fuzz = map + sizeof(u32);
read_initial_file();
+
+#ifdef __linux__
+ if (!fsrv->nyx_mode) { (void)check_binary_signatures(fsrv->target_path); }
+#else
(void)check_binary_signatures(fsrv->target_path);
+#endif
if (!fsrv->qemu_mode && !unicorn_mode) {
@@ -1252,7 +1236,7 @@ int main(int argc, char **argv_orig, char **envp) {
(new_map_size > map_size && new_map_size - map_size > MAP_SIZE)) {
if (!be_quiet)
- ACTF("Aquired new map size for target: %u bytes\n", new_map_size);
+ ACTF("Acquired new map size for target: %u bytes\n", new_map_size);
afl_shm_deinit(&shm);
afl_fsrv_kill(fsrv);
diff --git a/test-instr.c b/test-instr.c
index b2caa1fe..eda5189c 100644
--- a/test-instr.c
+++ b/test-instr.c
@@ -3,7 +3,7 @@
--------------------------------------------------------
Originally written by Michal Zalewski
Copyright 2014 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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:
@@ -24,7 +24,7 @@
int main(int argc, char **argv) {
- int fd = 0;
+ int fd = 0, cnt;
char buff[8];
char *buf = buff;
@@ -32,7 +32,6 @@ int main(int argc, char **argv) {
if (argc == 2) {
buf = argv[1];
- printf("Input %s - ", buf);
} else {
@@ -47,23 +46,36 @@ int main(int argc, char **argv) {
}
- if (read(fd, buf, sizeof(buf)) < 1) {
+ if ((cnt = read(fd, buf, sizeof(buf) - 1)) < 1) {
printf("Hum?\n");
return 1;
}
+ buf[cnt] = 0;
+
}
+ if (getenv("AFL_DEBUG")) fprintf(stderr, "test-instr: %s\n", buf);
+
// we support three input cases (plus a 4th if stdin is used but there is no
// input)
- if (buf[0] == '0')
- printf("Looks like a zero to me!\n");
- else if (buf[0] == '1')
- printf("Pretty sure that is a one!\n");
- else
- printf("Neither one or zero? How quaint!\n");
+ switch (buf[0]) {
+
+ case '0':
+ printf("Looks like a zero to me!\n");
+ break;
+
+ case '1':
+ printf("Pretty sure that is a one!\n");
+ break;
+
+ default:
+ printf("Neither one or zero? How quaint!\n");
+ break;
+
+ }
return 0;
diff --git a/test/test-all.sh b/test/test-all.sh
index 0c189727..3cb692ca 100755
--- a/test/test-all.sh
+++ b/test/test-all.sh
@@ -23,3 +23,5 @@
. ./test-unittests.sh
. ./test-post.sh
+
+exit 0 \ No newline at end of file
diff --git a/test/test-basic.sh b/test/test-basic.sh
index bec42b4d..5bb2ca28 100755
--- a/test/test-basic.sh
+++ b/test/test-basic.sh
@@ -7,9 +7,10 @@ AFL_GCC=afl-gcc
$ECHO "$BLUE[*] Testing: ${AFL_GCC}, afl-showmap, afl-fuzz, afl-cmin and afl-tmin"
test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "i386" && {
test -e ../${AFL_GCC} -a -e ../afl-showmap -a -e ../afl-fuzz && {
- ../${AFL_GCC} -o test-instr.plain -O0 ../test-instr.c > /dev/null 2>&1
- AFL_HARDEN=1 ../${AFL_GCC} -o test-compcov.harden test-compcov.c > /dev/null 2>&1
- test -e test-instr.plain && {
+ ../${AFL_GCC} -v 2>&1 | grep -qi "gcc version" && {
+ ../${AFL_GCC} -o test-instr.plain -O0 ../test-instr.c > /dev/null 2>&1
+ AFL_HARDEN=1 ../${AFL_GCC} -o test-compcov.harden test-compcov.c > /dev/null 2>&1
+ test -e test-instr.plain && {
$ECHO "$GREEN[+] ${AFL_GCC} compilation succeeded"
echo 0 | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.plain.0 -r -- ./test-instr.plain > /dev/null 2>&1
AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.plain.1 -r -- ./test-instr.plain < /dev/null > /dev/null 2>&1
@@ -35,41 +36,41 @@ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc
}
test "$TUPLES" -lt 3 && SKIP=1
true # this is needed because of the test above
- } || {
+ } || {
$ECHO "$RED[!] ${AFL_GCC} failed"
echo CUT------------------------------------------------------------------CUT
uname -a
../${AFL_GCC} -o test-instr.plain -O0 ../test-instr.c
echo CUT------------------------------------------------------------------CUT
CODE=1
- }
- test -e test-compcov.harden && {
+ }
+ test -e test-compcov.harden && {
nm test-compcov.harden | grep -Eq 'stack_chk_fail|fstack-protector-all|fortified' > /dev/null 2>&1 && {
$ECHO "$GREEN[+] ${AFL_GCC} hardened mode succeeded and is working"
} || {
$ECHO "$RED[!] ${AFL_GCC} hardened mode is not hardened"
- env | egrep 'AFL|PATH|LLVM'
+ env | grep -E 'AFL|PATH|LLVM'
AFL_DEBUG=1 AFL_HARDEN=1 ../${AFL_GCC} -o test-compcov.harden test-compcov.c
nm test-compcov.harden
CODE=1
}
rm -f test-compcov.harden
- } || {
+ } || {
$ECHO "$RED[!] ${AFL_GCC} hardened mode compilation failed"
CODE=1
- }
- # now we want to be sure that afl-fuzz is working
- # make sure crash reporter is disabled on Mac OS X
- (test "$(uname -s)" = "Darwin" && test $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') && {
+ }
+ # now we want to be sure that afl-fuzz is working
+ # make sure crash reporter is disabled on Mac OS X
+ (test "$(uname -s)" = "Darwin" && test $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') && {
$ECHO "$RED[!] we cannot run afl-fuzz with enabled crash reporter. Run 'sudo sh afl-system-config'.$RESET"
true
- }) || {
+ }) || {
mkdir -p in
echo 0 > in/in
test -z "$SKIP" && {
$ECHO "$GREY[*] running afl-fuzz for ${AFL_GCC}, this will take approx 10 seconds"
{
- ../afl-fuzz -V10 -m ${MEM_LIMIT} -i in -o out -D -- ./test-instr.plain >>errors 2>&1
+ ../afl-fuzz -V07 -m ${MEM_LIMIT} -i in -o out -- ./test-instr.plain >>errors 2>&1
} >>errors 2>&1
test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
$ECHO "$GREEN[+] afl-fuzz is working correctly with ${AFL_GCC}"
@@ -116,83 +117,89 @@ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc
}
rm -rf in out errors in2
unset AFL_QUIET
+ }
+ rm -f test-instr.plain
+ } || {
+ $ECHO "$YELLOW[-] afl-gcc executes clang, cannot test!"
+ INCOMPLETE=1
}
- rm -f test-instr.plain
} || {
- $ECHO "$YELLOW[-] afl is not compiled, cannot test"
- INCOMPLETE=1
+ $ECHO "$YELLOW[-] afl is not compiled, cannot test"
+ INCOMPLETE=1
}
- if [ ${AFL_GCC} = "afl-gcc" ] ; then AFL_GCC=afl-clang ; else AFL_GCC=afl-gcc ; fi
- $ECHO "$BLUE[*] Testing: ${AFL_GCC}, afl-showmap, afl-fuzz, afl-cmin and afl-tmin"
+
+ AFL_CLANG=afl-clang
+ $ECHO "$BLUE[*] Testing: ${AFL_CLANG}, afl-showmap, afl-fuzz, afl-cmin and afl-tmin"
SKIP=
- test -e ../${AFL_GCC} -a -e ../afl-showmap -a -e ../afl-fuzz && {
- ../${AFL_GCC} -o test-instr.plain -O0 ../test-instr.c > /dev/null 2>&1
- AFL_HARDEN=1 ../${AFL_GCC} -o test-compcov.harden test-compcov.c > /dev/null 2>&1
- test -e test-instr.plain && {
- $ECHO "$GREEN[+] ${AFL_GCC} compilation succeeded"
+ test -e ../${AFL_CLANG} -a -e ../afl-showmap -a -e ../afl-fuzz && {
+ ../${AFL_CLANG} -v 2>&1 | grep -qi "clang version" && {
+ ../${AFL_CLANG} -O0 -o test-instr.plain ../test-instr.c > /dev/null 2>&1
+ AFL_HARDEN=1 ../${AFL_CLANG} -o test-compcov.harden test-compcov.c > /dev/null 2>&1
+ test -e test-instr.plain && {
+ $ECHO "$GREEN[+] ${AFL_CLANG} compilation succeeded"
echo 0 | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.plain.0 -r -- ./test-instr.plain > /dev/null 2>&1
AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.plain.1 -r -- ./test-instr.plain < /dev/null > /dev/null 2>&1
test -e test-instr.plain.0 -a -e test-instr.plain.1 && {
diff test-instr.plain.0 test-instr.plain.1 > /dev/null 2>&1 && {
- $ECHO "$RED[!] ${AFL_GCC} instrumentation should be different on different input but is not"
+ $ECHO "$RED[!] ${AFL_CLANG} instrumentation should be different on different input but is not"
CODE=1
} || {
- $ECHO "$GREEN[+] ${AFL_GCC} instrumentation present and working correctly"
+ $ECHO "$GREEN[+] ${AFL_CLANG} instrumentation present and working correctly"
}
} || {
- $ECHO "$RED[!] ${AFL_GCC} instrumentation failed"
+ $ECHO "$RED[!] ${AFL_CLANG} instrumentation failed"
CODE=1
}
rm -f test-instr.plain.0 test-instr.plain.1
TUPLES=`echo 1|AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- ./test-instr.plain 2>&1 | grep Captur | awk '{print$3}'`
test "$TUPLES" -gt 1 -a "$TUPLES" -lt 12 && {
- $ECHO "$GREEN[+] ${AFL_GCC} run reported $TUPLES instrumented locations which is fine"
+ $ECHO "$GREEN[+] ${AFL_CLANG} run reported $TUPLES instrumented locations which is fine"
} || {
- $ECHO "$RED[!] ${AFL_GCC} instrumentation produces weird numbers: $TUPLES"
+ $ECHO "$RED[!] ${AFL_CLANG} instrumentation produces weird numbers: $TUPLES"
CODE=1
}
test "$TUPLES" -lt 3 && SKIP=1
true # this is needed because of the test above
- } || {
- $ECHO "$RED[!] ${AFL_GCC} failed"
+ } || {
+ $ECHO "$RED[!] ${AFL_CLANG} failed"
echo CUT------------------------------------------------------------------CUT
uname -a
- ../${AFL_GCC} -o test-instr.plain ../test-instr.c
+ ../${AFL_CLANG} -o test-instr.plain ../test-instr.c
echo CUT------------------------------------------------------------------CUT
CODE=1
- }
- test -e test-compcov.harden && {
+ }
+ test -e test-compcov.harden && {
nm test-compcov.harden | grep -Eq 'stack_chk_fail|fstack-protector-all|fortified' > /dev/null 2>&1 && {
- $ECHO "$GREEN[+] ${AFL_GCC} hardened mode succeeded and is working"
+ $ECHO "$GREEN[+] ${AFL_CLANG} hardened mode succeeded and is working"
} || {
- $ECHO "$RED[!] ${AFL_GCC} hardened mode is not hardened"
+ $ECHO "$RED[!] ${AFL_CLANG} hardened mode is not hardened"
CODE=1
}
rm -f test-compcov.harden
- } || {
- $ECHO "$RED[!] ${AFL_GCC} hardened mode compilation failed"
+ } || {
+ $ECHO "$RED[!] ${AFL_CLANG} hardened mode compilation failed"
CODE=1
- }
- # now we want to be sure that afl-fuzz is working
- # make sure crash reporter is disabled on Mac OS X
- (test "$(uname -s)" = "Darwin" && test $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') && {
+ }
+ # now we want to be sure that afl-fuzz is working
+ # make sure crash reporter is disabled on Mac OS X
+ (test "$(uname -s)" = "Darwin" && test $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') && {
$ECHO "$RED[!] we cannot run afl-fuzz with enabled crash reporter. Run 'sudo sh afl-system-config'.$RESET"
true
- }) || {
+ }) || {
mkdir -p in
echo 0 > in/in
test -z "$SKIP" && {
- $ECHO "$GREY[*] running afl-fuzz for ${AFL_GCC}, this will take approx 10 seconds"
+ $ECHO "$GREY[*] running afl-fuzz for ${AFL_CLANG}, this will take approx 10 seconds"
{
- ../afl-fuzz -V10 -m ${MEM_LIMIT} -i in -o out -D -- ./test-instr.plain >>errors 2>&1
+ ../afl-fuzz -V07 -m ${MEM_LIMIT} -i in -o out -- ./test-instr.plain >>errors 2>&1
} >>errors 2>&1
test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
- $ECHO "$GREEN[+] afl-fuzz is working correctly with ${AFL_GCC}"
+ $ECHO "$GREEN[+] afl-fuzz is working correctly with ${AFL_CLANG}"
} || {
echo CUT------------------------------------------------------------------CUT
cat errors
echo CUT------------------------------------------------------------------CUT
- $ECHO "$RED[!] afl-fuzz is not working correctly with ${AFL_GCC}"
+ $ECHO "$RED[!] afl-fuzz is not working correctly with ${AFL_CLANG}"
CODE=1
}
}
@@ -247,8 +254,12 @@ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc
}
rm -rf in out errors in2
unset AFL_QUIET
+ }
+ rm -f test-instr.plain
+ } || {
+ $ECHO "$YELLOW[-] afl-clang executes gcc, cannot test"
+ INCOMPLETE=1
}
- rm -f test-instr.plain
} || {
$ECHO "$YELLOW[-] afl is not compiled, cannot test"
INCOMPLETE=1
diff --git a/test/test-cmplog.c b/test/test-cmplog.c
index d724ecaf..2ab579b0 100644
--- a/test/test-cmplog.c
+++ b/test/test-cmplog.c
@@ -8,16 +8,14 @@
int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t i) {
- if (i < 30) return 0;
+ if (i < 15) return -1;
if (buf[0] != 'A') return 0;
if (buf[1] != 'B') return 0;
if (buf[2] != 'C') return 0;
if (buf[3] != 'D') return 0;
int *icmp = (int *)(buf + 4);
if (*icmp != 0x69694141) return 0;
- if (memcmp(buf + 8, "1234", 4) || memcmp(buf + 12, "EFGH", 4)) return 0;
- if (strncmp(buf + 16, "IJKL", 4) == 0 && strcmp(buf + 20, "DEADBEEF") == 0)
- abort();
+ if (memcmp(buf + 8, "1234EF", 6) == 0) abort();
return 0;
}
diff --git a/test/test-custom-mutators.sh b/test/test-custom-mutators.sh
index 5d679a82..49feedc0 100755
--- a/test/test-custom-mutators.sh
+++ b/test/test-custom-mutators.sh
@@ -3,84 +3,92 @@
. ./test-pre.sh
$ECHO "$BLUE[*] Testing: custom mutator"
-test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && {
- # normalize path
- CUSTOM_MUTATOR_PATH=$(cd $(pwd)/../custom_mutators/examples;pwd)
- test -e test-custom-mutator.c -a -e ${CUSTOM_MUTATOR_PATH}/example.c -a -e ${CUSTOM_MUTATOR_PATH}/example.py && {
- unset AFL_CC
- # Compile the vulnerable program for single mutator
- test -e ../afl-clang-fast && {
- ../afl-clang-fast -o test-custom-mutator test-custom-mutator.c > /dev/null 2>&1
+# normalize path
+CUSTOM_MUTATOR_PATH=$(cd $(pwd)/../custom_mutators/examples;pwd)
+test -e test-custom-mutator.c -a -e ${CUSTOM_MUTATOR_PATH}/example.c -a -e ${CUSTOM_MUTATOR_PATH}/example.py && {
+ unset AFL_CC
+ # Compile the vulnerable program for single mutator
+ test -e ../afl-clang-fast && {
+ ../afl-clang-fast -o test-custom-mutator test-custom-mutator.c > /dev/null 2>&1
+ } || {
+ test -e ../afl-gcc-fast && {
+ ../afl-gcc-fast -o test-custom-mutator test-custom-mutator.c > /dev/null 2>&1
} || {
- test -e ../afl-gcc-fast && {
- ../afl-gcc-fast -o test-custom-mutator test-custom-mutator.c > /dev/null 2>&1
- } || {
- ../afl-gcc -o test-custom-mutator test-custom-mutator.c > /dev/null 2>&1
- }
+ ../afl-gcc -o test-custom-mutator test-custom-mutator.c > /dev/null 2>&1
}
- # Compile the vulnerable program for multiple mutators
- test -e ../afl-clang-fast && {
- ../afl-clang-fast -o test-multiple-mutators test-multiple-mutators.c > /dev/null 2>&1
+ }
+ # Compile the vulnerable program for multiple mutators
+ test -e ../afl-clang-fast && {
+ ../afl-clang-fast -o test-multiple-mutators test-multiple-mutators.c > /dev/null 2>&1
+ } || {
+ test -e ../afl-gcc-fast && {
+ ../afl-gcc-fast -o test-multiple-mutators test-multiple-mutators.c > /dev/null 2>&1
} || {
- test -e ../afl-gcc-fast && {
- ../afl-gcc-fast -o test-multiple-mutators test-multiple-mutators.c > /dev/null 2>&1
- } || {
- ../afl-gcc -o test-multiple-mutators test-multiple-mutators.c > /dev/null 2>&1
- }
+ ../afl-gcc -o test-multiple-mutators test-multiple-mutators.c > /dev/null 2>&1
}
- # Compile the custom mutator
- cc -D_FIXED_CHAR=0x41 -g -fPIC -shared -I../include ../custom_mutators/examples/simple_example.c -o libexamplemutator.so > /dev/null 2>&1
- cc -D_FIXED_CHAR=0x42 -g -fPIC -shared -I../include ../custom_mutators/examples/simple_example.c -o libexamplemutator2.so > /dev/null 2>&1
- test -e test-custom-mutator -a -e ./libexamplemutator.so && {
- # Create input directory
- mkdir -p in
- echo "00000" > in/in
+ }
+ # Compile the custom mutator
+ cc -D_FIXED_CHAR=0x41 -g -fPIC -shared -I../include ../custom_mutators/examples/simple_example.c -o libexamplemutator.so > /dev/null 2>&1
+ cc -D_FIXED_CHAR=0x42 -g -fPIC -shared -I../include ../custom_mutators/examples/simple_example.c -o libexamplemutator2.so > /dev/null 2>&1
+ test -e test-custom-mutator -a -e ./libexamplemutator.so && {
+ # Create input directory
+ mkdir -p in
+ echo "00000" > in/in
- # Run afl-fuzz w/ the C mutator
- $ECHO "$GREY[*] running afl-fuzz for the C mutator, this will take approx 10 seconds"
- {
- AFL_CUSTOM_MUTATOR_LIBRARY=./libexamplemutator.so AFL_CUSTOM_MUTATOR_ONLY=1 ../afl-fuzz -V10 -m ${MEM_LIMIT} -i in -o out -- ./test-custom-mutator >>errors 2>&1
- } >>errors 2>&1
+ # Run afl-fuzz w/ the C mutator
+ $ECHO "$GREY[*] running afl-fuzz for the C mutator, this will take approx 10 seconds"
+ {
+ AFL_CUSTOM_MUTATOR_LIBRARY=./libexamplemutator.so AFL_CUSTOM_MUTATOR_ONLY=1 ../afl-fuzz -V07 -m ${MEM_LIMIT} -i in -o out -- ./test-custom-mutator >>errors 2>&1
+ } >>errors 2>&1
- # Check results
- test -n "$( ls out/default/crashes/id:000000* 2>/dev/null )" && { # TODO: update here
- $ECHO "$GREEN[+] afl-fuzz is working correctly with the C mutator"
- } || {
- echo CUT------------------------------------------------------------------CUT
- cat errors
- echo CUT------------------------------------------------------------------CUT
- $ECHO "$RED[!] afl-fuzz is not working correctly with the C mutator"
- CODE=1
- }
+ # Check results
+ test -n "$( ls out/default/crashes/id:000000* 2>/dev/null )" && { # TODO: update here
+ $ECHO "$GREEN[+] afl-fuzz is working correctly with the C mutator"
+ } || {
+ echo CUT------------------------------------------------------------------CUT
+ cat errors
+ echo CUT------------------------------------------------------------------CUT
+ $ECHO "$RED[!] afl-fuzz is not working correctly with the C mutator"
+ CODE=1
+ }
- # Clean
- rm -rf out errors core.*
+ # Clean
+ rm -rf out errors core.*
- # Run afl-fuzz w/ multiple C mutators
- $ECHO "$GREY[*] running afl-fuzz with multiple custom C mutators, this will take approx 10 seconds"
- {
- AFL_CUSTOM_MUTATOR_LIBRARY="./libexamplemutator.so;./libexamplemutator2.so" AFL_CUSTOM_MUTATOR_ONLY=1 ../afl-fuzz -V10 -m ${MEM_LIMIT} -i in -o out -- ./test-multiple-mutators >>errors 2>&1
- } >>errors 2>&1
+ # Run afl-fuzz w/ multiple C mutators
+ $ECHO "$GREY[*] running afl-fuzz with multiple custom C mutators, this will take approx 10 seconds"
+ {
+ AFL_CUSTOM_MUTATOR_LIBRARY="./libexamplemutator.so;./libexamplemutator2.so" AFL_CUSTOM_MUTATOR_ONLY=1 ../afl-fuzz -V07 -m ${MEM_LIMIT} -i in -o out -- ./test-multiple-mutators >>errors 2>&1
+ } >>errors 2>&1
- test -n "$( ls out/default/crashes/id:000000* 2>/dev/null )" && { # TODO: update here
- $ECHO "$GREEN[+] afl-fuzz is working correctly with multiple C mutators"
- } || {
- echo CUT------------------------------------------------------------------CUT
- cat errors
- echo CUT------------------------------------------------------------------CUT
- $ECHO "$RED[!] afl-fuzz is not working correctly with multiple C mutators"
- CODE=1
- }
+ test -n "$( ls out/default/crashes/id:000000* 2>/dev/null )" && { # TODO: update here
+ $ECHO "$GREEN[+] afl-fuzz is working correctly with multiple C mutators"
+ } || {
+ echo CUT------------------------------------------------------------------CUT
+ cat errors
+ echo CUT------------------------------------------------------------------CUT
+ $ECHO "$RED[!] afl-fuzz is not working correctly with multiple C mutators"
+ CODE=1
+ }
- # Clean
- rm -rf out errors core.*
+ # Clean
+ rm -rf out errors core.*
+ } || {
+ ls .
+ ls ${CUSTOM_MUTATOR_PATH}
+ $ECHO "$RED[!] cannot compile the test program or the custom mutator"
+ CODE=1
+ }
+}
+test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && {
+ test -e test-custom-mutator && {
# Run afl-fuzz w/ the Python mutator
$ECHO "$GREY[*] running afl-fuzz for the Python mutator, this will take approx 10 seconds"
{
export PYTHONPATH=${CUSTOM_MUTATOR_PATH}
export AFL_PYTHON_MODULE=example
- AFL_CUSTOM_MUTATOR_ONLY=1 ../afl-fuzz -V10 -m ${MEM_LIMIT} -i in -o out -- ./test-custom-mutator >>errors 2>&1
+ AFL_CUSTOM_MUTATOR_ONLY=1 ../afl-fuzz -V07 -m ${MEM_LIMIT} -i in -o out -- ./test-custom-mutator >>errors 2>&1
unset PYTHONPATH
unset AFL_PYTHON_MODULE
} >>errors 2>&1
@@ -106,20 +114,12 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && {
$ECHO "$RED[!] cannot compile the test program or the custom mutator"
CODE=1
}
-
- #test "$CODE" = 1 && { $ECHO "$YELLOW[!] custom mutator tests currently will not fail travis" ; CODE=0 ; }
-
- make -C ../utils/custom_mutators clean > /dev/null 2>&1
- rm -f test-custom-mutator
- rm -f test-custom-mutators
- } || {
- $ECHO "$YELLOW[-] no custom mutators in $CUSTOM_MUTATOR_PATH, cannot test"
- INCOMPLETE=1
- }
- unset CUSTOM_MUTATOR_PATH
} || {
$ECHO "$YELLOW[-] no python support in afl-fuzz, cannot test"
INCOMPLETE=1
}
+make -C ../utils/custom_mutators clean > /dev/null 2>&1
+rm -f test-custom-mutator test-custom-mutators
+
. ./test-post.sh
diff --git a/test/test-dlopen.c b/test/test-dlopen.c
index b81bab13..39442f93 100644
--- a/test/test-dlopen.c
+++ b/test/test-dlopen.c
@@ -28,7 +28,7 @@ int main(int argc, char **argv) {
}
- // must use deferred forkserver as otherwise afl++ instrumentation aborts
+ // must use deferred forkserver as otherwise AFL++ instrumentation aborts
// because all dlopen() of instrumented libs must be before the forkserver
__AFL_INIT();
diff --git a/test/test-frida-mode.sh b/test/test-frida-mode.sh
index 59b8e307..8c528da5 100755
--- a/test/test-frida-mode.sh
+++ b/test/test-frida-mode.sh
@@ -22,7 +22,7 @@ test -e ../afl-frida-trace.so && {
echo 00000 > in/in
$ECHO "$GREY[*] running afl-fuzz for frida_mode, this will take approx 10 seconds"
{
- AFL_DEBUG=1 AFL_FRIDA_VERBOSE=1 ../afl-fuzz -m ${MEM_LIMIT} -V10 -O -i in -o out -- ./test-instr >>errors 2>&1
+ AFL_DEBUG=1 AFL_FRIDA_VERBOSE=1 ../afl-fuzz -m ${MEM_LIMIT} -V07 -O -i in -o out -- ./test-instr >>errors 2>&1
} >>errors 2>&1
test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
$ECHO "$GREEN[+] afl-fuzz is working correctly with frida_mode"
@@ -39,7 +39,7 @@ test -e ../afl-frida-trace.so && {
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 frida_mode cmplog, this will take approx 10 seconds"
{
- ../afl-fuzz -m none -V10 -O -c 0 -i in -o out -- ./test-compcov >>errors 2>&1
+ ../afl-fuzz -m none -V07 -O -c 0 -l 3 -i in -o out -- ./test-compcov >>errors 2>&1
} >>errors 2>&1
test -n "$( ls out/default/queue/id:000003* 2>/dev/null )" && {
$ECHO "$GREEN[+] afl-fuzz is working correctly with frida_mode cmplog"
@@ -62,12 +62,12 @@ test -e ../afl-frida-trace.so && {
#else
#fi
export AFL_FRIDA_PERSISTENT_ADDR=0x`nm test-instr | grep -Ei "T _main|T main" | awk '{print $1}'`
- $ECHO "Info: AFL_FRIDA_PERSISTENT_ADDR=$AFL_FRIDA_PERSISTENT_ADDR <= $(nm test-instr | grep "T main" | awk '{print $1}')"
+ $ECHO "Note: AFL_FRIDA_PERSISTENT_ADDR=$AFL_FRIDA_PERSISTENT_ADDR <= $(nm test-instr | grep "T main" | awk '{print $1}')"
env|grep AFL_|sort
file test-instr
export AFL_DEBUG_CHILD=1
export AFL_FRIDA_VERBOSE=1
- ../afl-fuzz -m ${MEM_LIMIT} -V10 -O -i in -o out -- ./test-instr
+ ../afl-fuzz -m ${MEM_LIMIT} -V07 -O -i in -o out -- ./test-instr
nm test-instr | grep -i "main"
unset AFL_FRIDA_PERSISTENT_ADDR
} >>errors 2>&1
diff --git a/test/test-gcc-plugin.sh b/test/test-gcc-plugin.sh
index 95ae9c47..3690a80a 100755
--- a/test/test-gcc-plugin.sh
+++ b/test/test-gcc-plugin.sh
@@ -23,7 +23,7 @@ test -e ../afl-gcc-fast -a -e ../afl-compiler-rt.o && {
$ECHO "$GREEN[+] gcc_plugin run reported $TUPLES instrumented locations which is fine"
} || {
$ECHO "$RED[!] gcc_plugin instrumentation produces a weird numbers: $TUPLES"
- $ECHO "$YELLOW[-] this is a known issue in gcc, not afl++. It is not flagged as an error because travis builds would all fail otherwise :-("
+ $ECHO "$YELLOW[-] this is a known issue in gcc, not AFL++. It is not flagged as an error because travis builds would all fail otherwise :-("
#CODE=1
}
test "$TUPLES" -lt 2 && SKIP=1
@@ -63,7 +63,7 @@ test -e ../afl-gcc-fast -a -e ../afl-compiler-rt.o && {
echo 0 > in/in
$ECHO "$GREY[*] running afl-fuzz for gcc_plugin, this will take approx 10 seconds"
{
- ../afl-fuzz -V10 -m ${MEM_LIMIT} -i in -o out -D -- ./test-instr.plain.gccpi >>errors 2>&1
+ ../afl-fuzz -V07 -m ${MEM_LIMIT} -i in -o out -- ./test-instr.plain.gccpi >>errors 2>&1
} >>errors 2>&1
test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
$ECHO "$GREEN[+] afl-fuzz is working correctly with gcc_plugin"
diff --git a/test/test-llvm.sh b/test/test-llvm.sh
index ce64d76c..95e43b1c 100755
--- a/test/test-llvm.sh
+++ b/test/test-llvm.sh
@@ -133,7 +133,7 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
test -z "$SKIP" && {
$ECHO "$GREY[*] running afl-fuzz for llvm_mode, this will take approx 10 seconds"
{
- ../afl-fuzz -V10 -m ${MEM_LIMIT} -i in -o out -D -- ./test-instr.plain >>errors 2>&1
+ ../afl-fuzz -V07 -m ${MEM_LIMIT} -i in -o out -- ./test-instr.plain >>errors 2>&1
} >>errors 2>&1
test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
$ECHO "$GREEN[+] afl-fuzz is working correctly with llvm_mode"
@@ -228,7 +228,7 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
echo ZZZZ > in/in
$ECHO "$GREY[*] running afl-fuzz with floating point splitting, this will take max. 45 seconds"
{
- AFL_BENCH_UNTIL_CRASH=1 AFL_NO_UI=1 ../afl-fuzz -Z -s 123 -V50 -m ${MEM_LIMIT} -i in -o out -D -- ./test-floatingpoint >>errors 2>&1
+ AFL_BENCH_UNTIL_CRASH=1 AFL_NO_UI=1 ../afl-fuzz -Z -s 123 -V15 -m ${MEM_LIMIT} -i in -o out -- ./test-floatingpoint >>errors 2>&1
} >>errors 2>&1
test -n "$( ls out/default/crashes/id:* 2>/dev/null )" && {
$ECHO "$GREEN[+] llvm_mode laf-intel floatingpoint splitting feature works correctly"
@@ -257,14 +257,15 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
}
rm -f test-compcov test.out instrumentlist.txt
AFL_LLVM_CMPLOG=1 ../afl-clang-fast -o test-cmplog test-cmplog.c > /dev/null 2>&1
+ ../afl-clang-fast -O0 -o test-c test-cmplog.c > /dev/null 2>&1
test -e test-cmplog && {
$ECHO "$GREY[*] running afl-fuzz for llvm_mode cmplog, this will take approx 10 seconds"
{
mkdir -p in
echo 00000000000000000000000000000000 > in/in
- AFL_BENCH_UNTIL_CRASH=1 ../afl-fuzz -m none -V60 -i in -o out -c./test-cmplog -- ./test-cmplog >>errors 2>&1
+ AFL_BENCH_UNTIL_CRASH=1 ../afl-fuzz -l 3 -m none -V30 -i in -o out -c ./test-cmplog -- ./test-c >>errors 2>&1
} >>errors 2>&1
- test -n "$( ls out/default/crashes/id:000000* out/default/hangs/id:000000* 2>/dev/null )" & {
+ test -n "$( ls out/default/crashes/id:000000* out/default/hangs/id:000000* 2>/dev/null )" && {
$ECHO "$GREEN[+] afl-fuzz is working correctly with llvm_mode cmplog"
} || {
echo CUT------------------------------------------------------------------CUT
@@ -277,7 +278,7 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
$ECHO "$YELLOW[-] we cannot test llvm_mode cmplog because it is not present"
INCOMPLETE=1
}
- rm -rf errors test-cmplog in core.*
+ rm -rf errors test-cmplog test-c in core.*
../afl-clang-fast -o test-persistent ../utils/persistent_mode/persistent_demo.c > /dev/null 2>&1
test -e test-persistent && {
echo foo | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -q -r ./test-persistent && {
diff --git a/test/test-performance.sh b/test/test-performance.sh
index d61e2f2a..50957141 100755
--- a/test/test-performance.sh
+++ b/test/test-performance.sh
@@ -7,7 +7,7 @@ FILE=$AFL_PERFORMANCE_FILE
test -z "$FILE" && FILE=.afl_performance
test -e $FILE || {
- echo Warning: This script measure the performance of afl++ and saves the result for future comparisons into $FILE
+ echo Warning: This script measure the performance of AFL++ and saves the result for future comparisons into $FILE
echo Press ENTER to continue or CONTROL-C to abort
read IN
}
@@ -74,7 +74,7 @@ afl-system-config > /dev/null 2>&1
echo Performance settings applied.
echo
-$ECHO "${RESET}${GREY}[*] starting afl++ performance test framework ..."
+$ECHO "${RESET}${GREY}[*] starting AFL++ performance test framework ..."
$ECHO "$BLUE[*] Testing: ${AFL_GCC}"
GCC=x
diff --git a/test/test-pre.sh b/test/test-pre.sh
index b8b286e5..1ca9dfb5 100755
--- a/test/test-pre.sh
+++ b/test/test-pre.sh
@@ -133,7 +133,7 @@ MEM_LIMIT=none
export PATH="${PATH}:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin"
-$ECHO "${RESET}${GREY}[*] starting afl++ test framework ..."
+$ECHO "${RESET}${GREY}[*] starting AFL++ test framework ..."
test -z "$SYS" && $ECHO "$YELLOW[-] uname -m did not succeed"
diff --git a/test/test-qemu-mode.sh b/test/test-qemu-mode.sh
index 46b138ff..8eb7cb67 100755
--- a/test/test-qemu-mode.sh
+++ b/test/test-qemu-mode.sh
@@ -22,7 +22,7 @@ test -e ../afl-qemu-trace && {
echo 00000 > in/in
$ECHO "$GREY[*] running afl-fuzz for qemu_mode, this will take approx 10 seconds"
{
- ../afl-fuzz -m ${MEM_LIMIT} -V10 -Q -i in -o out -- ./test-instr >>errors 2>&1
+ ../afl-fuzz -m ${MEM_LIMIT} -V07 -Q -i in -o out -- ./test-instr >>errors 2>&1
} >>errors 2>&1
test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
$ECHO "$GREEN[+] afl-fuzz is working correctly with qemu_mode"
@@ -63,7 +63,7 @@ test -e ../afl-qemu-trace && {
{
export AFL_PRELOAD=../libcompcov.so
export AFL_COMPCOV_LEVEL=2
- ../afl-fuzz -m ${MEM_LIMIT} -V10 -Q -i in -o out -- ./test-compcov >>errors 2>&1
+ ../afl-fuzz -m ${MEM_LIMIT} -V07 -Q -i in -o out -- ./test-compcov >>errors 2>&1
unset AFL_PRELOAD
unset AFL_COMPCOV_LEVEL
} >>errors 2>&1
@@ -88,7 +88,7 @@ test -e ../afl-qemu-trace && {
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 qemu_mode cmplog, this will take approx 10 seconds"
{
- ../afl-fuzz -m none -V10 -Q -c 0 -i in -o out -- ./test-compcov >>errors 2>&1
+ ../afl-fuzz -m none -V07 -Q -c 0 -l 3 -i in -o out -- ./test-compcov >>errors 2>&1
} >>errors 2>&1
test -n "$( ls out/default/queue/id:000001* 2>/dev/null )" && {
$ECHO "$GREEN[+] afl-fuzz is working correctly with qemu_mode cmplog"
@@ -107,19 +107,26 @@ test -e ../afl-qemu-trace && {
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"
{
- 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/^.//'`
- else
- # 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/^.......//'`
- fi
- export AFL_QEMU_PERSISTENT_ADDR=`expr 0x4${ADDR_LOWER_PART}`
+ IS_STATIC=""
+ file test-instr | grep -q 'statically linked' && IS_STATIC=1
+ test -z "$IS_STATIC" && {
+ 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/^.//'`
+ else
+ # 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/^.......//'`
+ 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}'`
+ }
export AFL_QEMU_PERSISTENT_GPR=1
$ECHO "Info: AFL_QEMU_PERSISTENT_ADDR=$AFL_QEMU_PERSISTENT_ADDR <= $(nm test-instr | grep "T main" | awk '{print $1}')"
env|grep AFL_|sort
file test-instr
- ../afl-fuzz -m ${MEM_LIMIT} -V10 -Q -i in -o out -- ./test-instr
+ ../afl-fuzz -m ${MEM_LIMIT} -V07 -Q -i in -o out -- ./test-instr
unset AFL_QEMU_PERSISTENT_ADDR
} >>errors 2>&1
test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
diff --git a/test/test-unicorn-mode.sh b/test/test-unicorn-mode.sh
index f8ff4190..338c5982 100755
--- a/test/test-unicorn-mode.sh
+++ b/test/test-unicorn-mode.sh
@@ -34,7 +34,7 @@ test -d ../unicorn_mode/unicornafl -a -e ../unicorn_mode/unicornafl/Makefile &&
cd ../unicorn_mode/samples/persistent
make >>errors 2>&1
$ECHO "$GREY[*] running afl-fuzz for unicorn_mode (persistent), this will take approx 25 seconds"
- AFL_DEBUG_CHILD=1 ../../../afl-fuzz -m none -V25 -U -i sample_inputs -o out -d -- ./harness @@ >>errors 2>&1
+ AFL_DEBUG_CHILD=1 ../../../afl-fuzz -m none -V15 -U -i sample_inputs -o out -d -- ./harness @@ >>errors 2>&1
test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
$ECHO "$GREEN[+] afl-fuzz is working correctly with unicorn_mode (persistent)"
} || {
@@ -61,7 +61,7 @@ test -d ../unicorn_mode/unicornafl -a -e ../unicorn_mode/unicornafl/Makefile &&
{
$ECHO "$GREY[*] running afl-fuzz for unicorn_mode in python, this will take approx 25 seconds"
{
- ../afl-fuzz -m ${MEM_LIMIT} -V25 -U -i in -o out -d -- "$PY" ../unicorn_mode/samples/python_simple/simple_test_harness.py @@ >>errors 2>&1
+ ../afl-fuzz -m ${MEM_LIMIT} -V15 -U -i in -o out -d -- "$PY" ../unicorn_mode/samples/python_simple/simple_test_harness.py @@ >>errors 2>&1
} >>errors 2>&1
test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
$ECHO "$GREEN[+] afl-fuzz is working correctly with unicorn_mode"
@@ -80,7 +80,7 @@ test -d ../unicorn_mode/unicornafl -a -e ../unicorn_mode/unicornafl/Makefile &&
$ECHO "$GREY[*] running afl-fuzz for unicorn_mode compcov, this will take approx 35 seconds"
{
export AFL_COMPCOV_LEVEL=2
- ../afl-fuzz -m ${MEM_LIMIT} -V35 -U -i in -o out -d -- "$PY" ../unicorn_mode/samples/compcov_x64/compcov_test_harness.py @@ >>errors 2>&1
+ ../afl-fuzz -m ${MEM_LIMIT} -V15 -U -i in -o out -d -- "$PY" ../unicorn_mode/samples/compcov_x64/compcov_test_harness.py @@ >>errors 2>&1
unset AFL_COMPCOV_LEVEL
} >>errors 2>&1
test -n "$( ls out/default/queue/id:000001* 2>/dev/null )" && {
diff --git a/utils/README.md b/utils/README.md
index debc86e8..62d79193 100644
--- a/utils/README.md
+++ b/utils/README.md
@@ -56,8 +56,6 @@ Here's a quick overview of the stuff you can find in this directory:
- libpng_no_checksum - a sample patch for removing CRC checks in libpng.
- - optimin - An optimal corpus minimizer.
-
- persistent_mode - an example of how to use the LLVM persistent process
mode to speed up certain fuzzing jobs.
diff --git a/utils/afl_network_proxy/afl-network-client.c b/utils/afl_network_proxy/afl-network-client.c
index 7d04a89a..0416f0f9 100644
--- a/utils/afl_network_proxy/afl-network-client.c
+++ b/utils/afl_network_proxy/afl-network-client.c
@@ -4,7 +4,7 @@
Written by Marc Heuse <mh@mh-sec.de>
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -109,7 +109,7 @@ static void __afl_map_shm(void) {
if (id_str) {
#ifdef USEMMAP
- const char * shm_file_path = id_str;
+ const char *shm_file_path = id_str;
int shm_fd = -1;
unsigned char *shm_base = NULL;
@@ -209,13 +209,13 @@ static void __afl_end_testcase(int status) {
int main(int argc, char *argv[]) {
- u8 * interface, *buf, *ptr;
+ u8 *interface, *buf, *ptr;
s32 s = -1;
struct addrinfo hints, *hres, *aip;
- u32 * lenptr, max_len = 65536;
+ u32 *lenptr, max_len = 65536;
#ifdef USE_DEFLATE
- u8 * buf2;
- u32 * lenptr1, *lenptr2, buf2_len, compress_len;
+ u8 *buf2;
+ u32 *lenptr1, *lenptr2, buf2_len, compress_len;
size_t decompress_len;
#endif
diff --git a/utils/afl_network_proxy/afl-network-server.c b/utils/afl_network_proxy/afl-network-server.c
index 3e5e275d..04309ada 100644
--- a/utils/afl_network_proxy/afl-network-server.c
+++ b/utils/afl_network_proxy/afl-network-server.c
@@ -12,7 +12,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -60,7 +60,7 @@
#ifdef USE_DEFLATE
#include <libdeflate.h>
-struct libdeflate_compressor * compressor;
+struct libdeflate_compressor *compressor;
struct libdeflate_decompressor *decompressor;
#endif
@@ -194,7 +194,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
}
- if (!strstr(x, "symbolize=0")) {
+ if (!getenv("AFL_DEBUG") && !strstr(x, "symbolize=0")) {
FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!");
@@ -213,7 +213,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
}
- if (!strstr(x, "symbolize=0")) {
+ if (!getenv("AFL_DEBUG") && !strstr(x, "symbolize=0")) {
FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!");
@@ -221,18 +221,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
}
- setenv("ASAN_OPTIONS",
- "abort_on_error=1:"
- "detect_leaks=0:"
- "symbolize=0:"
- "allocator_may_return_null=1",
- 0);
-
- setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
- "symbolize=0:"
- "abort_on_error=1:"
- "allocator_may_return_null=1:"
- "msan_track_origins=0", 0);
+ set_sanitizer_defaults();
if (get_afl_env("AFL_PRELOAD")) {
@@ -387,8 +376,8 @@ int main(int argc, char **argv_orig, char **envp) {
struct sockaddr_in6 serveraddr, clientaddr;
int addrlen = sizeof(clientaddr);
char str[INET6_ADDRSTRLEN];
- char ** argv = argv_cpy_dup(argc, argv_orig);
- u8 * send_buf;
+ char **argv = argv_cpy_dup(argc, argv_orig);
+ u8 *send_buf;
#ifdef USE_DEFLATE
u32 *lenptr;
#endif
diff --git a/utils/afl_proxy/README.md b/utils/afl_proxy/README.md
index 3c768a19..7965659d 100644
--- a/utils/afl_proxy/README.md
+++ b/utils/afl_proxy/README.md
@@ -7,3 +7,8 @@ You only need to change the while() loop of the main() to send the
data of buf[] with length len to the target and write the coverage
information to __afl_area_ptr[__afl_map_size]
+UPDATE: you can also use [custom mutators](../../docs/custom_mutators.md) with
+afl_custom_fuzz_send to send data to a target, which is much more efficient!
+But you can only use this feature if you start the target via afl-fuzz and
+a forkserver is active (e.g. via -Q qemu_mode or source compiled).
+
diff --git a/utils/afl_proxy/afl-proxy.c b/utils/afl_proxy/afl-proxy.c
index 05247c60..531a97a2 100644
--- a/utils/afl_proxy/afl-proxy.c
+++ b/utils/afl_proxy/afl-proxy.c
@@ -4,7 +4,7 @@
Written by Marc Heuse <mh@mh-sec.de>
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -112,7 +112,7 @@ static void __afl_map_shm(void) {
if (id_str) {
#ifdef USEMMAP
- const char * shm_file_path = id_str;
+ const char *shm_file_path = id_str;
int shm_fd = -1;
unsigned char *shm_base = NULL;
diff --git a/utils/afl_untracer/afl-untracer.c b/utils/afl_untracer/afl-untracer.c
index fd4c3b8c..e1038212 100644
--- a/utils/afl_untracer/afl-untracer.c
+++ b/utils/afl_untracer/afl-untracer.c
@@ -4,7 +4,7 @@
Written by Marc Heuse <mh@mh-sec.de>
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -108,8 +108,8 @@ __thread u32 do_exit;
static pid_t pid = 65537;
static pthread_t __afl_thread;
static u8 __afl_dummy[MAP_SIZE];
-static u8 * __afl_area_ptr = __afl_dummy;
-static u8 * inputfile; // this will point to argv[1]
+static u8 *__afl_area_ptr = __afl_dummy;
+static u8 *inputfile; // this will point to argv[1]
static u32 len;
static library_list_t liblist[MAX_LIB_COUNT];
@@ -156,7 +156,7 @@ void read_library_information(void) {
*e = 0;
if (n[strlen(n) - 1] == '\n') n[strlen(n) - 1] = 0;
- liblist[liblist_cnt].name = strdup(n);
+ liblist[liblist_cnt].name = (u8 *)strdup((char *)n);
liblist[liblist_cnt].addr_start = strtoull(b, NULL, 16);
liblist[liblist_cnt].addr_end = strtoull(m, NULL, 16);
if (debug)
@@ -177,7 +177,7 @@ void read_library_information(void) {
#elif defined(__FreeBSD__)
int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()};
- char * buf, *start, *end;
+ char *buf, *start, *end;
size_t miblen = sizeof(mib) / sizeof(mib[0]);
size_t len;
@@ -210,16 +210,17 @@ void read_library_information(void) {
!(region->kve_protection & KVME_PROT_EXEC)) {
liblist[liblist_cnt].name =
- region->kve_path[0] != '\0' ? strdup(region->kve_path) : 0;
+ region->kve_path[0] != '\0' ? (u8 *)strdup(region->kve_path) : 0;
liblist[liblist_cnt].addr_start = region->kve_start;
liblist[liblist_cnt].addr_end = region->kve_end;
if (debug) {
- fprintf(stderr, "%s:%x (%lx-%lx)\n", liblist[liblist_cnt].name,
- liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start,
- liblist[liblist_cnt].addr_start,
- liblist[liblist_cnt].addr_end - 1);
+ fprintf(stderr, "%s:%lx (%lx-%lx)\n", liblist[liblist_cnt].name,
+ (unsigned long)(liblist[liblist_cnt].addr_end -
+ liblist[liblist_cnt].addr_start),
+ (unsigned long)liblist[liblist_cnt].addr_start,
+ (unsigned long)(liblist[liblist_cnt].addr_end - 1));
}
@@ -261,7 +262,7 @@ library_list_t *find_library(char *name) {
for (size_t i = 0; i < all_image_infos->infoArrayCount; i++) {
- const char * image_name = image_infos[i].imageFilePath;
+ const char *image_name = image_infos[i].imageFilePath;
mach_vm_address_t image_load_address =
(mach_vm_address_t)image_infos[i].imageLoadAddress;
if (strstr(image_name, name)) {
@@ -347,7 +348,7 @@ static void __afl_map_shm(void) {
if (id_str) {
#ifdef USEMMAP
- const char * shm_file_path = id_str;
+ const char *shm_file_path = id_str;
int shm_fd = -1;
unsigned char *shm_base = NULL;
@@ -468,10 +469,10 @@ void setup_trap_instrumentation(void) {
library_list_t *lib_base = NULL;
size_t lib_size = 0;
- u8 * lib_addr;
- char * line = NULL;
+ u8 *lib_addr;
+ char *line = NULL;
size_t nread, len = 0;
- char * filename = getenv("AFL_UNTRACER_FILE");
+ char *filename = getenv("AFL_UNTRACER_FILE");
if (!filename) filename = getenv("TRAPFUZZ_FILE");
if (!filename) FATAL("AFL_UNTRACER_FILE environment variable not set");
@@ -488,6 +489,12 @@ void setup_trap_instrumentation(void) {
uint32_t bitmap_index = 0;
#endif
+#if defined(__FreeBSD__) && __FreeBSD_version >= 1301000
+ // We try to allow W/X pages despite kern.elf32/64.allow_wx system settings
+ int allow_wx = PROC_WX_MAPPINGS_PERMIT;
+ (void)procctl(P_PID, 0, PROC_WXMAP_CTL, &allow_wx);
+#endif
+
while ((nread = getline(&line, &len, patches)) != -1) {
char *end = line + len;
@@ -699,7 +706,7 @@ int main(int argc, char *argv[]) {
if (argc > 1) {
use_stdin = 0;
- inputfile = argv[1];
+ inputfile = (u8 *)argv[1];
}
@@ -732,7 +739,7 @@ int main(int argc, char *argv[]) {
if (pid) {
u32 status;
- if (waitpid(pid, &status, 0) < 0) exit(1);
+ if (waitpid(pid, (int *)&status, 0) < 0) exit(1);
/* report the test case is done and wait for the next */
__afl_end_testcase(status);
diff --git a/utils/afl_untracer/libtestinstr.c b/utils/afl_untracer/libtestinstr.c
index a3f5acc8..b7afc325 100644
--- a/utils/afl_untracer/libtestinstr.c
+++ b/utils/afl_untracer/libtestinstr.c
@@ -3,7 +3,7 @@
--------------------------------------------------------
Originally written by Michal Zalewski
Copyright 2014 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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:
diff --git a/utils/aflpp_driver/GNUmakefile b/utils/aflpp_driver/GNUmakefile
index 234a1c31..b973f96a 100644
--- a/utils/aflpp_driver/GNUmakefile
+++ b/utils/aflpp_driver/GNUmakefile
@@ -8,9 +8,14 @@ ifeq "$(shell uname -s)" "Darwin"
LDFLAGS += $(SDK_LD)
endif
+ifeq "" "$(LLVM_CONFIG)"
+ LLVM_CONFIG := llvm-config
+endif
LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)
ifneq "" "$(LLVM_BINDIR)"
- LLVM_BINDIR := $(LLVM_BINDIR)/
+ ifeq "$(shell test -x $(LLVM_BINDIR)/clang && echo 1)" "1"
+ CC := $(LLVM_BINDIR)/clang
+ endif
endif
CFLAGS := -O3 -funroll-loops -g -fPIC
@@ -18,31 +23,31 @@ CFLAGS := -O3 -funroll-loops -g -fPIC
all: libAFLDriver.a libAFLQemuDriver.a aflpp_qemu_driver_hook.so
aflpp_driver.o: aflpp_driver.c
- -$(LLVM_BINDIR)clang -I. -I../../include $(CFLAGS) -c aflpp_driver.c
+ -$(CC) -I. -I../../include $(CFLAGS) -c aflpp_driver.c
libAFLDriver.a: aflpp_driver.o
@ar rc libAFLDriver.a aflpp_driver.o
@cp -vf libAFLDriver.a ../../
debug:
- $(LLVM_BINDIR)clang -Wno-deprecated -I../../include $(CFLAGS) -D_DEBUG=\"1\" -c -o afl-performance.o ../../src/afl-performance.c
- $(LLVM_BINDIR)clang -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c
- #$(LLVM_BINDIR)clang -S -emit-llvm -Wno-deprecated -I../../include $(CFLAGS) -D_DEBUG=\"1\" -c -o afl-performance.ll ../../src/afl-performance.c
- #$(LLVM_BINDIR)clang -S -emit-llvm -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c
+ $(CC) -Wno-deprecated -I../../include $(CFLAGS) -D_DEBUG=\"1\" -c -o afl-performance.o ../../src/afl-performance.c
+ $(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
aflpp_qemu_driver.o: aflpp_qemu_driver.c
- -$(LLVM_BINDIR)clang $(CFLAGS) -O0 -funroll-loops -c 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
@-cp -vf libAFLQemuDriver.a ../../
aflpp_qemu_driver_hook.so: aflpp_qemu_driver_hook.o
- @-test -e aflpp_qemu_driver_hook.o && $(LLVM_BINDIR)clang $(LDFLAGS) -shared aflpp_qemu_driver_hook.o -o aflpp_qemu_driver_hook.so || echo "Note: Optional aflpp_qemu_driver_hook.so not built."
+ @-test -e aflpp_qemu_driver_hook.o && $(CC) $(LDFLAGS) -shared aflpp_qemu_driver_hook.o -o aflpp_qemu_driver_hook.so || echo "Note: Optional aflpp_qemu_driver_hook.so not built."
aflpp_qemu_driver_hook.o: aflpp_qemu_driver_hook.c
- @-test -e ../../qemu_mode/qemuafl/qemuafl/api.h && $(LLVM_BINDIR)clang $(CFLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c || echo "Note: Optional aflpp_qemu_driver_hook.o not built."
+ @-test -e ../../qemu_mode/qemuafl/qemuafl/api.h && $(CC) $(CFLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c || echo "Note: Optional aflpp_qemu_driver_hook.o not built."
test: debug
#clang -S -emit-llvm -D_DEBUG=\"1\" -I../../include -Wl,--allow-multiple-definition -funroll-loops -o aflpp_driver_test.ll aflpp_driver_test.c
diff --git a/utils/aflpp_driver/aflpp_driver.c b/utils/aflpp_driver/aflpp_driver.c
index 7289c845..4e8f466d 100644
--- a/utils/aflpp_driver/aflpp_driver.c
+++ b/utils/aflpp_driver/aflpp_driver.c
@@ -1,12 +1,16 @@
-//===- afl_driver.cpp - a glue between AFL++ and libFuzzer ------*- C++ -* ===//
-//===----------------------------------------------------------------------===//
+//
+// afl_driver.cpp - a glue between AFL++ and LLVMFuzzerTestOneInput harnesses
+//
-/* This file allows to fuzz libFuzzer-style target functions
+/*
+
+ This file allows to fuzz libFuzzer-style target functions
(LLVMFuzzerTestOneInput) with AFL++ using persistent in-memory fuzzing.
Usage:
-################################################################################
-cat << EOF > test_fuzzer.cc
+
+# Example target:
+$ cat << EOF > test_fuzzer.cc
#include <stddef.h>
#include <stdint.h>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
@@ -20,21 +24,24 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
}
EOF
-# Build your target with -fsanitize-coverage=trace-pc-guard using fresh clang.
-clang -c aflpp_driver.c
-# Build afl-compiler-rt.o.c from the AFL distribution.
-clang -c $AFL_HOME/instrumentation/afl-compiler-rt.o.c
-# Build this file, link it with afl-compiler-rt.o.o and the target code.
-afl-clang-fast -o test_fuzzer test_fuzzer.cc afl-compiler-rt.o aflpp_driver.o
+
+# Build your target with afl-cc -fsanitize=fuzzer
+$ afl-c++ -fsanitize=fuzzer -o test_fuzzer test_fuzzer.cc
# Run AFL:
-rm -rf IN OUT; mkdir IN OUT; echo z > IN/z;
-$AFL_HOME/afl-fuzz -i IN -o OUT ./a.out
-################################################################################
+$ mkdir -p in ; echo z > in/foo;
+$ afl-fuzz -i in -o out -- ./test_fuzzer
+
*/
+#ifdef __cplusplus
+extern "C" {
+
+#endif
+
#include <assert.h>
#include <errno.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -57,15 +64,26 @@ $AFL_HOME/afl-fuzz -i IN -o OUT ./a.out
#include "hash.h"
#endif
+// AFL++ shared memory fuzz cases
int __afl_sharedmem_fuzzing = 1;
-extern unsigned int * __afl_fuzz_len;
+extern unsigned int *__afl_fuzz_len;
extern unsigned char *__afl_fuzz_ptr;
-// libFuzzer interface is thin, so we don't include any libFuzzer headers.
-int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
-__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
+// AFL++ coverage map
+extern unsigned char *__afl_area_ptr;
+extern unsigned int __afl_map_size;
-// Default nop ASan hooks for manual posisoning when not linking the ASan
+// libFuzzer interface is thin, so we don't include any libFuzzer headers.
+/* Using the weak attributed on LLVMFuzzerTestOneInput() breaks oss-fuzz but
+ on the other hand this is what Google needs to make LLVMFuzzerRunDriver()
+ work. Choose your poison Google! */
+/*__attribute__((weak))*/ int LLVMFuzzerTestOneInput(const uint8_t *Data,
+ size_t Size);
+__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
+__attribute__((weak)) int LLVMFuzzerRunDriver(
+ int *argc, char ***argv, int (*callback)(const uint8_t *data, size_t size));
+
+// Default nop ASan hooks for manual poisoning when not linking the ASan
// runtime
// https://github.com/google/sanitizers/wiki/AddressSanitizerManualPoisoning
__attribute__((weak)) void __asan_poison_memory_region(
@@ -187,7 +205,8 @@ static void maybe_close_fd_mask() {
// Define LLVMFuzzerMutate to avoid link failures for targets that use it
// with libFuzzer's LLVMFuzzerCustomMutator.
-size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
+__attribute__((weak)) size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
// assert(false && "LLVMFuzzerMutate should not be called from afl_driver");
return 0;
@@ -195,7 +214,9 @@ size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
}
// Execute any files provided as parameters.
-static int ExecuteFilesOnyByOne(int argc, char **argv) {
+static int ExecuteFilesOnyByOne(int argc, char **argv,
+ int (*callback)(const uint8_t *data,
+ size_t size)) {
unsigned char *buf = (unsigned char *)malloc(MAX_FILE);
@@ -231,7 +252,7 @@ static int ExecuteFilesOnyByOne(int argc, char **argv) {
prev_length = length;
printf("Reading %zu bytes from %s\n", length, argv[i]);
- LLVMFuzzerTestOneInput(buf, length);
+ callback(buf, length);
printf("Execution successful.\n");
}
@@ -245,7 +266,18 @@ static int ExecuteFilesOnyByOne(int argc, char **argv) {
}
-int main(int argc, char **argv) {
+__attribute__((weak)) int main(int argc, char **argv) {
+
+ // Enable if LLVMFuzzerTestOneInput() has the weak attribute
+ /*
+ if (!LLVMFuzzerTestOneInput) {
+
+ fprintf(stderr, "Error: function LLVMFuzzerTestOneInput() not found!\n");
+ abort();
+
+ }
+
+ */
if (argc < 2 || strncmp(argv[1], "-h", 2) == 0)
printf(
@@ -265,6 +297,17 @@ int main(int argc, char **argv) {
"===================================================================\n",
argv[0], argv[0]);
+ return LLVMFuzzerRunDriver(&argc, &argv, LLVMFuzzerTestOneInput);
+
+}
+
+__attribute__((weak)) int LLVMFuzzerRunDriver(
+ int *argcp, char ***argvp,
+ int (*callback)(const uint8_t *data, size_t size)) {
+
+ int argc = *argcp;
+ char **argv = *argvp;
+
if (getenv("AFL_GDB")) {
char cmd[64];
@@ -275,6 +318,12 @@ int main(int argc, char **argv) {
}
+ bool in_afl = !(!getenv(SHM_FUZZ_ENV_VAR) || !getenv(SHM_ENV_VAR) ||
+ fcntl(FORKSRV_FD, F_GETFD) == -1 ||
+ fcntl(FORKSRV_FD + 1, F_GETFD) == -1);
+
+ if (!in_afl) { __afl_sharedmem_fuzzing = 0; }
+
output_file = stderr;
maybe_duplicate_stderr();
maybe_close_fd_mask();
@@ -295,27 +344,28 @@ int main(int argc, char **argv) {
int N = INT_MAX;
- if (argc == 2 && !strcmp(argv[1], "-")) {
+ if (!in_afl && argc == 2 && !strcmp(argv[1], "-")) {
- __afl_sharedmem_fuzzing = 0;
__afl_manual_init();
- return ExecuteFilesOnyByOne(argc, argv);
+ return ExecuteFilesOnyByOne(argc, argv, callback);
- } else if (argc == 2 && argv[1][0] == '-') {
+ } else if (argc == 2 && argv[1][0] == '-' && argv[1][1]) {
N = atoi(argv[1] + 1);
- } else if (argc == 2 && (N = atoi(argv[1])) > 0) {
+ } else if (argc == 2 && argv[1][0] != '-' && (N = atoi(argv[1])) > 0) {
printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N);
- } else if (argc > 1) {
-
- __afl_sharedmem_fuzzing = 0;
+ } else if (!in_afl && argc > 1 && argv[1][0] != '-') {
if (argc == 2) { __afl_manual_init(); }
- return ExecuteFilesOnyByOne(argc, argv);
+ return ExecuteFilesOnyByOne(argc, argv, callback);
+
+ } else {
+
+ N = INT_MAX;
}
@@ -325,7 +375,7 @@ int main(int argc, char **argv) {
// Call LLVMFuzzerTestOneInput here so that coverage caused by initialization
// on the first execution of LLVMFuzzerTestOneInput is ignored.
- LLVMFuzzerTestOneInput(dummy_input, 4);
+ callback(dummy_input, 4);
__asan_poison_memory_region(__afl_fuzz_ptr, MAX_FILE);
size_t prev_length = 0;
@@ -352,7 +402,13 @@ int main(int argc, char **argv) {
}
prev_length = length;
- LLVMFuzzerTestOneInput(__afl_fuzz_ptr, length);
+
+ if (unlikely(callback(__afl_fuzz_ptr, length) == -1)) {
+
+ memset(__afl_area_ptr, 0, __afl_map_size);
+ __afl_area_ptr[0] = 1;
+
+ }
}
@@ -362,7 +418,7 @@ int main(int argc, char **argv) {
while (__afl_persistent_loop(N)) {
- LLVMFuzzerTestOneInput(__afl_fuzz_ptr, *__afl_fuzz_len);
+ callback(__afl_fuzz_ptr, *__afl_fuzz_len);
}
@@ -372,3 +428,9 @@ int main(int argc, char **argv) {
}
+#ifdef __cplusplus
+
+}
+
+#endif
+
diff --git a/utils/aflpp_driver/aflpp_driver_test.c b/utils/aflpp_driver/aflpp_driver_test.c
index 527ba57b..32119485 100644
--- a/utils/aflpp_driver/aflpp_driver_test.c
+++ b/utils/aflpp_driver/aflpp_driver_test.c
@@ -2,23 +2,28 @@
#include <stdlib.h>
#include <stdint.h>
-void __attribute__((noinline)) crashme(const uint8_t *Data, size_t Size) {
+char *foo = NULL;
- if (Size < 5) return;
+int __attribute__((noinline)) crashme(const uint8_t *Data, size_t Size) {
+
+ if (Size < 5) return -1;
if (Data[0] == 'F')
if (Data[1] == 'A')
if (Data[2] == '$')
if (Data[3] == '$')
- if (Data[4] == '$') abort();
+ if (Data[4] == '$') *foo = 1;
+
+ return 0;
}
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
- if (Size) crashme(Data, Size);
-
- return 0;
+ if (Size)
+ return crashme(Data, Size);
+ else
+ return -1;
}
diff --git a/utils/analysis_scripts/queue2csv.sh b/utils/analysis_scripts/queue2csv.sh
index 2528b438..47141efe 100755
--- a/utils/analysis_scripts/queue2csv.sh
+++ b/utils/analysis_scripts/queue2csv.sh
@@ -92,14 +92,14 @@ mkdir "$DIR" || exit 1
if [ -n "$3" -a -s "$DIR/../edges.txt" ]; then
- cat "$DIR/"* | sed 's/:.*//' | sort -n | uniq -c | egrep '^[ \t]*1 ' | awk '{print$2}' > $DIR/../unique.txt
+ cat "$DIR/"* | sed 's/:.*//' | sort -n | uniq -c | grep -E '^[ \t]*1 ' | awk '{print$2}' > $DIR/../unique.txt
if [ -s "$DIR/../unique.txt" ]; then
ls "$DIR/id:"* | grep -v ",sync:" |sed 's/.*\/id:/id:/g' | while read file; do
CNT=$(sed 's/:.*//' "$DIR/$file" | tee "$DIR/../tmp.txt" | wc -l)
- DIFF=$(diff -u "$DIR/../tmp.txt" "$DIR/../unique.txt" | egrep '^-[0-9]' | wc -l)
+ DIFF=$(diff -u "$DIR/../tmp.txt" "$DIR/../unique.txt" | grep -E '^-[0-9]' | wc -l)
UNIQUE=$(($CNT - $DIFF))
sed -i "s/;UNIQUE$file/;$UNIQUE/" "$DIR/../queue.csv" "$2"
diff --git a/utils/argv_fuzzing/Makefile b/utils/argv_fuzzing/Makefile
index 183f6bf8..6786467a 100644
--- a/utils/argv_fuzzing/Makefile
+++ b/utils/argv_fuzzing/Makefile
@@ -2,7 +2,7 @@
# american fuzzy lop++ - argvfuzz
# --------------------------------
#
-# Copyright 2019-2022 Kjell Braden <afflux@pentabarf.de>
+# Copyright 2019-2023 Kjell Braden <afflux@pentabarf.de>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -11,7 +11,7 @@
# http://www.apache.org/licenses/LICENSE-2.0
#
-.PHONY: all install clean
+.PHONY: all install clean argv_fuzz_persistent_demo argv_fuzz_demo demo
PREFIX ?= /usr/local
BIN_PATH = $(PREFIX)/bin
@@ -41,7 +41,7 @@ __M32FLAG=$(_M32FLAG:00=-mbe32)
___M32FLAG=$(__M32FLAG:$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)=-m32)
M32FLAG=$(___M32FLAG)
-all: argvfuzz32.so argvfuzz64.so
+all: argvfuzz32.so argvfuzz64.so demo
argvfuzz32.so: argvfuzz.c
-@$(CC) $(M32FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "argvfuzz32 build failure (that's fine)"
@@ -54,5 +54,14 @@ install: argvfuzz32.so argvfuzz64.so
if [ -f argvfuzz32.so ]; then set -e; install -m 755 argvfuzz32.so $(DESTDIR)$(HELPER_PATH)/; fi
if [ -f argvfuzz64.so ]; then set -e; install -m 755 argvfuzz64.so $(DESTDIR)$(HELPER_PATH)/; fi
+argv_fuzz_persistent_demo: argv_fuzz_persistent_demo.c
+ ../../afl-cc -g -o $@ $^
+
+argv_fuzz_demo: argv_fuzz_demo.c
+ ../../afl-cc -g -o $@ $^
+
+demo: argv_fuzz_persistent_demo argv_fuzz_demo
+
clean:
- rm -f argvfuzz32.so argvfuzz64.so
+ rm -f argvfuzz32.so argvfuzz64.so argv_fuzz_demo argv_fuzz_persistent_demo
+
diff --git a/utils/argv_fuzzing/README.md b/utils/argv_fuzzing/README.md
index e9224995..a085c098 100644
--- a/utils/argv_fuzzing/README.md
+++ b/utils/argv_fuzzing/README.md
@@ -1,16 +1,45 @@
-# argvfuzz
+# argv_fuzzing feature
+AFL++ supports fuzzing file inputs or standard input. The argv_fuzzing feature
+allows for the fuzzing of arguments passed to a program from the command line
+interface rather than from STDIN.
-AFL++ supports fuzzing file inputs or stdin. When source is available,
-`argv-fuzz-inl.h` can be used to change `main()` to build argv from stdin.
+## With source code
+When the source code is available, a specific macro from the `argv-fuzz-inl.h`
+header file can be used to change the program's behavior to build argv from STDIN.
+### Without persistent mode
+Conditions needed to use the argv_fuzzing feature:
+1. Include `argv-fuzz-inl.h` header file (`#include "argv-fuzz-inl.h"`)
+2. Identify your main function that parses arguments
+(for example, `int main(int argc, char **argv)`)
+3. Use one of the following macros (near the beginning of the main function)
+to initialize argv with the fuzzer's input:
+ - `AFL_INIT_ARGV();` or
+ - `AFL_INIT_SET0("prog_name");` to preserve `argv[0]`
+ (the name of the program being executed)
+
+see: [argv_fuzz_demo.c](argv_fuzz_demo.c)
+
+### With persistent mode
+Conditions needed to use the argv_fuzzing feature with persistent mode:
+1. Ensure your target can handle persistent mode fuzzing
+2. Follow instructions in the [llvm_mode persistent mode](https://github.com/AFLplusplus/AFLplusplus/blob/stable/instrumentation/README.persistent_mode.md)
+3. Use one of the following macros near the beginning of the main function and after
+the buffer initialization (`unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF`):
+ - `AFL_INIT_ARGV_PERSISTENT(buf)`, if you want to
+ - `AFL_INIT_SET0_PERSISTENT("name_of_binary", buf)`
+
+see: [argv_fuzz_persistent_demo.c](argv_fuzz_persistent_demo.c)
+
+## Binary only
`argvfuzz` tries to provide the same functionality for binaries. When loaded
using `LD_PRELOAD`, it will hook the call to `__libc_start_main` and replace
argv using the same logic of `argv-fuzz-inl.h`.
A few conditions need to be fulfilled for this mechanism to work correctly:
-1. As it relies on hooking the loader, it cannot work on static binaries.
+1. As it relies on hooking the loader, it cannot work on static binaries
2. If the target binary does not use the default libc's `_start` implementation
(crt1.o), the hook may not run.
-3. The hook will replace argv with pointers to `.data` of `argvfuzz.so`. If the
- target binary expects argv to be living on the stack, things may go wrong. \ No newline at end of file
+3. The hook will replace argv with pointers to `.data` of `argvfuzz.so`.
+Things may go wrong if the target binary expects argv to live on the stack.
diff --git a/utils/argv_fuzzing/argv-fuzz-inl.h b/utils/argv_fuzzing/argv-fuzz-inl.h
index c15c0271..cb0af2bc 100644
--- a/utils/argv_fuzzing/argv-fuzz-inl.h
+++ b/utils/argv_fuzzing/argv-fuzz-inl.h
@@ -29,11 +29,17 @@
If you would like to always preserve argv[0], use this instead:
AFL_INIT_SET0("prog_name");
+ To enable persistent fuzzing, use the AFL_INIT_ARGV_PERSISTENT macro with
+ buf as argument, or use AFL_INIT_SET0_PERSISTENT("prog_name", buf)
+ to preserver argv[0]. buf is a pointer to a buffer containing
+ the input data for the current test case being processed defined as:
+ unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF;
*/
#ifndef _HAVE_ARGV_FUZZ_INL
#define _HAVE_ARGV_FUZZ_INL
+#include <stdlib.h>
#include <unistd.h>
#define AFL_INIT_ARGV() \
@@ -52,6 +58,22 @@
\
} while (0)
+#define AFL_INIT_ARGV_PERSISTENT(persistent_buff) \
+ do { \
+ \
+ argv = afl_init_argv_persistent(&argc, persistent_buff); \
+ \
+ } while (0)
+
+#define AFL_INIT_SET0_PERSISTENT(_p, persistent_buff) \
+ do { \
+ \
+ argv = afl_init_argv_persistent(&argc, persistent_buff); \
+ argv[0] = (_p); \
+ if (!argc) argc = 1; \
+ \
+ } while (0)
+
#define MAX_CMDLINE_LEN 100000
#define MAX_CMDLINE_PAR 50000
@@ -63,7 +85,10 @@ static char **afl_init_argv(int *argc) {
char *ptr = in_buf;
int rc = 0;
- if (read(0, in_buf, MAX_CMDLINE_LEN - 2) < 0) {}
+ ssize_t num = read(0, in_buf, MAX_CMDLINE_LEN - 2);
+ if (num < 1) { _exit(1); }
+ in_buf[num] = '\0';
+ in_buf[num + 1] = '\0';
while (*ptr && rc < MAX_CMDLINE_PAR) {
@@ -83,6 +108,32 @@ static char **afl_init_argv(int *argc) {
}
+static char **afl_init_argv_persistent(int *argc,
+ unsigned char *persistent_buff) {
+
+ static char *ret[MAX_CMDLINE_PAR];
+
+ unsigned char *ptr = persistent_buff;
+ int rc = 0;
+
+ while (*ptr && rc < MAX_CMDLINE_PAR) {
+
+ ret[rc] = (char *)ptr;
+ if (ret[rc][0] == 0x02 && !ret[rc][1]) ret[rc]++;
+ rc++;
+
+ while (*ptr)
+ ptr++;
+ ptr++;
+
+ }
+
+ *argc = rc;
+
+ return ret;
+
+}
+
#undef MAX_CMDLINE_LEN
#undef MAX_CMDLINE_PAR
diff --git a/utils/argv_fuzzing/argv_fuzz_demo.c b/utils/argv_fuzzing/argv_fuzz_demo.c
new file mode 100644
index 00000000..6ab1e2e5
--- /dev/null
+++ b/utils/argv_fuzzing/argv_fuzz_demo.c
@@ -0,0 +1,28 @@
+#include <stdio.h>
+#include <string.h>
+#include "argv-fuzz-inl.h"
+
+int main(int argc, char **argv) {
+
+ // Initialize the argv array for use with the AFL (American Fuzzy Lop) tool
+ AFL_INIT_ARGV();
+
+ /* Check the number of command line arguments and
+ compare the values of the first two arguments to specific strings.
+ If the number of arguments is not correct or the values do not match,
+ an error message is printed. If the values do match, the program
+ calls the abort() function. */
+ if (argc > 1 && strcmp(argv[1], "XYZ") == 0) {
+
+ if (strcmp(argv[2], "TEST2") == 0) { abort(); }
+
+ } else {
+
+ printf("Bad number of arguments!\n");
+
+ }
+
+ return 0;
+
+}
+
diff --git a/utils/argv_fuzzing/argv_fuzz_persistent_demo.c b/utils/argv_fuzzing/argv_fuzz_persistent_demo.c
new file mode 100644
index 00000000..016c3d35
--- /dev/null
+++ b/utils/argv_fuzzing/argv_fuzz_persistent_demo.c
@@ -0,0 +1,59 @@
+/*
+This file contains a simple fuzzer for testing command line argument parsing
+using persistent mode.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include "argv-fuzz-inl.h"
+
+__AFL_FUZZ_INIT();
+
+/* The main function is an entry point for a program.
+ The argc parameter is an integer that indicates the number of arguments
+ passed to the program. The argv parameter is an array of character pointers,
+ with each element pointing to a null-terminated string that represents
+ one of the arguments.
+ */
+int main(int argc, char **argv) {
+
+#ifdef __AFL_HAVE_MANUAL_CONTROL
+ __AFL_INIT();
+#endif
+ unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF;
+
+ /* __AFL_LOOP() limits the maximum number of iterations before exiting
+ the loop and allowing the program to terminate. It protects against
+ accidental memory leaks and similar issues. */
+ while (__AFL_LOOP(100000)) {
+
+ int len = __AFL_FUZZ_TESTCASE_LEN;
+
+ // Check that the length of the test case is at least 8 bytes
+ if (len < 8) continue;
+
+ // Initialize the command line arguments using the testcase buffer
+ AFL_INIT_ARGV_PERSISTENT(buf);
+
+ /* Check if the first argument is "XYZ" and the second argument is "TEST2"
+ If so, call the "abort" function to terminate the program.
+ Otherwise, print an error message. */
+ if (argc > 1 && strcmp(argv[1], "XYZ") == 0) {
+
+ if (strcmp(argv[2], "TEST2") == 0) { abort(); }
+
+ } else {
+
+ printf("Bad number of arguments!\n");
+
+ }
+
+ }
+
+ /* Exiting the loop allows the program to terminate normally. AFL will restart
+ the process with a clean slate for allocated memory, file descriptors, etc.
+ */
+ return 0;
+
+}
+
diff --git a/utils/argv_fuzzing/argvfuzz.c b/utils/argv_fuzzing/argvfuzz.c
index e7cc6b72..41eead0c 100644
--- a/utils/argv_fuzzing/argvfuzz.c
+++ b/utils/argv_fuzzing/argvfuzz.c
@@ -2,7 +2,7 @@
american fuzzy lop++ - LD_PRELOAD for fuzzing argv in binaries
------------------------------------------------------------
- Copyright 2019-2022 Kjell Braden <afflux@pentabarf.de>
+ Copyright 2019-2023 Kjell Braden <afflux@pentabarf.de>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/utils/distributed_fuzzing/sync_script.sh b/utils/distributed_fuzzing/sync_script.sh
index 251ae4e6..b22816f1 100755
--- a/utils/distributed_fuzzing/sync_script.sh
+++ b/utils/distributed_fuzzing/sync_script.sh
@@ -6,7 +6,7 @@
# Originally written by Michal Zalewski
#
# Copyright 2014 Google Inc. All rights reserved.
-# Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+# Copyright 2019-2023 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.
diff --git a/utils/libdislocator/README.md b/utils/libdislocator/README.md
index e4934b5d..d0e45fff 100644
--- a/utils/libdislocator/README.md
+++ b/utils/libdislocator/README.md
@@ -34,8 +34,8 @@ heap-related security bugs in several ways:
- Size alignment to `max_align_t` can be enforced with `AFL_ALIGNED_ALLOC=1`. In
this case, a tail canary is inserted in the padding bytes at the end of the
- allocated zone. This reduce the ability of libdislocator to detect
- off-by-one bugs but also it make slibdislocator compliant to the C standard.
+ allocated zone. This reduces the ability of libdislocator to detect
+ off-by-one bugs but also it makes libdislocator compliant to the C standard.
Basically, it is inspired by some of the non-default options available for the
OpenBSD allocator - see malloc.conf(5) on that platform for reference. It is
diff --git a/utils/libdislocator/libdislocator.so.c b/utils/libdislocator/libdislocator.so.c
index bd08a678..1cd7abc6 100644
--- a/utils/libdislocator/libdislocator.so.c
+++ b/utils/libdislocator/libdislocator.so.c
@@ -6,7 +6,7 @@
Originally written by Michal Zalewski
Copyright 2016 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -171,7 +171,7 @@ static u32 alloc_canary;
static void *__dislocator_alloc(size_t len) {
- u8 * ret, *base;
+ u8 *ret, *base;
size_t tlen;
int flags, protflags, fd, sp;
@@ -304,7 +304,8 @@ static void *__dislocator_alloc(size_t len) {
/* The "user-facing" wrapper for calloc(). This just checks for overflows and
displays debug messages if requested. */
-void *calloc(size_t elem_len, size_t elem_cnt) {
+__attribute__((malloc)) __attribute__((alloc_size(1, 2))) void *calloc(
+ size_t elem_len, size_t elem_cnt) {
void *ret;
@@ -339,7 +340,8 @@ void *calloc(size_t elem_len, size_t elem_cnt) {
memory (unlike calloc(), malloc() is not guaranteed to return zeroed
memory). */
-void *malloc(size_t len) {
+__attribute__((malloc)) __attribute__((alloc_size(1))) void *malloc(
+ size_t len) {
void *ret;
@@ -398,7 +400,7 @@ void free(void *ptr) {
/* Realloc is pretty straightforward, too. We forcibly reallocate the buffer,
move data, and then free (aka mprotect()) the original one. */
-void *realloc(void *ptr, size_t len) {
+__attribute__((alloc_size(2))) void *realloc(void *ptr, size_t len) {
void *ret;
@@ -450,7 +452,8 @@ int posix_memalign(void **ptr, size_t align, size_t len) {
/* just the non-posix fashion */
-void *memalign(size_t align, size_t len) {
+__attribute__((malloc)) __attribute__((alloc_size(2))) void *memalign(
+ size_t align, size_t len) {
void *ret = NULL;
@@ -466,7 +469,8 @@ void *memalign(size_t align, size_t len) {
/* sort of C11 alias of memalign only more severe, alignment-wise */
-void *aligned_alloc(size_t align, size_t len) {
+__attribute__((malloc)) __attribute__((alloc_size(2))) void *aligned_alloc(
+ size_t align, size_t len) {
void *ret = NULL;
@@ -484,11 +488,12 @@ void *aligned_alloc(size_t align, size_t len) {
/* specific BSD api mainly checking possible overflow for the size */
-void *reallocarray(void *ptr, size_t elem_len, size_t elem_cnt) {
+__attribute__((alloc_size(2, 3))) void *reallocarray(void *ptr, size_t elem_len,
+ size_t elem_cnt) {
const size_t elem_lim = 1UL << (sizeof(size_t) * 4);
const size_t elem_tot = elem_len * elem_cnt;
- void * ret = NULL;
+ void *ret = NULL;
if ((elem_len >= elem_lim || elem_cnt >= elem_lim) && elem_len > 0 &&
elem_cnt > (SIZE_MAX / elem_len)) {
@@ -505,7 +510,28 @@ void *reallocarray(void *ptr, size_t elem_len, size_t elem_cnt) {
}
-#if !defined(__ANDROID__)
+int reallocarr(void *ptr, size_t elem_len, size_t elem_cnt) {
+
+ void *ret = NULL;
+ const size_t elem_tot = elem_len * elem_cnt;
+
+ if (elem_tot == 0) {
+
+ void **h = &ptr;
+ *h = ret;
+ return 0;
+
+ }
+
+ ret = reallocarray(ptr, elem_len, elem_cnt);
+ return ret ? 0 : -1;
+
+}
+
+#if defined(__APPLE__)
+size_t malloc_size(const void *ptr) {
+
+#elif !defined(__ANDROID__)
size_t malloc_usable_size(void *ptr) {
#else
@@ -517,13 +543,22 @@ size_t malloc_usable_size(const void *ptr) {
}
+#if defined(__APPLE__)
+size_t malloc_good_size(size_t len) {
+
+ return (len & ~(ALLOC_ALIGN_SIZE - 1)) + ALLOC_ALIGN_SIZE;
+
+}
+
+#endif
+
__attribute__((constructor)) void __dislocator_init(void) {
char *tmp = getenv("AFL_LD_LIMIT_MB");
if (tmp) {
- char * tok;
+ char *tok;
unsigned long long mmem = strtoull(tmp, &tok, 10);
if (*tok != '\0' || errno == ERANGE || mmem > SIZE_MAX / 1024 / 1024)
FATAL("Bad value for AFL_LD_LIMIT_MB");
diff --git a/utils/libtokencap/README.md b/utils/libtokencap/README.md
index 50104291..8705452c 100644
--- a/utils/libtokencap/README.md
+++ b/utils/libtokencap/README.md
@@ -47,9 +47,11 @@ by AFL++ in that earlier run. This demonstrates the basic principle:
```
export AFL_TOKEN_FILE=$PWD/temp_output.txt
+ timeout_sec="5"
for i in <out_dir>/queue/id*; do
LD_PRELOAD=/path/to/libtokencap.so \
+ timeout -s SIGKILL ${timeout_sec} \
/path/to/target/program [...params, including $i...]
done
diff --git a/utils/libtokencap/libtokencap.so.c b/utils/libtokencap/libtokencap.so.c
index 71c30eed..b21f3068 100644
--- a/utils/libtokencap/libtokencap.so.c
+++ b/utils/libtokencap/libtokencap.so.c
@@ -6,7 +6,7 @@
Originally written by Michal Zalewski
Copyright 2016 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -81,7 +81,11 @@ void *(*__libc_memmem)(const void *haystack, size_t haystack_len,
#define MAX_MAPPINGS 1024
-static struct mapping { void *st, *en; } __tokencap_ro[MAX_MAPPINGS];
+static struct mapping {
+
+ void *st, *en;
+
+} __tokencap_ro[MAX_MAPPINGS];
static u32 __tokencap_ro_cnt;
static u8 __tokencap_ro_loaded;
@@ -171,7 +175,7 @@ static void __tokencap_load_mappings(void) {
int mib[] = {CTL_VM, VM_PROC, VM_PROC_MAP, __tokencap_pid,
sizeof(struct kinfo_vmentry)};
#endif
- char * buf, *low, *high;
+ char *buf, *low, *high;
size_t miblen = sizeof(mib) / sizeof(mib[0]);
size_t len;
@@ -354,7 +358,7 @@ static void __tokencap_dump(const u8 *ptr, size_t len, u8 is_text) {
#undef strcmp
-int strcmp(const char *str1, const char *str2) {
+__attribute__((hot)) int strcmp(const char *str1, const char *str2) {
if (__tokencap_is_ro(str1)) __tokencap_dump(str1, strlen(str1), 1);
if (__tokencap_is_ro(str2)) __tokencap_dump(str2, strlen(str2), 1);
@@ -378,7 +382,8 @@ int strcmp(const char *str1, const char *str2) {
#undef strncmp
-int strncmp(const char *str1, const char *str2, size_t len) {
+__attribute__((hot)) int strncmp(const char *str1, const char *str2,
+ size_t len) {
if (__tokencap_is_ro(str1)) __tokencap_dump(str1, len, 1);
if (__tokencap_is_ro(str2)) __tokencap_dump(str2, len, 1);
@@ -404,7 +409,7 @@ int strncmp(const char *str1, const char *str2, size_t len) {
#undef strcasecmp
-int strcasecmp(const char *str1, const char *str2) {
+__attribute__((hot)) int strcasecmp(const char *str1, const char *str2) {
if (__tokencap_is_ro(str1)) __tokencap_dump(str1, strlen(str1), 1);
if (__tokencap_is_ro(str2)) __tokencap_dump(str2, strlen(str2), 1);
@@ -428,7 +433,8 @@ int strcasecmp(const char *str1, const char *str2) {
#undef strncasecmp
-int strncasecmp(const char *str1, const char *str2, size_t len) {
+__attribute__((hot)) int strncasecmp(const char *str1, const char *str2,
+ size_t len) {
if (__tokencap_is_ro(str1)) __tokencap_dump(str1, len, 1);
if (__tokencap_is_ro(str2)) __tokencap_dump(str2, len, 1);
@@ -454,7 +460,8 @@ int strncasecmp(const char *str1, const char *str2, size_t len) {
#undef memcmp
-int memcmp(const void *mem1, const void *mem2, size_t len) {
+__attribute__((hot)) int memcmp(const void *mem1, const void *mem2,
+ size_t len) {
if (__tokencap_is_ro(mem1)) __tokencap_dump(mem1, len, 0);
if (__tokencap_is_ro(mem2)) __tokencap_dump(mem2, len, 0);
@@ -481,7 +488,7 @@ int memcmp(const void *mem1, const void *mem2, size_t len) {
#undef bcmp
-int bcmp(const void *mem1, const void *mem2, size_t len) {
+__attribute__((hot)) int bcmp(const void *mem1, const void *mem2, size_t len) {
if (__tokencap_is_ro(mem1)) __tokencap_dump(mem1, len, 0);
if (__tokencap_is_ro(mem2)) __tokencap_dump(mem2, len, 0);
@@ -508,7 +515,7 @@ int bcmp(const void *mem1, const void *mem2, size_t len) {
#undef strstr
-char *strstr(const char *haystack, const char *needle) {
+__attribute__((hot)) char *strstr(const char *haystack, const char *needle) {
if (__tokencap_is_ro(haystack))
__tokencap_dump(haystack, strlen(haystack), 1);
@@ -537,7 +544,8 @@ char *strstr(const char *haystack, const char *needle) {
#undef strcasestr
-char *strcasestr(const char *haystack, const char *needle) {
+__attribute__((hot)) char *strcasestr(const char *haystack,
+ const char *needle) {
if (__tokencap_is_ro(haystack))
__tokencap_dump(haystack, strlen(haystack), 1);
@@ -566,8 +574,8 @@ char *strcasestr(const char *haystack, const char *needle) {
#undef memmem
-void *memmem(const void *haystack, size_t haystack_len, const void *needle,
- size_t needle_len) {
+__attribute__((hot)) void *memmem(const void *haystack, size_t haystack_len,
+ const void *needle, size_t needle_len) {
if (__tokencap_is_ro(haystack)) __tokencap_dump(haystack, haystack_len, 1);
diff --git a/utils/persistent_mode/test-instr.c b/utils/persistent_mode/test-instr.c
index 168aa429..4ead6577 100644
--- a/utils/persistent_mode/test-instr.c
+++ b/utils/persistent_mode/test-instr.c
@@ -3,7 +3,7 @@
--------------------------------------------------------
Originally written by Michal Zalewski
Copyright 2014 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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:
diff --git a/utils/qbdi_mode/template.cpp b/utils/qbdi_mode/template.cpp
index 182a014b..3630ae3f 100755
--- a/utils/qbdi_mode/template.cpp
+++ b/utils/qbdi_mode/template.cpp
@@ -123,7 +123,7 @@ void afl_maybe_log(unsigned long cur_loc) {
char *read_file(char *path, unsigned long *length) {
unsigned long len;
- char * buf;
+ char *buf;
FILE *fp = fopen(path, "rb");
fseek(fp, 0, SEEK_END);
@@ -142,7 +142,7 @@ QBDI_NOINLINE int fuzz_func() {
if (afl_setup()) { afl_forkserver(); }
unsigned long len = 0;
- char * data = read_file(input_pathname, &len);
+ char *data = read_file(input_pathname, &len);
// printf("In fuzz_func\n");
p_target_func(data, len);
@@ -152,7 +152,7 @@ QBDI_NOINLINE int fuzz_func() {
static QBDI::VMAction bbcallback(QBDI::VMInstanceRef vm,
const QBDI::VMState *state,
- QBDI::GPRState * gprState,
+ QBDI::GPRState *gprState,
QBDI::FPRState *fprState, void *data) {
// errno = SAVED_ERRNO;
diff --git a/utils/socket_fuzzing/socketfuzz.c b/utils/socket_fuzzing/socketfuzz.c
index 3ec8383b..7497519e 100644
--- a/utils/socket_fuzzing/socketfuzz.c
+++ b/utils/socket_fuzzing/socketfuzz.c
@@ -23,7 +23,8 @@
#include <errno.h>
#include <stdio.h>
#include <poll.h>
-//#include "logging.h" // switche from preeny_info() to fprintf(stderr, "Info: "
+// #include "logging.h" // switched from preeny_info() to fprintf(stderr, "Info:
+// "
//
// originals
diff --git a/utils/target_intelligence/README.md b/utils/target_intelligence/README.md
new file mode 100644
index 00000000..086c9e20
--- /dev/null
+++ b/utils/target_intelligence/README.md
@@ -0,0 +1,61 @@
+# Target Intelligence
+
+These are some ideas you can do so that your target that you are fuzzing can
+give helpful feedback to AFL++.
+
+## Add to the AFL++ dictionary from your target
+
+For this you target must be compiled for CMPLOG (`AFL_LLVM_CMPLOG=1`).
+
+Add in your source code:
+
+```
+__attribute__((weak)) void __cmplog_rtn_hook_strn(u8 *ptr1, u8 *ptr2, u64 len);
+__attribute__((weak)) void __cmplog_ins_hook1(uint8_t arg1, uint8_t arg2, uint8_t attr);
+__attribute__((weak)) void __cmplog_ins_hook2(uint16_t arg1, uint16_t arg2, uint8_t attr);
+__attribute__((weak)) void __cmplog_ins_hook4(uint32_t arg1, uint32_t arg2, uint8_t attr);
+__attribute__((weak)) void __cmplog_ins_hook8(uint64_t arg1, uint64_t arg2, uint8_t attr);
+
+int in_your_function(...) {
+
+ // to add two strings to the AFL++ dictionary:
+ if (__cmplog_rtn_hook_strn)
+ __cmplog_rtn_hook_strn(string1, length_of_string1, string2, length_of_string2);
+
+ // to add two 32 bit integers to the AFL++ dictionary:
+ if (__cmplog_ins_hook4)
+ __cmplog_ins_hook4(first_32_bit_var, second_32_bit_var, 0);
+
+}
+```
+
+Note that this only makes sense if these values are in-depth processed in the
+target in a way that AFL++ CMPLOG cannot uncover these, e.g. if these values
+are transformed by a matrix computation.
+
+Fixed values are always better to give to afl-fuzz via a `-x dictionary`.
+
+## Add inputs to AFL++ dictionary from your target
+
+If for whatever reason you want your target to propose new inputs to AFL++,
+then this is actually very easy.
+The environment variable `AFL_CUSTOM_INFO_OUT` contains the output directory
+of this run - including the fuzzer instance name (e.g. `default`), so if you
+run `afl-fuzz -o out -S foobar`, the value would be `out/foobar`).
+
+To show afl-fuzz an input it should consider just do the following:
+
+1. create the directory `$AFL_CUSTOM_INFO_OUT/../target/queue`
+2. create any new inputs you want afl-fuzz to notice in that directory with the
+ following naming convention: `id:NUMBER-OF-LENGTH-SIX-WITH-LEADING-ZEROES,whatever`
+ where that number has to be increasing.
+ e.g.:
+```
+ id:000000,first_file
+ id:000001,second_file
+ id:000002,third_file
+ etc.
+```
+
+Note that this will not work in nyx_mode because afl-fuzz cannot see inside the
+virtual machine.