Compare commits

..

5 Commits

Author SHA1 Message Date
5ebb0df444 more stability 2020-07-04 10:44:38 +02:00
0eca7a4f73 small fix 2020-07-03 23:51:33 +02:00
1bee082739 notify afl-fuzz about variadic map 2020-07-03 23:41:02 +02:00
bac6c7891d variadic map size 2020-07-03 23:34:18 +02:00
8b065725cc edges instrumentation at branch link time 2020-07-03 23:07:35 +02:00
821 changed files with 31060 additions and 127339 deletions

View File

@ -3,10 +3,10 @@
# american fuzzy lop++ - custom code formatter
# --------------------------------------------
#
# Written and maintained by Andrea Fioraldi <andreafioraldi@gmail.com>
# Written and maintaned by Andrea Fioraldi <andreafioraldi@gmail.com>
#
# Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
# Copyright 2019-2023 AFLplusplus Project. All rights reserved.
# Copyright 2019-2020 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,57 +18,41 @@
import subprocess
import sys
import os
# 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', 14)
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(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
import re
# string_re = re.compile('(\\"(\\\\.|[^"\\\\])*\\")') # future use
with open(".clang-format") as f:
fmt = f.read()
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")
CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN")
if CLANG_FORMAT_BIN is None:
o = 0
try:
p = subprocess.Popen(["clang-format-10", "--version"], stdout=subprocess.PIPE)
o, _ = p.communicate()
o = str(o, "utf-8")
o = o[len("clang-format version "):].strip()
o = o[:o.find(".")]
o = int(o)
except:
print ("clang-format-10 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-10'], stdout=subprocess.PIPE) == 0:
# CLANG_FORMAT_BIN = 'clang-format-10'
# else:
# print ("clang-format 7 or above is needed. Aborted.")
# exit(1)
else:
CLANG_FORMAT_BIN = 'clang-format-10'
COLUMN_LIMIT = 80
for line in fmt.split("\n"):
line = line.split(":")
@ -84,47 +68,26 @@ def custom_format(filename):
in_define = False
last_line = None
out = ""
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)
):
if "/*" 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 = 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() != ""
):
if 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() != ""
):
elif 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() != ""
):
elif line.strip().startswith("}") and last_line is not None and last_line.strip() != "":
line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
if not line.endswith("\\"):
@ -133,15 +96,14 @@ def custom_format(filename):
out += line + "\n"
last_line = line
return out
return (out)
args = sys.argv[1:]
if len(args) == 0:
print("Usage: ./format.py [-i] <filename>")
print()
print(" The -i option, if specified, let the script to modify in-place")
print(" the source files. By default the results are written to stdout.")
print ("Usage: ./format.py [-i] <filename>")
print ()
print (" The -i option, if specified, let the script to modify in-place")
print (" the source files. By default the results are written to stdout.")
print()
exit(1)
@ -157,3 +119,4 @@ for filename in args:
f.write(code)
else:
print(code)

View File

@ -1,75 +0,0 @@
!/coresight_mode
*.dSYM
*.o
*.pyc
*.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-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-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-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-*
test/unittests/unit_hash
test/unittests/unit_list
test/unittests/unit_maybe_alloc
test/unittests/unit_preallocable
test/unittests/unit_rand
unicorn_mode/samples/*/\.test-*
unicorn_mode/samples/*/output
unicorn_mode/unicornafl

13
.github/FUNDING.yml vendored
View File

@ -1,13 +0,0 @@
# These are supported funding model platforms
# Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
github: AFLplusplus
patreon: # Replace with a single Patreon username
open_collective: AFLplusplusEU
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@ -1,32 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**IMPORTANT**
1. You have verified that the issue to be present in the current `dev` branch.
2. Please supply the command line options and relevant environment variables,
e.g., a copy-paste of the contents of `out/default/fuzzer_setup`.
Thank you for making AFL++ better!
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. ...
2. ...
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screen output/Screenshots**
If applicable, add copy-paste of the screen output or screenshot that shows the issue. Please ensure the output is in **English** and not in Chinese, Russian, German, etc.
**Additional context**
Add any other context about the problem here.

View File

@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -1,56 +0,0 @@
name: CI
on:
push:
branches:
- stable
- dev
pull_request:
branches:
- dev # No need for stable-pull-request, as that equals dev-push
jobs:
linux:
runs-on: "${{ matrix.os }}"
strategy:
matrix:
os: [ubuntu-22.04, ubuntu-20.04, ubuntu-18.04]
env:
AFL_SKIP_CPUFREQ: 1
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
steps:
- 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
- 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
- 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
- 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@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

View File

@ -1,33 +0,0 @@
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

View File

@ -1,33 +0,0 @@
name: "CodeQL"
on:
push:
branches:
- stable
- dev
pull_request:
branches:
- dev # No need for stable-pull-request, as that equals dev-push
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
container: # We use a previous image as it's expected to have all the dependencies
image: docker.io/aflplusplus/aflplusplus:dev
steps:
- 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

View File

@ -1,75 +0,0 @@
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

View File

@ -1,33 +0,0 @@
name: Rust Custom Mutators
on:
push:
branches:
- stable
- dev
pull_request:
branches:
- dev # No need for stable-pull-request, as that equals dev-push
jobs:
test:
name: Test Rust Custom Mutator Support
runs-on: '${{ matrix.os }}'
defaults:
run:
working-directory: custom_mutators/rust
strategy:
matrix:
os: [ubuntu-22.04, ubuntu-20.04]
steps:
- uses: actions/checkout@v3
- name: Install Rust Toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Check Code Compiles
run: cargo check
- name: Run General Tests
run: cargo test
- name: Run Tests for afl_internals feature flag
run: cd custom_mutator && cargo test --features=afl_internals

51
.gitignore vendored
View File

@ -1,19 +1,8 @@
.test
.test2
.sync_tmp
.vscode
*.o
*.so
*.swp
*.pyc
*.dSYM
as
a.out
ld
in
out
core*
compile_commands.json
afl-analyze
afl-as
afl-clang
@ -30,7 +19,6 @@ afl-g++-fast
afl-gotcpu
afl-ld
afl-ld-lto
afl-cs-proxy
afl-qemu-trace
afl-showmap
afl-tmin
@ -43,10 +31,7 @@ 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
@ -55,18 +40,14 @@ afl-showmap.8
afl-system-config.8
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
as
ld
qemu_mode/qemu-*
qemu_mode/qemuafl
unicorn_mode/samples/*/\.test-*
unicorn_mode/samples/*/output/
unicorn_mode/unicornafl
core\.*
test/unittests/unit_maybe_alloc
test/unittests/unit_preallocable
test/unittests/unit_list
@ -74,27 +55,3 @@ 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
examples/aflpp_driver/libAFLDriver.a
examples/aflpp_driver/libAFLQemuDriver.a
libAFLDriver.a
libAFLQemuDriver.a
test/.afl_performance
gmon.out
afl-frida-trace.so
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
vuln_prog

26
.gitmodules vendored
View File

@ -1,27 +1,3 @@
[submodule "unicorn_mode/unicornafl"]
path = unicorn_mode/unicornafl
url = https://github.com/AFLplusplus/unicornafl
[submodule "custom_mutators/grammar_mutator"]
path = custom_mutators/grammar_mutator/grammar_mutator
url = https://github.com/AFLplusplus/Grammar-Mutator
[submodule "qemu_mode/qemuafl"]
path = qemu_mode/qemuafl
url = https://github.com/AFLplusplus/qemuafl
[submodule "custom_mutators/gramatron/json-c"]
path = custom_mutators/gramatron/json-c
url = https://github.com/json-c/json-c
[submodule "coresight_mode/patchelf"]
path = coresight_mode/patchelf
url = https://github.com/NixOS/patchelf.git
[submodule "coresight_mode/coresight-trace"]
path = coresight_mode/coresight-trace
url = https://github.com/RICSecLab/coresight-trace.git
[submodule "nyx_mode/libnyx"]
path = nyx_mode/libnyx
url = https://github.com/nyx-fuzz/libnyx.git
[submodule "nyx_mode/QEMU-Nyx"]
path = nyx_mode/QEMU-Nyx
url = https://github.com/nyx-fuzz/qemu-nyx.git
[submodule "nyx_mode/packer"]
path = nyx_mode/packer
url = https://github.com/nyx-fuzz/packer.git
url = https://github.com/AFLplusplus/unicornafl.git

58
.travis.yml Normal file
View File

@ -0,0 +1,58 @@
language: c
sudo: required
branches:
only:
- master
- dev
matrix:
include:
# - os: linux # focal errors every run with a timeout while installing packages
# dist: focal
# env: NAME="focal-amd64" MODERN="yes" GCC="9"
- os: linux
dist: bionic
env: NAME="bionic-amd64" MODERN="yes" GCC="7"
- os: linux
dist: xenial
env: NAME="xenial-amd64" MODERN="no" GCC="5" EXTRA="libtool-bin clang-6.0"
- os: linux
dist: trusty
env: NAME="trusty-amd64" MODERN="no" GCC="4.8"
# - os: linux # until travis can fix this!
# dist: xenial
# arch: arm64
# env: NAME="xenial-arm64" MODERN="no" GCC="5" EXTRA="libtool-bin clang-6.0" AFL_NO_X86="1" CPU_TARGET="aarch64"
# - os: osx
# osx_image: xcode11.2
# env: NAME="osx" HOMEBREW_NO_ANALYTICS="1" LINK="http://releases.llvm.org/9.0.0/" NAME="clang+llvm-9.0.0-x86_64-darwin-apple"
jobs:
allow_failures:
- os: osx
- arch: arm64
env:
- AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 AFL_NO_UI=1
# - AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 AFL_NO_UI=1 AFL_EXIT_WHEN_DONE=1
# TODO: test AFL_BENCH_UNTIL_CRASH once we have a target that crashes
# - AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 AFL_NO_UI=1 AFL_BENCH_JUST_ONE=1
before_install:
# export LLVM_DIR=${TRAVIS_BUILD_DIR}/${LLVM_PACKAGE}
- echo Testing on $NAME
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then wget "$LINK""$NAME".tar.xz ; export LLVM_CONFIG=`pwd`/"$NAME" ; tar xJf "$NAME".tar.xz ; fi
- if [ "$MODERN" = "yes" ]; then sudo apt update ; sudo apt upgrade ; sudo apt install -y git libtool libtool-bin automake bison libglib2.0-0 build-essential clang gcc-"$GCC" gcc-"$GCC"-plugin-dev libc++-"$GCC"-dev findutils libcmocka-dev python3-setuptools ; fi
- if [ "$MODERN" = "no" ]; then sudo apt update ; sudo apt install -y git libtool $EXTRA libpixman-1-dev automake bison libglib2.0 build-essential gcc-"$GCC" gcc-"$GCC"-plugin-dev libc++-dev findutils libcmocka-dev python3-setuptools ; fi
script:
- gcc -v
- clang -v
- sudo -E ./afl-system-config
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then export LLVM_CONFIG=`pwd`/"$NAME" ; make source-only ASAN_BUILD=1 ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" -a "$TRAVIS_CPU_ARCH" = "amd64" ]; then make distrib ASAN_BUILD=1 ; fi
- if [ "$TRAVIS_CPU_ARCH" = "arm64" ] ; then echo DEBUG ; find / -name llvm-config.h 2>/dev/null; apt-cache search clang | grep clang- ; apt-cache search llvm | grep llvm- ; dpkg -l | egrep 'clang|llvm'; echo DEBUG ; export LLVM_CONFIG=llvm-config-6.0 ; make ASAN_BUILD=1 ; cd qemu_mode && sh ./build_qemu_support.sh ; cd .. ; fi
- make tests
# - travis_terminate 0

View File

@ -1,21 +1,7 @@
//
// NOTE: This file is outdated. None of the AFL++ team uses Android hence
// we need users to keep this updated.
// In the current state it will likely fail, please send fixes!
// Also, this should build frida_mode.
//
cc_defaults {
name: "afl-defaults",
local_include_dirs: [
"include",
"instrumentation",
],
cflags: [
"-flto=full",
"-funroll-loops",
"-Wno-pointer-sign",
"-Wno-pointer-arith",
@ -24,62 +10,24 @@ cc_defaults {
"-Wno-unused-function",
"-Wno-format",
"-Wno-user-defined-warnings",
"-DAFL_LLVM_USE_TRACE_PC=1",
"-DUSE_TRACE_PC=1",
"-DBIN_PATH=\"out/host/linux-x86/bin\"",
"-DDOC_PATH=\"out/host/linux-x86/shared/doc/afl\"",
"-D__USE_GNU",
"-DDEBUG_BUILD",
"-U_FORTIFY_SOURCE",
"-ggdb3",
"-g",
"-O0",
"-fno-omit-frame-pointer",
"-fPIC",
],
target: {
android_arm64: {
cflags: [
"-D__ANDROID__",
],
},
android_arm: {
cflags: [
"-D__ANDROID__",
],
},
android_x86_64: {
cflags: [
"-D__ANDROID__",
],
},
android_x86: {
cflags: [
"-D__ANDROID__",
],
},
},
}
cc_binary {
name: "afl-fuzz",
sanitize: {
never: true,
},
static_executable: true,
host_supported: true,
compile_multilib: "64",
defaults: [
"afl-defaults",
],
srcs: [
"src/afl-fuzz*.c",
"src/afl-common.c",
"src/afl-forkserver.c",
"src/afl-sharedmem.c",
"src/afl-forkserver.c",
"src/afl-performance.c",
"afl-fuzz.c",
],
}
@ -93,11 +41,7 @@ cc_binary {
],
srcs: [
"src/afl-showmap.c",
"src/afl-common.c",
"src/afl-sharedmem.c",
"src/afl-forkserver.c",
"src/afl-performance.c",
"afl-showmap.c",
],
}
@ -111,11 +55,7 @@ cc_binary {
],
srcs: [
"src/afl-tmin.c",
"src/afl-common.c",
"src/afl-sharedmem.c",
"src/afl-forkserver.c",
"src/afl-performance.c",
"afl-tmin.c",
],
}
@ -129,10 +69,7 @@ cc_binary {
],
srcs: [
"src/afl-analyze.c",
"src/afl-common.c",
"src/afl-sharedmem.c",
"src/afl-performance.c",
"afl-analyze.c",
],
}
@ -146,13 +83,12 @@ cc_binary {
],
srcs: [
"src/afl-gotcpu.c",
"src/afl-common.c",
"afl-gotcpu.c",
],
}
cc_binary_host {
name: "afl-cc",
name: "afl-clang-fast",
static_executable: true,
defaults: [
@ -160,172 +96,17 @@ cc_binary_host {
],
cflags: [
"-D__ANDROID__",
"-DAFL_PATH=\"out/host/linux-x86/lib64\"",
"-DAFL_CLANG_FLTO=\"-flto=full\"",
"-DUSE_BINDIR=1",
"-DLLVM_BINDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin\"",
"-DLLVM_LIBDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/lib64\"",
"-DCLANGPP_BIN=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/clang++\"",
"-DAFL_REAL_LD=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/ld.lld\"",
"-DLLVM_LTO=1",
"-DLLVM_MAJOR=11",
"-DLLVM_MINOR=2",
],
srcs: [
"src/afl-cc.c",
"src/afl-common.c",
],
symlinks: [
"afl-clang-fast",
"afl-clang-fast++",
],
}
cc_library_static {
name: "afl-compiler-rt",
compile_multilib: "64",
vendor_available: true,
host_supported: true,
recovery_available: true,
sdk_version: "9",
apex_available: [
"com.android.adbd",
"com.android.appsearch",
"com.android.art",
"com.android.bluetooth.updatable",
"com.android.cellbroadcast",
"com.android.conscrypt",
"com.android.extservices",
"com.android.cronet",
"com.android.neuralnetworks",
"com.android.media",
"com.android.media.swcodec",
"com.android.mediaprovider",
"com.android.permission",
"com.android.runtime",
"com.android.resolv",
"com.android.tethering",
"com.android.wifi",
"com.android.sdkext",
"com.android.os.statsd",
"//any",
],
defaults: [
"afl-defaults",
],
srcs: [
"instrumentation/afl-compiler-rt.o.c",
],
}
cc_library_headers {
name: "libafl_headers",
vendor_available: true,
host_supported: true,
export_include_dirs: [
"include",
"instrumentation",
],
}
/*
cc_prebuilt_library_static {
name: "libfrida-gum",
compile_multilib: "64",
strip: {
none: true,
},
srcs: [
"utils/afl_frida/android/libfrida-gum.a",
],
export_include_dirs: [
"utils/afl_frida/android",
],
}
cc_library_shared {
name: "libtestinstr",
srcs: [
"utils/afl_frida/libtestinstr.c",
],
cflags: [
"-O0",
"-fPIC",
],
}
cc_binary {
name: "afl-frida",
compile_multilib: "64",
defaults: [
"afl-defaults",
],
cflags: [
"-g",
"-O0",
"-Wno-format",
"-Wno-pointer-sign",
"-fpermissive",
"-fPIC",
],
static_libs: [
"afl-compiler-rt",
"libfrida-gum",
],
shared_libs: [
"libdl",
"liblog",
],
srcs: [
"utils/afl_frida/afl-frida.c",
],
local_include_dirs: [
"utils/afl_frida",
"utils/afl_frida/android",
],
}
*/
cc_binary {
name: "afl-fuzz-32",
sanitize: {
never: true,
},
host_supported: true,
compile_multilib: "32",
defaults: [
"afl-defaults",
],
srcs: [
"src/afl-fuzz*.c",
"src/afl-common.c",
"src/afl-sharedmem.c",
"src/afl-forkserver.c",
"src/afl-performance.c",
"llvm_mode/afl-clang-fast.c",
],
}
cc_binary_host {
name: "afl-cc-32",
compile_multilib: "32",
name: "afl-clang-fast++",
static_executable: true,
defaults: [
@ -333,87 +114,28 @@ cc_binary_host {
],
cflags: [
"-D__ANDROID__",
"-DAFL_PATH=\"out/host/linux-x86/lib64\"",
"-DAFL_CLANG_FLTO=\"-flto=full\"",
"-DUSE_BINDIR=1",
"-DLLVM_BINDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin\"",
"-DLLVM_LIBDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/lib64\"",
"-DCLANGPP_BIN=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/clang++\"",
"-DAFL_REAL_LD=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/ld.lld\"",
"-DLLVM_LTO=1",
"-DLLVM_MAJOR=11",
"-DLLVM_MINOR=2",
],
srcs: [
"src/afl-cc.c",
"src/afl-common.c",
],
symlinks: [
"afl-clang-fast-32",
"afl-clang-fast++-32",
"llvm_mode/afl-clang-fast.c",
],
}
cc_library_static {
name: "afl-compiler-rt-32",
compile_multilib: "32",
name: "afl-llvm-rt",
compile_multilib: "both",
vendor_available: true,
host_supported: true,
recovery_available: true,
sdk_version: "9",
apex_available: [
"com.android.adbd",
"com.android.appsearch",
"com.android.art",
"com.android.bluetooth.updatable",
"com.android.cellbroadcast",
"com.android.conscrypt",
"com.android.extservices",
"com.android.cronet",
"com.android.neuralnetworks",
"com.android.media",
"com.android.media.swcodec",
"com.android.mediaprovider",
"com.android.permission",
"com.android.runtime",
"com.android.resolv",
"com.android.tethering",
"com.android.wifi",
"com.android.sdkext",
"com.android.os.statsd",
"//any",
],
defaults: [
"afl-defaults",
],
srcs: [
"instrumentation/afl-compiler-rt.o.c",
"llvm_mode/afl-llvm-rt.o.c",
],
}
/*
cc_prebuilt_library_static {
name: "libfrida-gum-32",
compile_multilib: "32",
strip: {
none: true,
},
srcs: [
"utils/afl_frida/android/arm/libfrida-gum.a",
],
export_include_dirs: [
"utils/afl_frida/android/arm",
],
}
*/
subdirs = [
"custom_mutators",
]

1
Android.mk Symbolic link
View File

@ -0,0 +1 @@
Makefile

View File

@ -1,31 +0,0 @@
cff-version: 1.2.0
message: "If you use this software, please cite it as below."
authors:
- given-names: Marc
family-names: Heuse
email: mh@mh-sec.de
- given-names: Heiko
family-names: Eißfeldt
email: heiko.eissfeldt@hexco.de
- given-names: Andrea
family-names: Fioraldi
email: andreafioraldi@gmail.com
- given-names: Dominik
family-names: Maier
email: mail@dmnk.co
title: "AFL++"
version: 4.00c
type: software
date-released: 2022-01-26
url: "https://github.com/AFLplusplus/AFLplusplus"
keywords:
- fuzzing
- fuzzer
- fuzz-testing
- instrumentation
- afl-fuzz
- qemu
- llvm
- unicorn-emulator
- securiy
license: AGPL-3.0-or-later

View File

@ -1,8 +1,4 @@
# Contributing to AFL++
## How to submit a pull request
All contributions (pull requests) must be made against our `dev` branch.
# How to submit a Pull Request to AFLplusplus
Each modified source file, before merging, must be formatted.
@ -17,43 +13,10 @@ project, or added a file in a directory we already format, otherwise run:
./.custom-format.py -i file-that-you-have-created.c
```
Regarding the coding style, please follow the AFL style. No camel case at all
and use AFL's macros wherever possible (e.g., WARNF, FATAL, MAP_SIZE, ...).
Regarding the coding style, please follow the AFL style.
No camel case at all and use the AFL's macros wherever possible
(e.g. WARNF, FATAL, MAP_SIZE, ...).
Remember that AFL++ has to build and run on many platforms, so generalize your
Makefiles/GNUmakefile (or your patches to our pre-existing Makefiles) to be as
generic as possible.
## How to contribute to the docs
We welcome contributions to our docs.
Before creating a new file, please check if your content matches an existing
file in one the following folders:
* [docs/](docs/) (this is where you can find most of our docs content)
* [frida_mode/](frida_mode/)
* [instrumentation/](instrumentation/)
* [qemu_mode/](qemu_mode/)
* [unicorn_mode/](unicorn_mode/)
When working on the docs, please keep the following guidelines in mind:
* Edit or create Markdown files and use Markdown markup.
* Do: fuzzing_gui_program.md
* Don't: fuzzing_gui_program.txt
* Use underscore in file names.
* Do: fuzzing_network_service.md
* Don't: fuzzing-network-service.md
* Use a maximum of 80 characters per line to make reading in a console easier.
* Make all pull requests against `dev`, see
[#how-to-submit-a-pull-request-to-afl](#how-to-submit-a-pull-request-to-afl).
And finally, here are some best practices for writing docs content:
* Use clear and simple language.
* Structure your content with headings and paragraphs.
* Use bulleted lists to present similar content in a way that makes it easy to
scan.
* Use numbered lists for procedures or prioritizing.
* Link to related content, for example, prerequisites or in-depth discussions.
Remember that AFLplusplus has to build and run on many platforms, so
generalize your Makefiles (or your patches to our pre-existing Makefiles)
to be as much generic as possible.

View File

@ -1,95 +1,62 @@
#
# This Dockerfile for AFLplusplus uses Ubuntu 22.04 jammy and
# installs LLVM 14 for afl-clang-lto support.
#
# GCC 11 is used instead of 12 because genhtml for afl-cov doesn't like it.
# This Dockerfile for AFLplusplus uses Ubuntu 20.04 focal and
# installs LLVM 11 from llvm.org for afl-clang-lto support :-)
# It also installs gcc/g++ 10 from the Ubuntu development platform
# has focal has gcc-10 but not g++-10 ...
#
FROM ubuntu:22.04 AS aflplusplus
LABEL "maintainer"="afl++ team <afl@aflplus.plus>"
LABEL "about"="AFLplusplus container image"
### 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
### 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
### No changes beyond the point unless you know what you are doing :)
FROM ubuntu:20.04
MAINTAINER afl++ team <afl@aflplus.plus>
LABEL "about"="AFLplusplus docker image"
ARG DEBIAN_FRONTEND=noninteractive
ENV NO_ARCH_OPT=1
ENV IS_DOCKER=1
RUN apt-get update && apt-get upgrade -y && \
apt-get -y install --no-install-suggests --no-install-recommends \
automake \
bison flex \
build-essential \
git \
python3 python3-dev python3-setuptools python-is-python3 \
libtool libtool-bin \
libglib2.0-dev \
wget vim jupp nano \
apt-utils apt-transport-https ca-certificates gnupg dialog \
libpixman-1-dev
RUN apt-get update && apt-get full-upgrade -y && \
apt-get install -y --no-install-recommends wget ca-certificates apt-utils && \
rm -rf /var/lib/apt/lists/*
RUN echo deb http://apt.llvm.org/focal/ llvm-toolchain-focal main >> /etc/apt/sources.list && \
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
RUN echo deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu focal main >> /etc/apt/sources.list && \
apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 1E9377A2BA9EF27F
RUN apt-get update && apt-get upgrade -y
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 install -y gcc-10 g++-10 gcc-10-plugin-dev gcc-10-multilib \
libc++-10-dev gdb lcov
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-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 apt-get install -y clang-11 clang-tools-11 libc++1-11 libc++-11-dev \
libc++abi1-11 libc++abi-11-dev libclang1-11 libclang-11-dev \
libclang-common-11-dev libclang-cpp11 libclang-cpp11-dev liblld-11 \
liblld-11-dev liblldb-11 liblldb-11-dev libllvm11 libomp-11-dev \
libomp5-11 lld-11 lldb-11 llvm-11 llvm-11-dev llvm-11-runtime llvm-11-tools
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 update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 0
RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 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 rm -rf /var/cache/apt/archives/*
ARG CC=gcc-10
ARG CXX=g++-10
ARG LLVM_CONFIG=llvm-config-11
RUN git clone https://github.com/AFLplusplus/AFLplusplus
RUN cd AFLplusplus && export REAL_CXX=g++-10 && make distrib && \
make install && make clean
RUN git clone https://github.com/vanhauser-thc/afl-cov afl-cov
RUN cd afl-cov && make install
RUN echo 'alias joe="jupp --wordwrap"' >> ~/.bashrc
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 && \
(cd afl-cov && make install) && rm -rf afl-cov
WORKDIR /AFLplusplus
COPY . .
ARG CC=gcc-$GCC_VERSION
ARG CXX=g++-$GCC_VERSION
# Used in CI to prevent a 'make clean' which would remove the binaries to be tested
ARG TEST_BUILD
RUN sed -i.bak 's/^ -/ /g' GNUmakefile && \
make clean && make distrib && \
([ "${TEST_BUILD}" ] || (make install && make clean)) && \
mv GNUmakefile.bak GNUmakefile
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$(__git_ps1) \$ '"'" >> ~/.bashrc

View File

@ -10,7 +10,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
# https://www.apache.org/licenses/LICENSE-2.0
# http://www.apache.org/licenses/LICENSE-2.0
#
# For Heiko:
@ -24,44 +24,18 @@ BIN_PATH = $(PREFIX)/bin
HELPER_PATH = $(PREFIX)/lib/afl
DOC_PATH = $(PREFIX)/share/doc/afl
MISC_PATH = $(PREFIX)/share/afl
MAN_PATH = $(PREFIX)/share/man/man8
MAN_PATH = $(PREFIX)/man/man8
PROGNAME = afl
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
# PROGS intentionally omit afl-as, which gets installed elsewhere.
PROGS = afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-system-config afl-persistent-config afl-cc
PROGS = afl-gcc afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-system-config
MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8) afl-as.8
ASAN_OPTIONS=detect_leaks=0
SYS = $(shell uname -s)
ARCH = $(shell uname -m)
$(info [*] Compiling afl++ for OS $(SYS) on ARCH $(ARCH))
ifdef NO_SPLICING
override CFLAGS_OPT += -DNO_SPLICING
endif
ifdef ASAN_BUILD
$(info Compiling ASAN version of binaries)
override CFLAGS += $(ASAN_CFLAGS)
LDFLAGS += $(ASAN_LDFLAGS)
endif
ifdef UBSAN_BUILD
$(info Compiling UBSAN version of binaries)
override CFLAGS += -fsanitize=undefined -fno-omit-frame-pointer
override LDFLAGS += -fsanitize=undefined
endif
ifdef MSAN_BUILD
$(info Compiling MSAN version of binaries)
CC := clang
override CFLAGS += -fsanitize=memory -fno-omit-frame-pointer
override LDFLAGS += -fsanitize=memory
endif
ifeq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" ""
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
CFLAGS_FLTO ?= -flto=full
@ -76,41 +50,30 @@ else
endif
endif
#ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -fno-move-loop-invariants -fdisable-tree-cunrolli -x c - -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
# SPECIAL_PERFORMANCE += -fno-move-loop-invariants -fdisable-tree-cunrolli
#endif
#ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -march=native -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
# ifndef SOURCE_DATE_EPOCH
# HAVE_MARCHNATIVE = 1
# CFLAGS_OPT += -march=native
# endif
#endif
ifneq "$(SYS)" "Darwin"
#ifeq "$(HAVE_MARCHNATIVE)" "1"
# SPECIAL_PERFORMANCE += -march=native
#endif
ifndef DEBUG
CFLAGS_OPT += -D_FORTIFY_SOURCE=1
endif
else
# On some odd MacOS system configurations, the Xcode sdk path is not set correctly
SDK_LD = -L$(shell xcrun --show-sdk-path)/usr/lib
LDFLAGS += $(SDK_LD)
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -fno-move-loop-invariants -fdisable-tree-cunrolli -x c - -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
SPECIAL_PERFORMANCE += -fno-move-loop-invariants -fdisable-tree-cunrolli
endif
ifeq "$(SYS)" "SunOS"
CFLAGS_OPT += -Wno-format-truncation
LDFLAGS = -lkstat -lrt -lsocket -lnsl
ifneq "$(shell uname)" "Darwin"
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -march=native -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
#CFLAGS_OPT += -march=native
SPECIAL_PERFORMANCE += -march=native
endif
# OS X does not like _FORTIFY_SOURCE=2
CFLAGS_OPT += -D_FORTIFY_SOURCE=2
endif
ifeq "$(shell uname)" "SunOS"
CFLAGS_OPT += -Wno-format-truncation
LDFLAGS=-lkstat
endif
ifdef STATIC
$(info Compiling static version of binaries, disabling python though)
# Disable python for static compilation to simplify things
PYTHON_OK = 0
PYTHON_OK=0
PYFLAGS=
PYTHON_INCLUDE = /
PYTHON_INCLUDE=/
CFLAGS_OPT += -static
LDFLAGS += -lm -lpthread -lz -lutil
@ -118,62 +81,50 @@ endif
ifdef PROFILING
$(info Compiling with profiling information, for analysis: gprof ./afl-fuzz gmon.out > prof.txt)
override CFLAGS_OPT += -pg -DPROFILING=1
override LDFLAGS += -pg
CFLAGS_OPT += -pg -DPROFILING=1
LDFLAGS += -pg
endif
ifdef INTROSPECTION
$(info Compiling with introspection documentation)
override CFLAGS_OPT += -DINTROSPECTION=1
endif
ifneq "$(ARCH)" "x86_64"
ifneq "$(patsubst i%86,i386,$(ARCH))" "i386"
ifneq "$(ARCH)" "amd64"
ifneq "$(ARCH)" "i86pc"
ifneq "$(shell uname -m)" "x86_64"
ifneq "$(patsubst i%86,i386,$(shell uname -m))" "i386"
ifneq "$(shell uname -m)" "amd64"
ifneq "$(shell uname -m)" "i86pc"
AFL_NO_X86=1
endif
endif
endif
endif
ifdef DEBUG
$(info Compiling DEBUG version of binaries)
override CFLAGS += -ggdb3 -O0 -Wall -Wextra -Werror $(CFLAGS_OPT)
else
CFLAGS ?= -O2 $(CFLAGS_OPT) # -funroll-loops is slower on modern compilers
endif
CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT)
override CFLAGS += -Wall -g -Wno-pointer-sign -Wmissing-declarations\
-I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
-DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wno-pointer-arith \
-fPIC -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
-DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
# -fstack-protector
ifeq "$(SYS)" "FreeBSD"
ifeq "$(shell uname -s)" "FreeBSD"
override CFLAGS += -I /usr/local/include/
override LDFLAGS += -L /usr/local/lib/
LDFLAGS += -L /usr/local/lib/
endif
ifeq "$(SYS)" "DragonFly"
ifeq "$(shell uname -s)" "DragonFly"
override CFLAGS += -I /usr/local/include/
override LDFLAGS += -L /usr/local/lib/
LDFLAGS += -L /usr/local/lib/
endif
ifeq "$(SYS)" "OpenBSD"
ifeq "$(shell uname -s)" "OpenBSD"
override CFLAGS += -I /usr/local/include/ -mno-retpoline
override LDFLAGS += -Wl,-z,notext -L /usr/local/lib/
LDFLAGS += -Wl,-z,notext -L /usr/local/lib/
endif
ifeq "$(SYS)" "NetBSD"
ifeq "$(shell uname -s)" "NetBSD"
override CFLAGS += -I /usr/pkg/include/
override LDFLAGS += -L /usr/pkg/lib/
LDFLAGS += -L /usr/pkg/lib/
endif
ifeq "$(SYS)" "Haiku"
ifeq "$(shell uname -s)" "Haiku"
SHMAT_OK=0
override CFLAGS += -DUSEMMAP=1 -Wno-error=format
override LDFLAGS += -Wno-deprecated-declarations -lgnu -lnetwork
#SPECIAL_PERFORMANCE += -DUSEMMAP=1
override CFLAGS += -DUSEMMAP=1 -Wno-error=format -fPIC
LDFLAGS += -Wno-deprecated-declarations -lgnu
SPECIAL_PERFORMANCE += -DUSEMMAP=1
endif
AFL_FUZZ_FILES = $(wildcard src/afl-fuzz*.c)
@ -244,23 +195,24 @@ else
BUILD_DATE ?= $(shell date "+%Y-%m-%d")
endif
ifneq "$(filter Linux GNU%,$(SYS))" ""
override LDFLAGS += -ldl -lrt -lm
ifneq "$(filter Linux GNU%,$(shell uname))" ""
LDFLAGS += -ldl
endif
ifneq "$(findstring FreeBSD, $(SYS))" ""
ifneq "$(findstring FreeBSD, $(shell uname))" ""
override CFLAGS += -pthread
override LDFLAGS += -lpthread
LDFLAGS += -lpthread
endif
ifneq "$(findstring NetBSD, $(SYS))" ""
ifneq "$(findstring NetBSD, $(shell uname))" ""
override CFLAGS += -pthread
override LDFLAGS += -lpthread
LDFLAGS += -lpthread
endif
ifneq "$(findstring OpenBSD, $(SYS))" ""
override CFLAGS += -pthread
override LDFLAGS += -lpthread
ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
TEST_CC = afl-gcc
else
TEST_CC = afl-clang
endif
COMM_HDR = include/alloc-inl.h include/config.h include/debug.h include/types.h
@ -287,85 +239,57 @@ ifeq "$(shell command -v svn >/dev/null && svn proplist . 2>/dev/null && echo 1
endif
ifeq "$(shell echo 'int main() { return 0;}' | $(CC) $(CFLAGS) -fsanitize=address -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -DASAN_BUILD
ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
ASAN_LDFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
endif
ifdef ASAN_BUILD
$(info Compiling ASAN version of binaries)
override CFLAGS+=$(ASAN_CFLAGS)
LDFLAGS+=$(ASAN_LDFLAGS)
endif
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
SHMAT_OK=1
else
SHMAT_OK=0
override CFLAGS+=-DUSEMMAP=1
LDFLAGS += -Wno-deprecated-declarations
LDFLAGS += -Wno-deprecated-declarations -lrt
endif
ifdef TEST_MMAP
SHMAT_OK=0
override CFLAGS += -DUSEMMAP=1
LDFLAGS += -Wno-deprecated-declarations
LDFLAGS += -Wno-deprecated-declarations -lrt
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 build, 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 build, 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 build, 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
@echo
all: test_x86 test_shm test_python ready $(PROGS) afl-as test_build all_done
.PHONY: llvm
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
gcc_plugin:
ifneq "$(SYS)" "Darwin"
-$(MAKE) -f GNUmakefile.gcc_plugin
endif
.PHONY: man
man: $(MANPAGES)
.PHONY: test
test: tests
.PHONY: tests
tests: source-only
@cd test ; ./test-all.sh
@cd test ; ./test.sh
@rm -f test/errors
.PHONY: performance-tests
performance-tests: performance-test
.PHONY: test-performance
test-performance: performance-test
.PHONY: performance-test
performance-test: source-only
@cd test ; ./test-performance.sh
# hint: make targets are also listed in the top level README.md
.PHONY: help
help:
@echo "HELP --- the following make targets exist:"
@echo "=========================================="
@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 "all: just the main afl++ binaries"
@echo "binary-only: everything for binary-only fuzzing: qemu_mode, unicorn_mode, libdislocator, libtokencap"
@echo "source-only: everything for source code fuzzing: llvm_mode, gcc_plugin, libdislocator, libtokencap"
@echo "distrib: everything (for both binary-only and source code fuzzing)"
@echo "man: creates simple man pages from the help option of the programs"
@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 "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)"
@ -377,67 +301,72 @@ help:
@echo Known build environment options:
@echo "=========================================="
@echo STATIC - compile AFL++ static
@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 ASAN_BUILD - compiles with memory sanitizer for debug purposes
@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 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 "=========================================="
@echo e.g.: make ASAN_BUILD=1
.PHONY: test_x86
ifndef AFL_NO_X86
test_x86:
@echo "[*] Checking for the default compiler cc..."
@type $(CC) >/dev/null || ( echo; echo "Oops, looks like there is no compiler '"$(CC)"' in your path."; echo; echo "Don't panic! You can restart with '"$(_)" CC=<yourCcompiler>'."; echo; exit 1 )
@echo "[*] Testing the PATH environment variable..."
@test "$${PATH}" != "$${PATH#.:}" && { echo "Please remove current directory '.' from PATH to avoid recursion of 'as', thanks!"; echo; exit 1; } || :
@echo "[*] Checking for the ability to compile x86 code..."
@echo 'int main() { __asm__("xorb %al, %al"); }' | $(CC) $(CFLAGS) $(LDFLAGS) -w -x c - -o .test1 || ( echo; echo "Oops, looks like your compiler can't generate x86 code."; echo; echo "Don't panic! You can use the LLVM or QEMU mode, but see docs/INSTALL first."; echo "(To ignore this error, set AFL_NO_X86=1 and try again.)"; echo; exit 1 )
@echo 'main() { __asm__("xorb %al, %al"); }' | $(CC) $(CFLAGS) -w -x c - -o .test1 || ( echo; echo "Oops, looks like your compiler can't generate x86 code."; echo; echo "Don't panic! You can use the LLVM or QEMU mode, but see docs/INSTALL first."; echo "(To ignore this error, set AFL_NO_X86=1 and try again.)"; echo; exit 1 )
@rm -f .test1
else
test_x86:
@echo "[!] Note: skipping x86 compilation checks (AFL_NO_X86 set)."
endif
.PHONY: test_shm
ifeq "$(SHMAT_OK)" "1"
test_shm:
@echo "[+] shmat seems to be working."
@rm -f .test2
else
test_shm:
@echo "[-] shmat seems not to be working, switching to mmap implementation"
endif
.PHONY: test_python
ifeq "$(PYTHON_OK)" "1"
test_python:
@rm -f .test 2> /dev/null
@echo "[+] $(PYTHON_VERSION) support seems to be working."
else
test_python:
@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"
@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"
endif
.PHONY: ready
ready:
@echo "[+] Everything seems to be working, ready to compile."
afl-gcc: src/afl-gcc.c $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
set -e; for i in afl-g++ afl-clang afl-clang++; do ln -sf afl-gcc $$i; done
afl-as: src/afl-as.c include/afl-as.h $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
@ln -sf afl-as as
ln -sf afl-as as
src/afl-performance.o : $(COMM_HDR) src/afl-performance.c include/hash.h
$(CC) $(CFLAGS) $(CFLAGS_OPT) -Iinclude -c src/afl-performance.c -o src/afl-performance.o
$(CC) -Iinclude $(SPECIAL_PERFORMANCE) -O3 -fno-unroll-loops -c src/afl-performance.c -o src/afl-performance.o
src/afl-common.o : $(COMM_HDR) src/afl-common.c include/common.h
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-common.c -o src/afl-common.o
@ -449,25 +378,23 @@ src/afl-sharedmem.o : $(COMM_HDR) src/afl-sharedmem.c include/sharedmem.h
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-sharedmem.c -o src/afl-sharedmem.o
afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o | test_x86
$(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
$(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)
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)
afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.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 -o $@ $(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)
afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o src/afl-forkserver.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o src/afl-forkserver.o -o $@ $(LDFLAGS)
afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.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-performance.o -o $@ $(LDFLAGS)
afl-gotcpu: src/afl-gotcpu.c src/afl-common.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o -o $@ $(LDFLAGS)
.PHONY: document
document: afl-fuzz-document
# document all mutations and only do one run (use with only one input file!)
afl-fuzz-document: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-performance.o | test_x86
document: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-performance.o | test_x86
$(CC) -D_DEBUG=\"1\" -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.c src/afl-performance.o -o afl-fuzz-document $(PYFLAGS) $(LDFLAGS)
test/unittests/unit_maybe_alloc.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_maybe_alloc.c $(AFL_FUZZ_FILES)
@ -505,245 +432,126 @@ unit_preallocable: test/unittests/unit_preallocable.o
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_preallocable.o -o test/unittests/unit_preallocable $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
./test/unittests/unit_preallocable
.PHONY: unit_clean
unit_clean:
@rm -f ./test/unittests/unit_preallocable ./test/unittests/unit_list ./test/unittests/unit_maybe_alloc test/unittests/*.o
.PHONY: unit
ifneq "$(SYS)" "Darwin"
unit: unit_maybe_alloc unit_preallocable unit_list unit_clean unit_rand unit_hash
ifneq "$(shell uname)" "Darwin"
unit: unit_maybe_alloc unit_preallocable unit_list unit_clean unit_rand unit_hash
else
unit:
@echo [-] unit tests are skipped on Darwin \(lacks GNU linker feature --wrap\)
endif
.PHONY: code-format
code-format:
./.custom-format.py -i src/*.c
./.custom-format.py -i include/*.h
./.custom-format.py -i instrumentation/*.h
./.custom-format.py -i instrumentation/*.cc
./.custom-format.py -i instrumentation/*.c
./.custom-format.py -i *.h
./.custom-format.py -i *.c
@#./.custom-format.py -i custom_mutators/*/*.c* # destroys libfuzzer :-(
@#./.custom-format.py -i custom_mutators/*/*.h # destroys honggfuzz :-(
./.custom-format.py -i utils/*/*.c*
./.custom-format.py -i utils/*/*.h
./.custom-format.py -i libdislocator/*.c
./.custom-format.py -i libtokencap/*.c
./.custom-format.py -i llvm_mode/*.c
./.custom-format.py -i llvm_mode/*.h
./.custom-format.py -i llvm_mode/*.cc
./.custom-format.py -i gcc_plugin/*.c
#./.custom-format.py -i gcc_plugin/*.h
./.custom-format.py -i gcc_plugin/*.cc
./.custom-format.py -i custom_mutators/*/*.c
./.custom-format.py -i custom_mutators/*/*.h
./.custom-format.py -i examples/*/*.c
./.custom-format.py -i examples/*/*.h
./.custom-format.py -i test/*.c
./.custom-format.py -i frida_mode/src/*.c
./.custom-format.py -i frida_mode/include/*.h
-./.custom-format.py -i frida_mode/src/*/*.c
./.custom-format.py -i qemu_mode/patches/*.h
./.custom-format.py -i qemu_mode/libcompcov/*.c
./.custom-format.py -i qemu_mode/libcompcov/*.cc
./.custom-format.py -i qemu_mode/libcompcov/*.h
./.custom-format.py -i qemu_mode/libqasan/*.c
./.custom-format.py -i qemu_mode/libqasan/*.h
./.custom-format.py -i qbdi_mode/*.c
./.custom-format.py -i qbdi_mode/*.cpp
./.custom-format.py -i *.h
./.custom-format.py -i *.c
.PHONY: test_build
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 )
test_build: afl-gcc afl-as afl-showmap
@echo "[*] Testing the CC wrapper and instrumentation output..."
@unset AFL_USE_ASAN AFL_USE_MSAN AFL_CC; AFL_DEBUG=1 AFL_INST_RATIO=100 AFL_PATH=. ./$(TEST_CC) $(CFLAGS) test-instr.c -o test-instr $(LDFLAGS) 2>&1 | grep 'afl-as' >/dev/null || (echo "Oops, afl-as did not get called from "$(TEST_CC)". This is normally achieved by "$(CC)" honoring the -B option."; 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
@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
@echo "[+] All right, the instrumentation of afl-cc seems to be working!"
# @echo "[*] Testing the CC wrapper afl-gcc and its instrumentation output..."
# @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; AFL_CC=$(CC) ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-gcc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-gcc 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
# @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-gcc does not seem to be behaving correctly!"; \
# gcc -v 2>&1 | grep -q -- --with-as= && ( echo; echo "Gcc is configured not to use an external assembler with the -B option." ) || \
# ( echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue." ); echo; exit 0; fi
# @echo
# @echo "[+] All right, the instrumentation of afl-gcc seems to be working!"
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation 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 "[+] All right, the instrumentation seems to be working!"
else
test_build: afl-cc afl-as afl-showmap
test_build: afl-gcc afl-as afl-showmap
@echo "[!] Note: skipping build tests (you may need to use LLVM or QEMU mode)."
endif
.PHONY: all_done
all_done: test_build
@test -e afl-cc && echo "[+] Main compiler 'afl-cc' successfully built!" || { echo "[-] Main compiler 'afl-cc' failed to build, set up a working build environment first!" ; exit 1 ; }
@test -e cmplog-instructions-pass.so && echo "[+] LLVM mode for 'afl-cc' successfully built!" || echo "[-] LLVM mode for 'afl-cc' failed to build, likely you either don't have llvm installed, or you need to set LLVM_CONFIG, to point to e.g. llvm-config-11. See instrumentation/README.llvm.md how to do this. Highly recommended!"
@test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode for 'afl-cc' successfully built!" || echo "[-] LLVM LTO mode for 'afl-cc' failed to build, this would need LLVM 11+, see instrumentation/README.lto.md how to build it"
@test -e afl-gcc-pass.so && echo "[+] gcc_plugin for 'afl-cc' successfully built!" || echo "[-] gcc_plugin for 'afl-cc' failed to build, unless you really need it that is fine - or read instrumentation/README.gcc_plugin.md how to build it"
@if [ ! "`type clang 2>/dev/null`" = "" ]; then echo "[+] LLVM users: see llvm_mode/README.md for a faster alternative to afl-gcc."; fi
@echo "[+] All done! Be sure to review the README.md - it's pretty short and useful."
@if [ "$(SYS)" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD for fuzzing software not\nspecifically for MacOS.\n\n"; fi
@if [ "`uname`" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD. You can also use VirtualBox\n(virtualbox.org) to put AFL inside a Linux or *BSD VM.\n\n"; fi
@! tty <&1 >/dev/null || printf "\033[0;30mNOTE: If you can read this, your terminal probably uses white background.\nThis will make the UI hard to read. See docs/status_screen.md for advice.\033[0m\n" 2>/dev/null
.NOTPARALLEL: clean all
.PHONY: clean
clean:
rm -rf $(PROGS) afl-fuzz-document afl-as as afl-g++ afl-clang afl-clang++ *.o src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 afl-cs-proxy afl-qemu-trace afl-gcc-fast afl-g++-fast ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable .afl-* afl-gcc afl-g++ afl-clang afl-clang++ test/unittests/unit_hash test/unittests/unit_rand *.dSYM lib*.a
-$(MAKE) -f GNUmakefile.llvm 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/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
rm -rf nyx_mode/packer/linux_initramfs/init.cpio.gz nyx_mode/libnyx/libnyx/target/release/* nyx_mode/QEMU-Nyx/x86_64-softmmu/qemu-system-x86_64
rm -f $(PROGS) libradamsa.so afl-fuzz-document afl-as as afl-g++ afl-clang afl-clang++ *.o src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 afl-qemu-trace afl-gcc-fast afl-gcc-pass.so afl-gcc-rt.o afl-g++-fast ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable .afl-*
rm -rf out_dir qemu_mode/qemu-3.1.1 *.dSYM */*.dSYM
-$(MAKE) -C llvm_mode clean
-$(MAKE) -C gcc_plugin clean
$(MAKE) -C libdislocator clean
$(MAKE) -C libtokencap clean
$(MAKE) -C examples/afl_network_proxy clean
$(MAKE) -C examples/socket_fuzzing clean
$(MAKE) -C examples/argv_fuzzing clean
$(MAKE) -C qemu_mode/unsigaction clean
$(MAKE) -C qemu_mode/libcompcov clean
rm -rf qemu_mode/qemu-3.1.1
ifeq "$(IN_REPO)" "1"
-test -e coresight_mode/coresight-trace/Makefile && $(MAKE) -C coresight_mode/coresight-trace clean || true
-test -e qemu_mode/qemuafl/Makefile && $(MAKE) -C qemu_mode/qemuafl clean || true
-test -e unicorn_mode/unicornafl/Makefile && $(MAKE) -C unicorn_mode/unicornafl clean || true
-test -e nyx_mode/QEMU-Nyx/Makefile && $(MAKE) -C nyx_mode/QEMU-Nyx clean || true
test -d unicorn_mode/unicornafl && $(MAKE) -C unicorn_mode/unicornafl clean || true
else
rm -rf coresight_mode/coresight_trace
rm -rf qemu_mode/qemuafl
rm -rf qemu_mode/qemu-3.1.1.tar.xz
rm -rf unicorn_mode/unicornafl
endif
.PHONY: deepclean
deepclean: clean
rm -rf coresight_mode/coresight-trace
rm -rf qemu_mode/qemu-3.1.1.tar.xz
rm -rf unicorn_mode/unicornafl
rm -rf qemu_mode/qemuafl
rm -rf nyx_mode/libnyx nyx_mode/packer nyx_mode/QEMU-Nyx
ifeq "$(IN_REPO)" "1"
git checkout coresight_mode/coresight-trace
git checkout unicorn_mode/unicornafl
git checkout qemu_mode/qemuafl
git checkout nyx_mode/libnyx
git checkout nyx_mode/packer
git checkout nyx_mode/QEMU-Nyx
endif
git reset --hard >/dev/null 2>&1 || true
.PHONY: distrib
distrib: all
-$(MAKE) -j$(nproc) -f GNUmakefile.llvm
ifneq "$(SYS)" "Darwin"
-$(MAKE) -f GNUmakefile.gcc_plugin
-$(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"
ifndef NO_CORESIGHT
-$(MAKE) -C coresight_mode
endif
endif
ifeq "$(SYS)" "Linux"
ifndef NO_NYX
-cd nyx_mode && ./build_nyx_support.sh
endif
endif
-$(MAKE) -C llvm_mode
-$(MAKE) -C gcc_plugin
$(MAKE) -C libdislocator
$(MAKE) -C libtokencap
$(MAKE) -C examples/afl_network_proxy
$(MAKE) -C examples/socket_fuzzing
$(MAKE) -C examples/argv_fuzzing
-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
cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
.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
# -$(MAKE) -C utils/plot_ui
-$(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
-cd nyx_mode && ./build_nyx_support.sh
endif
endif
binary-only: all
$(MAKE) -C libdislocator
$(MAKE) -C libtokencap
$(MAKE) -C examples/afl_network_proxy
$(MAKE) -C examples/socket_fuzzing
$(MAKE) -C examples/argv_fuzzing
-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
cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
.PHONY: source-only
source-only: all
-$(MAKE) -j$(nproc) -f GNUmakefile.llvm
ifneq "$(SYS)" "Darwin"
-$(MAKE) -f GNUmakefile.gcc_plugin
-$(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 build, 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 build, 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 build, 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
-$(MAKE) -C llvm_mode
-$(MAKE) -C gcc_plugin
$(MAKE) -C libdislocator
$(MAKE) -C libtokencap
#$(MAKE) -C examples/afl_network_proxy
#$(MAKE) -C examples/socket_fuzzing
#$(MAKE) -C examples/argv_fuzzing
%.8: %
@echo .TH $* 8 $(BUILD_DATE) "afl++" > $@
@ -764,53 +572,30 @@ endif
@echo .SH LICENSE >> $@
@echo Apache License Version 2.0, January 2004 >> $@
.PHONY: install
install: all $(MANPAGES)
@install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH)
@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 -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH)
rm -f $${DESTDIR}$(BIN_PATH)/afl-plot.sh
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
@if [ -f libdislocator.so ]; then set -e; install -m 755 libdislocator.so $${DESTDIR}$(HELPER_PATH); fi
@if [ -f libtokencap.so ]; then set -e; install -m 755 libtokencap.so $${DESTDIR}$(HELPER_PATH); fi
@if [ -f libcompcov.so ]; then set -e; install -m 755 libcompcov.so $${DESTDIR}$(HELPER_PATH); fi
@if [ -f libqasan.so ]; then set -e; install -m 755 libqasan.so $${DESTDIR}$(HELPER_PATH); fi
@if [ -f afl-fuzz-document ]; then set -e; install -m 755 afl-fuzz-document $${DESTDIR}$(BIN_PATH); fi
@if [ -f socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C utils/socket_fuzzing install; fi
@if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C utils/argv_fuzzing install; fi
@if [ -f afl-frida-trace.so ]; then install -m 755 afl-frida-trace.so $${DESTDIR}$(HELPER_PATH); fi
@if [ -f libnyx.so ]; then install -m 755 libnyx.so $${DESTDIR}$(HELPER_PATH); fi
@if [ -f utils/afl_network_proxy/afl-network-server ]; then $(MAKE) -C utils/afl_network_proxy install; fi
@if [ -f utils/aflpp_driver/libAFLDriver.a ]; then set -e; install -m 644 utils/aflpp_driver/libAFLDriver.a $${DESTDIR}$(HELPER_PATH); fi
@if [ -f utils/aflpp_driver/libAFLQemuDriver.a ]; then set -e; install -m 644 utils/aflpp_driver/libAFLQemuDriver.a $${DESTDIR}$(HELPER_PATH); fi
-$(MAKE) -f GNUmakefile.llvm install
ifneq "$(SYS)" "Darwin"
-$(MAKE) -f GNUmakefile.gcc_plugin install
endif
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-gcc
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-g++
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang++
@mkdir -m 0755 -p ${DESTDIR}$(MAN_PATH)
rm -f $${DESTDIR}$(BIN_PATH)/afl-as
if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi
if [ -f afl-gcc-fast ]; then set e; install -m 755 afl-gcc-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-gcc-fast $${DESTDIR}$(BIN_PATH)/afl-g++-fast; install -m 755 afl-gcc-pass.so afl-gcc-rt.o $${DESTDIR}$(HELPER_PATH); fi
if [ -f afl-clang-fast ]; then $(MAKE) -C llvm_mode install; fi
if [ -f libdislocator.so ]; then set -e; install -m 755 libdislocator.so $${DESTDIR}$(HELPER_PATH); fi
if [ -f libtokencap.so ]; then set -e; install -m 755 libtokencap.so $${DESTDIR}$(HELPER_PATH); fi
if [ -f libcompcov.so ]; then set -e; install -m 755 libcompcov.so $${DESTDIR}$(HELPER_PATH); fi
if [ -f afl-fuzz-document ]; then set -e; install -m 755 afl-fuzz-document $${DESTDIR}$(BIN_PATH); fi
if [ -f socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C examples/socket_fuzzing install; fi
if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C examples/argv_fuzzing install; fi
if [ -f examples/afl_network_proxy/afl-network-server ]; then $(MAKE) -C examples/afl_network_proxy install; fi
set -e; ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-g++
set -e; if [ -f afl-clang-fast ] ; then ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang++ ; else ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang++; fi
mkdir -m 0755 -p ${DESTDIR}$(MAN_PATH)
install -m0644 *.8 ${DESTDIR}$(MAN_PATH)
install -m 755 afl-as $${DESTDIR}$(HELPER_PATH)
ln -sf afl-as $${DESTDIR}$(HELPER_PATH)/as
install -m 644 docs/*.md $${DESTDIR}$(DOC_PATH)
cp -r testcases/ $${DESTDIR}$(MISC_PATH)
cp -r dictionaries/ $${DESTDIR}$(MISC_PATH)
.PHONY: uninstall
uninstall:
-cd $${DESTDIR}$(BIN_PATH) && rm -f $(PROGS) $(SH_PROGS) afl-cs-proxy afl-qemu-trace afl-plot-ui afl-fuzz-document afl-network-server afl-g* afl-plot.sh afl-as afl-ld-lto afl-c* afl-lto*
-cd $${DESTDIR}$(HELPER_PATH) && rm -f afl-g*.*o afl-llvm-*.*o afl-compiler-*.*o libdislocator.so libtokencap.so libcompcov.so libqasan.so afl-frida-trace.so libnyx.so socketfuzz*.so argvfuzz*.so libAFLDriver.a libAFLQemuDriver.a as afl-as SanitizerCoverage*.so compare-transform-pass.so cmplog-*-pass.so split-*-pass.so dynamic_list.txt
-rm -rf $${DESTDIR}$(MISC_PATH)/testcases $${DESTDIR}$(MISC_PATH)/dictionaries
-sh -c "ls docs/*.md | sed 's|^docs/|$${DESTDIR}$(DOC_PATH)/|' | xargs rm -f"
-cd $${DESTDIR}$(MAN_PATH) && rm -f $(MANPAGES)
-rmdir $${DESTDIR}$(BIN_PATH) 2>/dev/null
-rmdir $${DESTDIR}$(HELPER_PATH) 2>/dev/null
-rmdir $${DESTDIR}$(MISC_PATH) 2>/dev/null
-rmdir $${DESTDIR}$(DOC_PATH) 2>/dev/null
-rmdir $${DESTDIR}$(MAN_PATH) 2>/dev/null

View File

@ -1,210 +0,0 @@
#
# american fuzzy lop++ - GCC plugin instrumentation
# -----------------------------------------------
#
# Written by Austin Seipp <aseipp@pobox.com> and
# Laszlo Szekeres <lszekeres@google.com> and
# Michal Zalewski and
# Heiko Eißfeldt <heiko@hexco.de>
#
# GCC integration design is based on the LLVM design, which comes
# from Laszlo Szekeres.
#
# Copyright 2015 Google Inc. 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:
#
# https://www.apache.org/licenses/LICENSE-2.0
#
#TEST_MMAP=1
PREFIX ?= /usr/local
HELPER_PATH ?= $(PREFIX)/lib/afl
BIN_PATH ?= $(PREFIX)/bin
DOC_PATH ?= $(PREFIX)/share/doc/afl
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=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=1
CXXEFLAGS := $(CXXFLAGS) -Wall -std=c++11
CC ?= gcc
CXX ?= g++
SYS = $(shell uname -s)
ifeq "clang" "$(CC)"
CC = gcc
CXX = g++
endif
ifeq "clang++" "$(CXX)"
CC = gcc
CXX = g++
endif
ifeq "$(findstring Foundation,$(shell $(CC) --version))" ""
CC = gcc
CXX = g++
endif
PLUGIN_BASE = "$(shell $(CC) -print-file-name=plugin)"
PLUGIN_FLAGS = -fPIC -fno-rtti -I$(PLUGIN_BASE)/include -I$(PLUGIN_BASE)
HASH=\#
GCCVER = $(shell $(CC) --version 2>/dev/null | awk 'NR == 1 {print $$NF}')
GCCBINDIR = $(shell dirname `command -v $(CC)` 2>/dev/null )
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
SHMAT_OK=1
else
SHMAT_OK=0
override CFLAGS_SAFE += -DUSEMMAP=1
endif
ifeq "$(TEST_MMAP)" "1"
SHMAT_OK=0
override CFLAGS_SAFE += -DUSEMMAP=1
endif
ifneq "$(SYS)" "Haiku"
ifneq "$(SYS)" "OpenBSD"
LDFLAGS += -lrt
endif
else
CFLAGS_SAFE += -DUSEMMAP=1
endif
ifeq "$(SYS)" "OpenBSD"
CC = egcc
CXX = eg++
PLUGIN_FLAGS += -I/usr/local/include
endif
ifeq "$(SYS)" "DragonFly"
PLUGIN_FLAGS += -I/usr/local/include
endif
ifeq "$(SYS)" "SunOS"
PLUGIN_FLAGS += -I/usr/include/gmp
endif
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
.PHONY: test_shm
ifeq "$(SHMAT_OK)" "1"
test_shm:
@echo "[+] shmat seems to be working."
@rm -f .test2
else
test_shm:
@echo "[-] shmat seems not to be working, switching to mmap implementation"
endif
.PHONY: test_deps
test_deps:
@echo "[*] Checking for working '$(CC)'..."
@command -v $(CC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(CC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 )
# @echo "[*] Checking for gcc for plugin support..."
# @$(CC) -v 2>&1 | grep -q -- --enable-plugin || ( echo "[-] Oops, this gcc has not been configured with plugin support."; exit 1 )
@echo "[*] Checking for gcc plugin development header files..."
@test -d `$(CC) -print-file-name=plugin`/include || ( echo "[-] Oops, can't find gcc header files. Be sure to install 'gcc-X-plugin-dev'."; exit 1 )
@echo "[*] Checking for './afl-showmap'..."
@test -f ./afl-showmap || ( echo "[-] Oops, can't find './afl-showmap'. Be sure to compile AFL first."; exit 1 )
@echo "[+] All set and ready to build."
afl-common.o: ./src/afl-common.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ $(LDFLAGS)
./afl-compiler-rt.o: instrumentation/afl-compiler-rt.o.c
$(CC) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -fPIC -c $< -o $@
./afl-compiler-rt-32.o: instrumentation/afl-compiler-rt.o.c
@printf "[*] Building 32-bit variant of the runtime (-m32)... "
@$(CC) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
./afl-compiler-rt-64.o: instrumentation/afl-compiler-rt.o.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
ln -sf afl-cc afl-g++-fast
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..."
unset AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_QUIET=1 AFL_INST_RATIO=100 AFL_PATH=. AFL_CC=$(CC) ./afl-gcc-fast $(CFLAGS) $(CPPFLAGS) ./test-instr.c -o test-instr $(LDFLAGS)
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
@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 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 "[+] All right, the instrumentation seems to be working!"
.PHONY: all_done
all_done: test_build
@echo "[+] All done! You can now use './afl-gcc-fast' to compile programs."
.NOTPARALLEL: clean
%.8: %
@echo .TH $* 8 `date "+%Y-%m-%d"` "afl++" > ./$@
@echo .SH NAME >> ./$@
@echo .B $* >> ./$@
@echo >> ./$@
@echo .SH SYNOPSIS >> ./$@
@./$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> ./$@
@echo >> ./$@
@echo .SH OPTIONS >> ./$@
@echo .nf >> ./$@
@./$* -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 >> ./$@
@echo .SH LICENSE >> ./$@
@echo Apache License Version 2.0, January 2004 >> ./$@
ln -sf afl-cc.8 ./afl-g++-fast.8
.PHONY: install
install: all
ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-gcc-fast
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
clean:
rm -f *.o *.so *~ a.out core core.[1-9][0-9]* test-instr .test-instr0 .test-instr1 .test2
rm -f $(PROGS) afl-common.o ./afl-g++-fast ./afl-g*-fast.8 instrumentation/*.o

View File

@ -1,536 +0,0 @@
# american fuzzy lop++ - LLVM instrumentation
# -----------------------------------------
#
# Written by Laszlo Szekeres <lszekeres@google.com> and
# Michal Zalewski
#
# LLVM integration design comes from Laszlo Szekeres.
#
# Copyright 2015, 2016 Google Inc. 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:
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# For Heiko:
#TEST_MMAP=1
HASH=\#
PREFIX ?= /usr/local
HELPER_PATH ?= $(PREFIX)/lib/afl
BIN_PATH ?= $(PREFIX)/bin
DOC_PATH ?= $(PREFIX)/share/doc/afl
MISC_PATH ?= $(PREFIX)/share/afl
MAN_PATH ?= $(PREFIX)/share/man/man8
BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u "+%Y-%m-%d")
VERSION = $(shell grep '^$(HASH)define VERSION ' ./config.h | cut -d '"' -f2)
SYS = $(shell uname -s)
ifeq "$(SYS)" "OpenBSD"
LLVM_CONFIG ?= $(BIN_PATH)/llvm-config
HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1)
ifeq "$(HAS_OPT)" "1"
$(warning llvm_mode needs a complete llvm installation (versions 6.0 up to 13) -> e.g. "pkg_add llvm-7.0.1p9")
endif
else
LLVM_CONFIG ?= llvm-config
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 | 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[5-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_10_OK = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -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 | 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
LLVM_APPLE_XCODE = $(shell $(CC) -v 2>&1 | grep -q Apple && echo 1 || echo 0)
LLVM_LTO = 0
ifeq "$(LLVMVER)" ""
$(warning [!] llvm_mode needs llvm-config, which was not found. Set LLVM_CONFIG to its path and retry.)
endif
ifeq "$(LLVM_UNSUPPORTED)" "1"
$(error llvm_mode only supports llvm from version 3.8 onwards)
endif
ifeq "$(LLVM_TOO_NEW)" "1"
$(warning you are using an in-development llvm version - this might break llvm_mode!)
endif
LLVM_TOO_OLD=1
ifeq "$(LLVM_MAJOR)" "9"
$(info [+] llvm_mode detected llvm 9, enabling neverZero implementation)
LLVM_TOO_OLD=0
endif
ifeq "$(LLVM_NEW_API)" "1"
$(info [+] llvm_mode detected llvm 10+, enabling neverZero implementation and c++14)
LLVM_STDCXX = c++14
LLVM_TOO_OLD=0
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_HAVE_LTO)" "1"
$(info [+] llvm_mode detected llvm 11+, enabling afl-lto LTO implementation)
LLVM_LTO = 1
endif
ifeq "$(LLVM_LTO)" "0"
$(info [+] llvm_mode detected llvm < 11, afl-lto LTO will not be build.)
endif
ifeq "$(LLVM_APPLE_XCODE)" "1"
$(warning llvm_mode will not compile with Xcode clang...)
endif
# We were using llvm-config --bindir to get the location of clang, but
# this seems to be busted on some distros, so using the one in $PATH is
# probably better.
CC = $(LLVM_BINDIR)/clang
CXX = $(LLVM_BINDIR)/clang++
# llvm-config --bindir may not providing a valid path, so ...
ifeq "$(shell test -e $(CC) || echo 1 )" "1"
# however we must ensure that this is not a "CC=gcc make"
ifeq "$(shell command -v $(CC) 2> /dev/null)" ""
# we do not have a valid CC variable so we try alternatives
ifeq "$(shell test -e '$(BIN_DIR)/clang' && echo 1)" "1"
# we found one in the local install directory, lets use these
CC = $(BIN_DIR)/clang
else
# hope for the best
$(warning we have trouble finding clang - llvm-config is not helping us)
CC = clang
endif
endif
endif
# llvm-config --bindir may not providing a valid path, so ...
ifeq "$(shell test -e $(CXX) || echo 1 )" "1"
# however we must ensure that this is not a "CXX=g++ make"
ifeq "$(shell command -v $(CXX) 2> /dev/null)" ""
# we do not have a valid CXX variable so we try alternatives
ifeq "$(shell test -e '$(BIN_DIR)/clang++' && echo 1)" "1"
# we found one in the local install directory, lets use these
CXX = $(BIN_DIR)/clang++
else
# hope for the best
$(warning we have trouble finding clang++ - llvm-config is not helping us)
CXX = clang++
endif
endif
endif
# sanity check.
# Are versions of clang --version and llvm-config --version equal?
CLANGVER = $(shell $(CC) --version | sed -E -ne '/^.*version\ (1?[0-9]\.[0-9]\.[0-9]).*/s//\1/p')
# I disable this because it does not make sense with what we did before (marc)
# We did exactly set these 26 lines above with these values, and it would break
# "CC=gcc make" etc. usages
ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
CC_SAVE := $(LLVM_BINDIR)/clang
else
CC_SAVE := $(CC)
endif
ifeq "$(findstring clang, $(shell $(CXX) --version 2>/dev/null))" ""
CXX_SAVE := $(LLVM_BINDIR)/clang++
else
CXX_SAVE := $(CXX)
endif
CLANG_BIN := $(CC_SAVE)
CLANGPP_BIN := $(CXX_SAVE)
ifeq "$(CC_SAVE)" "$(LLVM_BINDIR)/clang"
USE_BINDIR = 1
else
ifeq "$(CXX_SAVE)" "$(LLVM_BINDIR)/clang++"
USE_BINDIR = 1
else
USE_BINDIR = 0
endif
endif
# On old platform we cannot compile with clang because std++ libraries are too
# old. For these we need to use gcc/g++, so if we find REAL_CC and REAL_CXX
# variable we override the compiler variables here
ifneq "$(REAL_CC)" ""
CC = $(REAL_CC)
endif
ifneq "$(REAL_CXX)" ""
CXX = $(REAL_CXX)
endif
#
# Now it can happen that CC points to clang - but there is no clang on the
# system. Then we fall back to cc
#
ifeq "$(shell command -v $(CC) 2>/dev/null)" ""
CC = cc
endif
ifeq "$(shell command -v $(CXX) 2>/dev/null)" ""
CXX = c++
endif
# After we set CC/CXX we can start makefile magic tests
#ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -march=native -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
# CFLAGS_OPT = -march=native
#endif
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
AFL_CLANG_FLTO ?= -flto=full
else
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
AFL_CLANG_FLTO ?= -flto=thin
else
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
AFL_CLANG_FLTO ?= -flto
endif
endif
endif
ifeq "$(LLVM_LTO)" "1"
ifneq "$(AFL_CLANG_FLTO)" ""
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
endif
endif
else
$(warning clang option -flto is not working - maybe LLVMgold.so not found - cannot enable LTO mode)
LLVM_LTO = 0
endif
endif
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=$(AFL_REAL_LD) -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
AFL_CLANG_LDPATH=1
endif
else
$(warning -fuse-ld is not working, cannot enable LTO mode)
LLVM_LTO = 0
endif
endif
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fdebug-prefix-map=$(CURDIR)=llvm_mode -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
AFL_CLANG_DEBUG_PREFIX = -fdebug-prefix-map="$(CURDIR)=llvm_mode"
else
AFL_CLANG_DEBUG_PREFIX =
endif
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)\" \
-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
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=1
override CXXFLAGS += -Wall -g -I ./include/ \
-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" ""
CLANG_CFL = -I$(shell $(LLVM_CONFIG) --includedir)
endif
ifneq "$(LLVM_CONFIG)" ""
CLANG_CFL += -I$(shell dirname $(LLVM_CONFIG))/../include
endif
CLANG_CPPFL = `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC $(CXXFLAGS) -Wno-deprecated-declarations
CLANG_LFL = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS)
# User teor2345 reports that this is required to make things work on MacOS X.
ifeq "$(SYS)" "Darwin"
CLANG_LFL += -Wl,-flat_namespace -Wl,-undefined,suppress
override LLVM_HAVE_LTO := 0
override LLVM_LTO := 0
else
CLANG_CPPFL += -Wl,-znodelete
endif
ifeq "$(SYS)" "OpenBSD"
CLANG_LFL += `$(LLVM_CONFIG) --libdir`/libLLVM.so
CLANG_CPPFL += -mno-retpoline
CFLAGS += -mno-retpoline
# Needed for unwind symbols
LDFLAGS += -lc++abi -lpthread
endif
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
SHMAT_OK=1
else
SHMAT_OK=0
CFLAGS_SAFE += -DUSEMMAP=1
LDFLAGS += -Wno-deprecated-declarations
endif
ifeq "$(TEST_MMAP)" "1"
SHMAT_OK=0
CFLAGS_SAFE += -DUSEMMAP=1
LDFLAGS += -Wno-deprecated-declarations
endif
PROGS_ALWAYS = ./afl-cc ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o
PROGS = $(PROGS_ALWAYS) ./afl-llvm-pass.so ./SanitizerCoveragePCGUARD.so ./split-compares-pass.so ./split-switches-pass.so ./cmplog-routines-pass.so ./cmplog-instructions-pass.so ./cmplog-switches-pass.so ./afl-llvm-dict2file.so ./compare-transform-pass.so ./afl-ld-lto ./afl-llvm-lto-instrumentlist.so ./SanitizerCoverageLTO.so
# If prerequisites are not given, warn, do not build anything, and exit with code 0
ifeq "$(LLVMVER)" ""
NO_BUILD = 1
endif
ifneq "$(LLVM_UNSUPPORTED)$(LLVM_APPLE_XCODE)" "00"
NO_BUILD = 1
endif
ifeq "$(NO_BUILD)" "1"
TARGETS = test_shm $(PROGS_ALWAYS) afl-cc.8
else
TARGETS = test_shm test_deps $(PROGS) afl-cc.8 test_build all_done
endif
LLVM_MIN_4_0_1 = $(shell awk 'function tonum(ver, a) {split(ver,a,"."); return a[1]*1000000+a[2]*1000+a[3]} BEGIN { exit tonum(ARGV[1]) >= tonum(ARGV[2]) }' $(LLVMVER) 4.0.1; echo $$?)
.PHONY: all
all: $(TARGETS)
.PHONY: test_shm
ifeq "$(SHMAT_OK)" "1"
test_shm:
@echo "[+] shmat seems to be working."
@rm -f .test2
else
test_shm:
@echo "[-] shmat seems not to be working, switching to mmap implementation"
endif
.PHONY: no_build
no_build:
@printf "%b\\n" "\\033[0;31mPrerequisites are not met, skipping build llvm_mode\\033[0m"
.PHONY: test_deps
test_deps:
@echo "[*] Checking for working 'llvm-config'..."
ifneq "$(LLVM_APPLE_XCODE)" "1"
@type $(LLVM_CONFIG) >/dev/null 2>&1 || ( echo "[-] Oops, can't find 'llvm-config'. Install clang or set \$$LLVM_CONFIG or \$$PATH beforehand."; echo " (Sometimes, the binary will be named llvm-config-11 or something like that.)"; exit 1 )
endif
@echo "[*] Checking for working '$(CC)'..."
@type $(CC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(CC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 )
@echo "[*] Checking for matching versions of '$(CC)' and '$(LLVM_CONFIG)'"
ifneq "$(CLANGVER)" "$(LLVMVER)"
@echo "[!] WARNING: we have llvm-config version $(LLVMVER) and a clang version $(CLANGVER)"
else
@echo "[*] We have llvm-config version $(LLVMVER) with a clang version $(CLANGVER), good."
endif
@echo "[*] Checking for './afl-showmap'..."
@test -f ./afl-showmap || ( echo "[-] Oops, can't find './afl-showmap'. Be sure to compile AFL first."; exit 1 )
@echo "[+] All set and ready to build."
instrumentation/afl-common.o: ./src/afl-common.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ $(LDFLAGS)
./afl-cc: src/afl-cc.c instrumentation/afl-common.o
$(CC) $(CLANG_CFL) $(CFLAGS) $(CPPFLAGS) $< instrumentation/afl-common.o -o $@ -DLLVM_MINOR=$(LLVM_MINOR) -DLLVM_MAJOR=$(LLVM_MAJOR) $(LDFLAGS) -DCFLAGS_OPT=\"$(CFLAGS_OPT)\" -lm
@ln -sf afl-cc ./afl-c++
@ln -sf afl-cc ./afl-gcc
@ln -sf afl-cc ./afl-g++
@ln -sf afl-cc ./afl-clang
@ln -sf afl-cc ./afl-clang++
@ln -sf afl-cc ./afl-clang-fast
@ln -sf afl-cc ./afl-clang-fast++
ifneq "$(AFL_CLANG_FLTO)" ""
ifeq "$(LLVM_LTO)" "1"
@ln -sf afl-cc ./afl-clang-lto
@ln -sf afl-cc ./afl-clang-lto++
@ln -sf afl-cc ./afl-lto
@ln -sf afl-cc ./afl-lto++
endif
endif
instrumentation/afl-llvm-common.o: instrumentation/afl-llvm-common.cc instrumentation/afl-llvm-common.h
$(CXX) $(CFLAGS) $(CPPFLAGS) `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC -std=$(LLVM_STDCXX) -c $< -o $@
./afl-llvm-pass.so: instrumentation/afl-llvm-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
ifeq "$(LLVM_MIN_4_0_1)" "0"
$(info [!] N-gram branch coverage instrumentation is not available for llvm version $(LLVMVER))
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"
-$(CXX) $(CLANG_CPPFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) -Wno-deprecated-copy-dtor -Wdeprecated instrumentation/afl-llvm-common.o
endif
./afl-llvm-lto-instrumentlist.so: instrumentation/afl-llvm-lto-instrumentlist.so.cc instrumentation/afl-llvm-common.o
ifeq "$(LLVM_LTO)" "1"
$(CXX) $(CLANG_CPPFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
endif
./afl-ld-lto: src/afl-ld-lto.c
ifeq "$(LLVM_LTO)" "1"
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@
endif
./SanitizerCoverageLTO.so: instrumentation/SanitizerCoverageLTO.so.cc instrumentation/afl-llvm-common.o
ifeq "$(LLVM_LTO)" "1"
$(CXX) $(CLANG_CPPFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto.o
@$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m64 -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto-64.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
@$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m32 -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto-32.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
endif
# laf
./split-switches-pass.so: instrumentation/split-switches-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
./compare-transform-pass.so: instrumentation/compare-transform-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
./split-compares-pass.so: instrumentation/split-compares-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
# /laf
./cmplog-routines-pass.so: instrumentation/cmplog-routines-pass.cc instrumentation/afl-llvm-common.o | test_deps
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
./cmplog-instructions-pass.so: instrumentation/cmplog-instructions-pass.cc instrumentation/afl-llvm-common.o | test_deps
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
./cmplog-switches-pass.so: instrumentation/cmplog-switches-pass.cc instrumentation/afl-llvm-common.o | test_deps
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
afl-llvm-dict2file.so: instrumentation/afl-llvm-dict2file.so.cc instrumentation/afl-llvm-common.o | test_deps
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
.PHONY: document
document:
$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CPPFLAGS) $(CLANG_CFL) -O3 -Wno-unused-result -fPIC -c instrumentation/afl-compiler-rt.o.c -o ./afl-compiler-rt.o
@$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CPPFLAGS) $(CLANG_CFL) -O3 -Wno-unused-result -m32 -fPIC -c instrumentation/afl-compiler-rt.o.c -o ./afl-compiler-rt-32.o 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
@$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CPPFLAGS) $(CLANG_CFL) -O3 -Wno-unused-result -m64 -fPIC -c instrumentation/afl-compiler-rt.o.c -o ./afl-compiler-rt-64.o 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
./afl-compiler-rt.o: instrumentation/afl-compiler-rt.o.c
$(CC) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -fPIC -c $< -o $@
./afl-compiler-rt-32.o: instrumentation/afl-compiler-rt.o.c
@printf "[*] Building 32-bit variant of the runtime (-m32)... "
@$(CC) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
./afl-compiler-rt-64.o: instrumentation/afl-compiler-rt.o.c
@printf "[*] Building 64-bit variant of the runtime (-m64)... "
@$(CC) $(CLANG_CFL) $(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
.PHONY: test_build
test_build: $(PROGS)
@echo "[*] Testing the CC wrapper and instrumentation output..."
unset AFL_USE_ASAN AFL_USE_MSAN AFL_INST_RATIO; ASAN_OPTIONS=detect_leaks=0 AFL_QUIET=1 AFL_PATH=. AFL_LLVM_LAF_ALL=1 ./afl-cc $(CFLAGS) $(CPPFLAGS) ./test-instr.c -o test-instr $(LDFLAGS)
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
@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 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 "[+] All right, the instrumentation seems to be working!"
.PHONY: all_done
all_done: test_build
@echo "[+] All done! You can now use './afl-cc' to compile programs."
.NOTPARALLEL: clean
.PHONY: install
install: all
@install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH)
@if [ -f ./afl-cc ]; then set -e; install -m 755 ./afl-cc $${DESTDIR}$(BIN_PATH); ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-c++; fi
@rm -f $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt*.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt*.o
@if [ -f ./afl-compiler-rt.o ]; then set -e; install -m 755 ./afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH); fi
@if [ -f ./afl-lto ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-lto; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-lto++; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ./afl-llvm-rt-lto*.o ./afl-llvm-lto-instrumentlist.so $${DESTDIR}$(HELPER_PATH); fi
@if [ -f ./afl-ld-lto ]; then set -e; install -m 755 ./afl-ld-lto $${DESTDIR}$(BIN_PATH); fi
@if [ -f ./afl-compiler-rt-32.o ]; then set -e; install -m 755 ./afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH); fi
@if [ -f ./afl-compiler-rt-64.o ]; then set -e; install -m 755 ./afl-compiler-rt-64.o $${DESTDIR}$(HELPER_PATH); fi
@if [ -f ./compare-transform-pass.so ]; then set -e; install -m 755 ./*.so $${DESTDIR}$(HELPER_PATH); fi
@if [ -f ./compare-transform-pass.so ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-fast ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang-fast++ ; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang++ ; fi
@if [ -f ./SanitizerCoverageLTO.so ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang-lto++ ; fi
set -e; install -m 644 ./dynamic_list.txt $${DESTDIR}$(HELPER_PATH)
install -m 644 instrumentation/README.*.md $${DESTDIR}$(DOC_PATH)/
%.8: %
@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" >> ./$@
@echo .B $* >> ./$@
@echo >> ./$@
@echo .SH SYNOPSIS >> ./$@
@./$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> ./$@
@echo >> ./$@
@echo .SH OPTIONS >> ./$@
@echo .nf >> ./$@
@./$* -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 >> ./$@
@echo .SH LICENSE >> ./$@
@echo Apache License Version 2.0, January 2004 >> ./$@
@ln -sf afl-cc.8 ./afl-c++.8
@ln -sf afl-cc.8 ./afl-clang-fast.8
@ln -sf afl-cc.8 ./afl-clang-fast++.8
ifneq "$(AFL_CLANG_FLTO)" ""
ifeq "$(LLVM_LTO)" "1"
@ln -sf afl-cc.8 ./afl-clang-lto.8
@ln -sf afl-cc.8 ./afl-clang-lto++.8
@ln -sf afl-cc.8 ./afl-lto.8
@ln -sf afl-cc.8 ./afl-lto++.8
endif
endif
.PHONY: clean
clean:
rm -f *.o *.so *~ a.out core core.[1-9][0-9]* .test2 test-instr .test-instr0 .test-instr1 *.dwo
rm -f $(PROGS) afl-common.o ./afl-c++ ./afl-lto ./afl-lto++ ./afl-clang-lto* ./afl-clang-fast* ./afl-clang*.8 ./ld ./afl-ld ./afl-compiler-rt*.o ./afl-llvm-rt*.o instrumentation/*.o

1
QuickStartGuide.md Symbolic link
View File

@ -0,0 +1 @@
docs/QuickStartGuide.md

907
README.md
View File

@ -1,258 +1,763 @@
# American Fuzzy Lop plus plus (AFL++)
# 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/andreafioraldi/AFLplusplus-website/master/static/logo_256x256.png" alt="AFL++ Logo">
Release version: [4.05c](https://github.com/AFLplusplus/AFLplusplus/releases)
![Travis State](https://api.travis-ci.com/AFLplusplus/AFLplusplus.svg?branch=stable)
GitHub version: 4.06a
Release Version: [2.66c](https://github.com/AFLplusplus/AFLplusplus/releases)
Repository:
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
Github Version: 2.66d
AFL++ is maintained by:
includes all necessary/interesting changes from Google's afl 2.56b
* 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>
* Documentation: Jana Aydinbas <jana.aydinbas@gmail.com>
Originally developed by Michal "lcamtuf" Zalewski.
Originally developed by Michał "lcamtuf" Zalewski.
Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
AFL++ is a superior fork to Google's AFL - more speed, more and better
mutations, more and better instrumentation, custom module support, etc.
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> and
* Dominik Maier <mail@dmnk.co>.
You are free to copy, modify, and distribute AFL++ with attribution under the
terms of the Apache-2.0 License. See the [LICENSE](LICENSE) for details.
Note that although afl now has a Google afl repository [https://github.com/Google/afl](https://github.com/Google/afl),
it is unlikely to receive any notable enhancements: [https://twitter.com/Dor3s/status/1154737061787660288](https://twitter.com/Dor3s/status/1154737061787660288)
## Getting started
## The enhancements compared to the original stock afl
Here is some information to get you started:
Many improvements were made over the official afl release - which did not
get any feature improvements since November 2017.
* For an overview of the AFL++ documentation and a very helpful graphical guide,
please visit [docs/README.md](docs/README.md).
* To get you started with tutorials, go to
[docs/tutorials.md](docs/tutorials.md).
* For releases, see the
[Releases tab](https://github.com/AFLplusplus/AFLplusplus/releases) and
[branches](#branches). The best branches to use are, however, `stable` or
`dev` - depending on your risk appetite. Also take a look at the list of
[important changes in AFL++](docs/important_changes.md) and the list of
[features](docs/features.md).
* If you want to use AFL++ for your academic work, check the
[papers page](https://aflplus.plus/papers/) on the website.
* To cite our work, look at the [Cite](#cite) section.
* For comparisons, use the fuzzbench `aflplusplus` setup, or use
`afl-clang-fast` with `AFL_LLVM_CMPLOG=1`. You can find the `aflplusplus`
default configuration on Google's
[fuzzbench](https://github.com/google/fuzzbench/tree/master/fuzzers/aflplusplus).
Among other changes afl++ has a more performant llvm_mode, supports
llvm up to version 11, QEMU 3.1, more speed and crashfixes for QEMU,
better *BSD and Android support and much, much more.
## Building and installing AFL++
Additionally the following features and patches have been integrated:
To have AFL++ easily available with everything compiled, pull the image directly
from the Docker Hub (available for both x86_64 and arm64):
* AFLfast's power schedules by Marcel Böhme: [https://github.com/mboehme/aflfast](https://github.com/mboehme/aflfast)
* The new excellent MOpt mutator: [https://github.com/puppet-meteor/MOpt-AFL](https://github.com/puppet-meteor/MOpt-AFL)
* InsTrim, a very effective CFG llvm_mode instrumentation implementation for large targets: [https://github.com/csienslab/instrim](https://github.com/csienslab/instrim)
* C. Holler's afl-fuzz Python mutator module and llvm_mode instrument file support: [https://github.com/choller/afl](https://github.com/choller/afl)
* Custom mutator by a library (instead of Python) by kyakdan
* Unicorn mode which allows fuzzing of binaries from completely different platforms (integration provided by domenukk)
* LAF-Intel or CompCov support for llvm_mode, qemu_mode and unicorn_mode
* NeverZero patch for afl-gcc, llvm_mode, qemu_mode and unicorn_mode which prevents a wrapping map value to zero, increases coverage
* Persistent mode and deferred forkserver for qemu_mode
* Win32 PE binary-only fuzzing with QEMU and Wine
* Radamsa mutator (as a custom mutator).
* QBDI mode to fuzz android native libraries via QBDI framework
* The new CmpLog instrumentation for LLVM and QEMU inspired by [Redqueen](https://www.syssec.ruhr-uni-bochum.de/media/emma/veroeffentlichungen/2018/12/17/NDSS19-Redqueen.pdf)
* LLVM mode Ngram coverage by Adrian Herrera [https://github.com/adrianherrera/afl-ngram-pass](https://github.com/adrianherrera/afl-ngram-pass)
A more thorough list is available in the [PATCHES](docs/PATCHES.md) file.
| Feature/Instrumentation | afl-gcc | llvm_mode | gcc_plugin | qemu_mode | unicorn_mode |
| ----------------------- |:-------:|:---------:|:----------:|:----------------:|:------------:|
| NeverZero | x | x(1) | (2) | x | x |
| Persistent mode | | x | x | x86[_64]/arm[64] | x |
| LAF-Intel / CompCov | | x | | x86[_64]/arm[64] | x86[_64]/arm |
| CmpLog | | x | | x86[_64]/arm[64] | |
| Instrument file list | | x | x | (x)(3) | |
| Non-colliding coverage | | x(4) | | (x)(5) | |
| InsTrim | | x | | | |
| Ngram prev_loc coverage | | x(6) | | | |
| Context coverage | | x | | | |
| Snapshot LKM support | | x | | (x)(5) | |
neverZero:
(1) default for LLVM >= 9.0, env var for older version due an efficiency bug in llvm <= 8
(2) GCC creates non-performant code, hence it is disabled in gcc_plugin
(3) partially via AFL_CODE_START/AFL_CODE_END
(4) Only for LLVM >= 11 and not all targets compile
(5) upcoming, development in the branch
(6) not compatible with LTO instrumentation and needs at least LLVM >= 4.1
So all in all this is the best-of afl that is currently out there :-)
For new versions and additional information, check out:
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
To compare notes with other users or get notified about major new features,
send a mail to <afl-users+subscribe@googlegroups.com>.
See [docs/QuickStartGuide.md](docs/QuickStartGuide.md) if you don't have time to
read this file.
## Branches
The following branches exist:
* [master/trunk](https://github.com/AFLplusplus/AFLplusplus/) : stable state of afl++ - it is synced from dev from time to
time when we are satisfied with it's stability
* [dev](https://github.com/AFLplusplus/AFLplusplus/tree/dev) : development state of afl++ - bleeding edge and you might catch a
checkout which does not compile or has a bug. *We only accept PRs in dev!!*
* (any other) : experimental branches to work on specific features or testing
new functionality or changes.
For releases, please see the [Releases](https://github.com/AFLplusplus/AFLplusplus/releases) tab.
## Google Summer of Code 2020 (and any other students and enthusiast developers)
We are happy to be part of [Google Summer of Code 2020](https://summerofcode.withgoogle.com/organizations/5100744400699392/)! :-)
We have several ideas we would like to see in AFL++ to make it even better.
However, we already work on so many things that we do not have the time for
all the big ideas.
This can be your way to support and contribute to AFL++ - extend it to
something cool.
We have an idea list in [docs/ideas.md](docs/ideas.md).
For everyone who wants to contribute (and send pull requests) please read
[CONTRIBUTING.md](CONTRIBUTING.md) before your submit.
## Building and installing afl++
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-11 -
hence afl-clang-lto is available!) or just pull directly from the docker hub:
```shell
docker pull aflplusplus/aflplusplus
docker run -ti -v /location/of/your/target:/src aflplusplus/aflplusplus
```
This container is automatically generated when a push to master happens.
You will find your target source code in /src in the container.
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.
If you want to build afl++ yourself you have many options.
The easiest is to build and install everything:
Note: you can also pull `aflplusplus/aflplusplus:dev` which is the most current
development state of AFL++.
```shell
sudo apt install build-essential libtool-bin python3-dev automake flex bison libglib2.0-dev libpixman-1-dev clang python3-setuptools llvm
make distrib
sudo make install
```
It is recommended to install the newest available gcc and clang and llvm-dev
possible in your distribution!
To build AFL++ yourself - *which we recommend* - continue at
[docs/INSTALL.md](docs/INSTALL.md).
Note that "make distrib" also builds llvm_mode, qemu_mode, unicorn_mode and
more. If you just want plain afl then do "make all", however compiling and
using at least llvm_mode is highly recommended for much better results -
hence in this case
## Quick start: Fuzzing with AFL++
```shell
make source-only
```
is what you should choose.
*NOTE: Before you start, please read about the
[common sense risks of fuzzing](docs/fuzzing_in_depth.md#0-common-sense-risks).*
These build targets exist:
This is a quick start for fuzzing targets with the source code available. To
read about the process in detail, see
[docs/fuzzing_in_depth.md](docs/fuzzing_in_depth.md).
* all: just the main afl++ binaries
* binary-only: everything for binary-only fuzzing: qemu_mode, unicorn_mode, libdislocator, libtokencap
* source-only: everything for source code fuzzing: llvm_mode, libdislocator, libtokencap
* distrib: everything (for both binary-only and source code fuzzing)
* man: creates simple man pages from the help option of the programs
* install: installs everything you have compiled with the build options above
* clean: cleans everything compiled, not downloads (unless not on a checkout)
* deepclean: cleans everything including downloads
* code-format: format the code, do this before you commit and send a PR please!
* tests: runs test cases to ensure that all features are still working as they should
* unit: perform unit tests (based on cmocka)
* help: shows these build options
To learn about fuzzing other targets, see:
* Binary-only targets:
[docs/fuzzing_binary-only_targets.md](docs/fuzzing_binary-only_targets.md)
* Network services:
[docs/best_practices.md#fuzzing-a-network-service](docs/best_practices.md#fuzzing-a-network-service)
* GUI programs:
[docs/best_practices.md#fuzzing-a-gui-program](docs/best_practices.md#fuzzing-a-gui-program)
[Unless you are on Mac OS X](https://developer.apple.com/library/archive/qa/qa1118/_index.html) you can also build statically linked versions of the
afl++ binaries by passing the STATIC=1 argument to make:
Step-by-step quick start:
```shell
make all STATIC=1
```
1. Compile the program or library to be fuzzed using `afl-cc`. A common way to
do this would be:
These build options exist:
```
CC=/path/to/afl-cc CXX=/path/to/afl-c++ ./configure --disable-shared
make clean all
```
* STATIC - compile AFL++ static
* ASAN_BUILD - compiles with memory sanitizer for debug purposes
* PROFILING - compile with profiling information (gprof)
* NO_PYTHON - disable python support
* 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)
2. Get a small but valid input file that makes sense to the program. When
fuzzing verbose syntax (SQL, HTTP, etc.), create a dictionary as described in
[dictionaries/README.md](dictionaries/README.md), too.
e.g.: make ASAN_BUILD=1
3. If the program reads from stdin, run `afl-fuzz` like so:
## Challenges of guided fuzzing
```
./afl-fuzz -i seeds_dir -o output_dir -- \
/path/to/tested/program [...program's cmdline...]
```
Fuzzing is one of the most powerful and proven strategies for identifying
security issues in real-world software; it is responsible for the vast
majority of remote code execution and privilege escalation bugs found to date
in security-critical software.
To add a dictionary, add `-x /path/to/dictionary.txt` to afl-fuzz.
Unfortunately, fuzzing is also relatively shallow; blind, random mutations
make it very unlikely to reach certain code paths in the tested code, leaving
some vulnerabilities firmly outside the reach of this technique.
If the program takes input from a file, you can put `@@` in the program's
command line; AFL++ will put an auto-generated file name in there for you.
There have been numerous attempts to solve this problem. One of the early
approaches - pioneered by Tavis Ormandy - is corpus distillation. The method
relies on coverage signals to select a subset of interesting seeds from a
massive, high-quality corpus of candidate files, and then fuzz them by
traditional means. The approach works exceptionally well but requires such
a corpus to be readily available. In addition, block coverage measurements
provide only a very simplistic understanding of the program state and are less
useful for guiding the fuzzing effort in the long haul.
4. Investigate anything shown in red in the fuzzer UI by promptly consulting
[docs/afl-fuzz_approach.md#understanding-the-status-screen](docs/afl-fuzz_approach.md#understanding-the-status-screen).
Other, more sophisticated research has focused on techniques such as program
flow analysis ("concolic execution"), symbolic execution, or static analysis.
All these methods are extremely promising in experimental settings, but tend
to suffer from reliability and performance problems in practical uses - and
currently do not offer a viable alternative to "dumb" fuzzing techniques.
5. You will find found crashes and hangs in the subdirectories `crashes/` and
`hangs/` in the `-o output_dir` directory. You can replay the crashes by
feeding them to the target, e.g. if your target is using stdin:
```
cat output_dir/crashes/id:000000,* | /path/to/tested/program [...program's cmdline...]
```
## The afl-fuzz approach
You can generate cores or use gdb directly to follow up the crashes.
American Fuzzy Lop is a brute-force fuzzer coupled with an exceedingly simple
but rock-solid instrumentation-guided genetic algorithm. It uses a modified
form of edge coverage to effortlessly pick up subtle, local-scale changes to
program control flow.
6. We cannot stress this enough - if you want to fuzz effectively, read the
[docs/fuzzing_in_depth.md](docs/fuzzing_in_depth.md) document!
Simplifying a bit, the overall algorithm can be summed up as:
## Contact
1) Load user-supplied initial test cases into the queue,
Questions? Concerns? Bug reports?
2) Take the next input file from the queue,
* The contributors can be reached via (e.g., by creating an issue):
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus).
* Take a look at our [FAQ](docs/FAQ.md). If you find an interesting or important
question missing, submit it via
[https://github.com/AFLplusplus/AFLplusplus/discussions](https://github.com/AFLplusplus/AFLplusplus/discussions).
* Best: join the [Awesome Fuzzing](https://discord.gg/gCraWct) Discord server.
* There is a (not really used) mailing list for the AFL/AFL++ project
([browse archive](https://groups.google.com/group/afl-users)). To compare
notes with other users or to get notified about major new features, send an
email to <afl-users+subscribe@googlegroups.com>, but note that this is not
managed by us.
3) Attempt to trim the test case to the smallest size that doesn't alter
the measured behavior of the program,
## Branches
4) Repeatedly mutate the file using a balanced and well-researched variety
of traditional fuzzing strategies,
The following branches exist:
5) If any of the generated mutations resulted in a new state transition
recorded by the instrumentation, add mutated output as a new entry in the
queue.
* [release](https://github.com/AFLplusplus/AFLplusplus/tree/release): the latest
release
* [stable/trunk](https://github.com/AFLplusplus/AFLplusplus/): stable state of
AFL++ - it is synced from dev from time to time when we are satisfied with its
stability
* [dev](https://github.com/AFLplusplus/AFLplusplus/tree/dev): development state
of AFL++ - bleeding edge and you might catch a checkout which does not compile
or has a bug. **We only accept PRs (pull requests) for the 'dev' branch!**
* (any other): experimental branches to work on specific features or testing new
functionality or changes.
6) Go to 2.
## Help wanted
The discovered test cases are also periodically culled to eliminate ones that
have been obsoleted by newer, higher-coverage finds; and undergo several other
instrumentation-driven effort minimization steps.
We have several [ideas](docs/ideas.md) we would like to see in AFL++ to make it
even better. However, we already work on so many things that we do not have the
time for all the big ideas.
As a side result of the fuzzing process, the tool creates a small,
self-contained corpus of interesting test cases. These are extremely useful
for seeding other, labor- or resource-intensive testing regimes - for example,
for stress-testing browsers, office applications, graphics suites, or
closed-source tools.
This can be your way to support and contribute to AFL++ - extend it to do
something cool.
The fuzzer is thoroughly tested to deliver out-of-the-box performance far
superior to blind fuzzing or coverage-only tools.
For everyone who wants to contribute (and send pull requests), please read our
[contributing guidelines](CONTRIBUTING.md) before you submit.
## Instrumenting programs for use with AFL
PLEASE NOTE: llvm_mode compilation with afl-clang-fast/afl-clang-fast++
instead of afl-gcc/afl-g++ is much faster and has many cool features.
See llvm_mode/ - however few code does not compile with llvm.
We support llvm versions 3.4 to 11.
When source code is available, instrumentation can be injected by a companion
tool that works as a drop-in replacement for gcc or clang in any standard build
process for third-party code.
The instrumentation has a fairly modest performance impact; in conjunction with
other optimizations implemented by afl-fuzz, most programs can be fuzzed as fast
or even faster than possible with traditional tools.
The correct way to recompile the target program may vary depending on the
specifics of the build process, but a nearly-universal approach would be:
```shell
CC=/path/to/afl/afl-gcc ./configure
make clean all
```
For C++ programs, you'd would also want to set `CXX=/path/to/afl/afl-g++`.
The clang wrappers (afl-clang and afl-clang++) can be used in the same way;
clang users may also opt to leverage a higher-performance instrumentation mode,
as described in [llvm_mode/README.md](llvm_mode/README.md).
Clang/LLVM has a much better performance and works with LLVM version 3.4 to 11.
Using the LAF Intel performance enhancements are also recommended, see
[llvm_mode/README.laf-intel.md](llvm_mode/README.laf-intel.md)
Using partial instrumentation is also recommended, see
[llvm_mode/README.instrument_file.md](llvm_mode/README.instrument_file.md)
When testing libraries, you need to find or write a simple program that reads
data from stdin or from a file and passes it to the tested library. In such a
case, it is essential to link this executable against a static version of the
instrumented library or to make sure that the correct .so file is loaded at
runtime (usually by setting `LD_LIBRARY_PATH`). The simplest option is a static
build, usually possible via:
```shell
CC=/path/to/afl/afl-gcc ./configure --disable-shared
```
Setting `AFL_HARDEN=1` when calling 'make' will cause the CC wrapper to
automatically enable code hardening options that make it easier to detect
simple memory bugs. Libdislocator, a helper library included with AFL (see
[libdislocator/README.md](libdislocator/README.md)) can help uncover heap corruption issues, too.
PS. ASAN users are advised to review [docs/notes_for_asan.md](docs/notes_for_asan.md)
file for important caveats.
## Instrumenting binary-only apps
When source code is *NOT* available, the fuzzer offers experimental support for
fast, on-the-fly instrumentation of black-box binaries. This is accomplished
with a version of QEMU running in the lesser-known "user space emulation" mode.
QEMU is a project separate from AFL, but you can conveniently build the
feature by doing:
```shell
cd qemu_mode
./build_qemu_support.sh
```
For additional instructions and caveats, see [qemu_mode/README.md](qemu_mode/README.md).
If possible you should use the persistent mode, see [qemu_mode/README.persistent.md](qemu_mode/README.persistent.md).
The mode is approximately 2-5x slower than compile-time instrumentation, is
less conducive to parallelization, and may have some other quirks.
If [afl-dyninst](https://github.com/vanhauser-thc/afl-dyninst) works for
your binary, then you can use afl-fuzz normally and it will have twice
the speed compared to qemu_mode.
A more comprehensive description of these and other options can be found in
[docs/binaryonly_fuzzing.md](docs/binaryonly_fuzzing.md)
## Good examples and writeups
Here are some good writeups to show how to effectively use AFL++:
* [https://aflplus.plus/docs/tutorials/libxml2_tutorial/](https://aflplus.plus/docs/tutorials/libxml2_tutorial/)
* [https://bananamafia.dev/post/gb-fuzz/](https://bananamafia.dev/post/gb-fuzz/)
* [https://securitylab.github.com/research/fuzzing-challenges-solutions-1](https://securitylab.github.com/research/fuzzing-challenges-solutions-1)
* [https://securitylab.github.com/research/fuzzing-sockets-FTP](https://securitylab.github.com/research/fuzzing-sockets-FTP)
If you are interested in fuzzing structured data (where you define what the
structure is), these two links have you covered:
* [https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator)
* [https://github.com/thebabush/afl-libprotobuf-mutator](https://github.com/thebabush/afl-libprotobuf-mutator)
If you find other good ones, please send them to us :-)
## Power schedules
The power schedules were copied from Marcel Böhme's excellent AFLfast
implementation and expand on the ability to discover new paths and
therefore may increase the code coverage.
The available schedules are:
- explore (default, original AFL)
- exploit (original AFL)
- fast (AFLfast)
- coe (AFLfast)
- quad (AFLfast)
- lin (AFLfast)
- rare (afl++ experimental)
- mmopt (afl++ experimental)
- seek (afl++ experimental)
In parallel mode (-M/-S, several instances with the shared queue), we suggest to
run the main node using the explore or fast schedule (-p explore) and the secondary
nodes with a combination of cut-off-exponential (-p coe), exponential (-p fast),
explore (-p explore) and mmopt (-p mmopt) schedules. If a schedule does
not perform well for a target, restart the secondary nodes with a different schedule.
In single mode, using -p fast is usually slightly more beneficial than the
default explore mode.
(We don't want to change the default behavior of afl, so "fast" has not been
made the default mode).
More details can be found in the paper published at the 23rd ACM Conference on
Computer and Communications Security [CCS'16](https://www.sigsac.org/ccs/CCS2016/accepted-papers/)
## Choosing initial test cases
To operate correctly, the fuzzer requires one or more starting file that
contains a good example of the input data normally expected by the targeted
application. There are two basic rules:
- Keep the files small. Under 1 kB is ideal, although not strictly necessary.
For a discussion of why size matters, see [perf_tips.md](docs/perf_tips.md).
- Use multiple test cases only if they are functionally different from
each other. There is no point in using fifty different vacation photos
to fuzz an image library.
You can find many good examples of starting files in the testcases/ subdirectory
that comes with this tool.
PS. If a large corpus of data is available for screening, you may want to use
the afl-cmin utility to identify a subset of functionally distinct files that
exercise different code paths in the target binary.
## Fuzzing binaries
The fuzzing process itself is carried out by the afl-fuzz utility. This program
requires a read-only directory with initial test cases, a separate place to
store its findings, plus a path to the binary to test.
For target binaries that accept input directly from stdin, the usual syntax is:
```shell
./afl-fuzz -i testcase_dir -o findings_dir /path/to/program [...params...]
```
For programs that take input from a file, use '@@' to mark the location in
the target's command line where the input file name should be placed. The
fuzzer will substitute this for you:
```shell
./afl-fuzz -i testcase_dir -o findings_dir /path/to/program @@
```
You can also use the -f option to have the mutated data written to a specific
file. This is useful if the program expects a particular file extension or so.
Non-instrumented binaries can be fuzzed in the QEMU mode (add -Q in the command
line) or in a traditional, blind-fuzzer mode (specify -n).
You can use -t and -m to override the default timeout and memory limit for the
executed process; rare examples of targets that may need these settings touched
include compilers and video decoders.
Tips for optimizing fuzzing performance are discussed in [perf_tips.md](docs/perf_tips.md).
Note that afl-fuzz starts by performing an array of deterministic fuzzing
steps, which can take several days, but tend to produce neat test cases. If you
want quick & dirty results right away - akin to zzuf and other traditional
fuzzers - add the -d option to the command line.
## Interpreting output
See the [docs/status_screen.md](docs/status_screen.md) file for information on
how to interpret the displayed stats and monitor the health of the process. Be
sure to consult this file especially if any UI elements are highlighted in red.
The fuzzing process will continue until you press Ctrl-C. At a minimum, you want
to allow the fuzzer to complete one queue cycle, which may take anywhere from a
couple of hours to a week or so.
There are three subdirectories created within the output directory and updated
in real-time:
- queue/ - test cases for every distinctive execution path, plus all the
starting files given by the user. This is the synthesized corpus
mentioned in section 2.
Before using this corpus for any other purposes, you can shrink
it to a smaller size using the afl-cmin tool. The tool will find
a smaller subset of files offering equivalent edge coverage.
- crashes/ - unique test cases that cause the tested program to receive a
fatal signal (e.g., SIGSEGV, SIGILL, SIGABRT). The entries are
grouped by the received signal.
- hangs/ - unique test cases that cause the tested program to time out. The
default time limit before something is classified as a hang is
the larger of 1 second and the value of the -t parameter.
The value can be fine-tuned by setting AFL_HANG_TMOUT, but this
is rarely necessary.
Crashes and hangs are considered "unique" if the associated execution paths
involve any state transitions not seen in previously-recorded faults. If a
single bug can be reached in multiple ways, there will be some count inflation
early in the process, but this should quickly taper off.
The file names for crashes and hangs are correlated with the parent, non-faulting
queue entries. This should help with debugging.
When you can't reproduce a crash found by afl-fuzz, the most likely cause is
that you are not setting the same memory limit as used by the tool. Try:
```shell
LIMIT_MB=50
( ulimit -Sv $[LIMIT_MB << 10]; /path/to/tested_binary ... )
```
Change LIMIT_MB to match the -m parameter passed to afl-fuzz. On OpenBSD,
also change -Sv to -Sd.
Any existing output directory can be also used to resume aborted jobs; try:
```shell
./afl-fuzz -i- -o existing_output_dir [...etc...]
```
If you have gnuplot installed, you can also generate some pretty graphs for any
active fuzzing task using afl-plot. For an example of how this looks like,
see [http://lcamtuf.coredump.cx/afl/plot/](http://lcamtuf.coredump.cx/afl/plot/).
## Parallelized fuzzing
Every instance of afl-fuzz takes up roughly one core. This means that on
multi-core systems, parallelization is necessary to fully utilize the hardware.
For tips on how to fuzz a common target on multiple cores or multiple networked
machines, please refer to [docs/parallel_fuzzing.md](docs/parallel_fuzzing.md).
The parallel fuzzing mode also offers a simple way for interfacing AFL to other
fuzzers, to symbolic or concolic execution engines, and so forth; again, see the
last section of [docs/parallel_fuzzing.md](docs/parallel_fuzzing.md) for tips.
## Fuzzer dictionaries
By default, afl-fuzz mutation engine is optimized for compact data formats -
say, images, multimedia, compressed data, regular expression syntax, or shell
scripts. It is somewhat less suited for languages with particularly verbose and
redundant verbiage - notably including HTML, SQL, or JavaScript.
To avoid the hassle of building syntax-aware tools, afl-fuzz provides a way to
seed the fuzzing process with an optional dictionary of language keywords,
magic headers, or other special tokens associated with the targeted data type
-- and use that to reconstruct the underlying grammar on the go:
[http://lcamtuf.blogspot.com/2015/01/afl-fuzz-making-up-grammar-with.html](http://lcamtuf.blogspot.com/2015/01/afl-fuzz-making-up-grammar-with.html)
To use this feature, you first need to create a dictionary in one of the two
formats discussed in [dictionaries/README.md](dictionaries/README.md);
and then point the fuzzer to it via the -x option in the command line.
(Several common dictionaries are already provided in that subdirectory, too.)
There is no way to provide more structured descriptions of the underlying
syntax, but the fuzzer will likely figure out some of this based on the
instrumentation feedback alone. This actually works in practice, say:
[http://lcamtuf.blogspot.com/2015/04/finding-bugs-in-sqlite-easy-way.html](http://lcamtuf.blogspot.com/2015/04/finding-bugs-in-sqlite-easy-way.html)
PS. Even when no explicit dictionary is given, afl-fuzz will try to extract
existing syntax tokens in the input corpus by watching the instrumentation
very closely during deterministic byte flips. This works for some types of
parsers and grammars but isn't nearly as good as the -x mode.
If a dictionary is really hard to come by, another option is to let AFL run
for a while and then use the token capture library that comes as a companion
utility with AFL. For that, see [libtokencap/README.md](libtokencap/README.tokencap.md).
## Crash triage
The coverage-based grouping of crashes usually produces a small data set that
can be quickly triaged manually or with a very simple GDB or Valgrind script.
Every crash is also traceable to its parent non-crashing test case in the
queue, making it easier to diagnose faults.
Having said that, it's important to acknowledge that some fuzzing crashes can be
difficult to quickly evaluate for exploitability without a lot of debugging and
code analysis work. To assist with this task, afl-fuzz supports a very unique
"crash exploration" mode enabled with the -C flag.
In this mode, the fuzzer takes one or more crashing test cases as the input
and uses its feedback-driven fuzzing strategies to very quickly enumerate all
code paths that can be reached in the program while keeping it in the
crashing state.
Mutations that do not result in a crash are rejected; so are any changes that
do not affect the execution path.
The output is a small corpus of files that can be very rapidly examined to see
what degree of control the attacker has over the faulting address, or whether
it is possible to get past an initial out-of-bounds read - and see what lies
beneath.
Oh, one more thing: for test case minimization, give afl-tmin a try. The tool
can be operated in a very simple way:
```shell
./afl-tmin -i test_case -o minimized_result -- /path/to/program [...]
```
The tool works with crashing and non-crashing test cases alike. In the crash
mode, it will happily accept instrumented and non-instrumented binaries. In the
non-crashing mode, the minimizer relies on standard AFL instrumentation to make
the file simpler without altering the execution path.
The minimizer accepts the -m, -t, -f and @@ syntax in a manner compatible with
afl-fuzz.
Another recent addition to AFL is the afl-analyze tool. It takes an input
file, attempts to sequentially flip bytes, and observes the behavior of the
tested program. It 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. More info about its operation can be found
near the end of [docs/technical_details.md](docs/technical_details.md).
## Going beyond crashes
Fuzzing is a wonderful and underutilized technique for discovering non-crashing
design and implementation errors, too. Quite a few interesting bugs have been
found by modifying the target programs to call abort() when say:
- Two bignum libraries produce different outputs when given the same
fuzzer-generated input,
- An image library produces different outputs when asked to decode the same
input image several times in a row,
- A serialization / deserialization library fails to produce stable outputs
when iteratively serializing and deserializing fuzzer-supplied data,
- A compression library produces an output inconsistent with the input file
when asked to compress and then decompress a particular blob.
Implementing these or similar sanity checks usually takes very little time;
if you are the maintainer of a particular package, you can make this code
conditional with `#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION` (a flag also
shared with libfuzzer) or `#ifdef __AFL_COMPILER` (this one is just for AFL).
## Common-sense risks
Please keep in mind that, similarly to many other computationally-intensive
tasks, fuzzing may put a strain on your hardware and on the OS. In particular:
- Your CPU will run hot and will need adequate cooling. In most cases, if
cooling is insufficient or stops working properly, CPU speeds will be
automatically throttled. That said, especially when fuzzing on less
suitable hardware (laptops, smartphones, etc), it's not entirely impossible
for something to blow up.
- Targeted programs may end up erratically grabbing gigabytes of memory or
filling up disk space with junk files. AFL tries to enforce basic memory
limits, but can't prevent each and every possible mishap. The bottom line
is that you shouldn't be fuzzing on systems where the prospect of data loss
is not an acceptable risk.
- Fuzzing involves billions of reads and writes to the filesystem. On modern
systems, this will be usually heavily cached, resulting in fairly modest
"physical" I/O - but there are many factors that may alter this equation.
It is your responsibility to monitor for potential trouble; with very heavy
I/O, the lifespan of many HDDs and SSDs may be reduced.
A good way to monitor disk I/O on Linux is the 'iostat' command:
```shell
$ iostat -d 3 -x -k [...optional disk ID...]
```
## Known limitations & areas for improvement
Here are some of the most important caveats for AFL:
- AFL detects faults by checking for the first spawned process dying due to
a signal (SIGSEGV, SIGABRT, etc). Programs that install custom handlers for
these signals may need to have the relevant code commented out. In the same
vein, faults in child processes spawned by the fuzzed target may evade
detection unless you manually add some code to catch that.
- As with any other brute-force tool, the fuzzer offers limited coverage if
encryption, checksums, cryptographic signatures, or compression are used to
wholly wrap the actual data format to be tested.
To work around this, you can comment out the relevant checks (see
examples/libpng_no_checksum/ for inspiration); if this is not possible,
you can also write a postprocessor, one of the hooks of custom mutators.
See [docs/custom_mutators.md](docs/custom_mutators.md) on how to use
`AFL_CUSTOM_MUTATOR_LIBRARY`
- There are some unfortunate trade-offs with ASAN and 64-bit binaries. This
isn't due to any specific fault of afl-fuzz; see [docs/notes_for_asan.md](docs/notes_for_asan.md)
for tips.
- 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 may offer a relatively simple option, too - see:
[https://github.com/zardus/preeny](https://github.com/zardus/preeny)
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)
- AFL doesn't output human-readable coverage data. If you want to monitor
coverage, use afl-cov from Michael Rash: [https://github.com/mrash/afl-cov](https://github.com/mrash/afl-cov)
- Occasionally, sentient machines rise against their creators. If this
happens to you, please consult [http://lcamtuf.coredump.cx/prep/](http://lcamtuf.coredump.cx/prep/).
Beyond this, see INSTALL for platform-specific tips.
## Special thanks
Many of the improvements to the original AFL and AFL++ wouldn't be possible
without feedback, bug reports, or patches from our contributors.
Many of the improvements to the original afl and afl++ wouldn't be possible
without feedback, bug reports, or patches from:
Thank you! (For people sending pull requests - please add yourself to this list
:-)
```
Jann Horn Hanno Boeck
Felix Groebert Jakub Wilk
Richard W. M. Jones Alexander Cherepanov
Tom Ritter Hovik Manucharyan
Sebastian Roschke Eberhard Mattes
Padraig Brady Ben Laurie
@dronesec Luca Barbato
Tobias Ospelt Thomas Jarosch
Martin Carpenter Mudge Zatko
Joe Zbiciak Ryan Govostes
Michael Rash William Robinet
Jonathan Gray Filipe Cabecinhas
Nico Weber Jodie Cunningham
Andrew Griffiths Parker Thompson
Jonathan Neuschaefer Tyler Nighswander
Ben Nagy Samir Aguiar
Aidan Thornton Aleksandar Nikolich
Sam Hakim Laszlo Szekeres
David A. Wheeler Turo Lamminen
Andreas Stieger Richard Godbee
Louis Dassy teor2345
Alex Moneger Dmitry Vyukov
Keegan McAllister Kostya Serebryany
Richo Healey Martijn Bogaard
rc0r Jonathan Foote
Christian Holler Dominique Pelle
Jacek Wielemborek Leo Barnes
Jeremy Barnes Jeff Trull
Guillaume Endignoux ilovezfs
Daniel Godas-Lopez Franjo Ivancic
Austin Seipp Daniel Komaromy
Daniel Binderman Jonathan Metzman
Vegard Nossum Jan Kneschke
Kurt Roeckx Marcel Boehme
Van-Thuan Pham Abhik Roychoudhury
Joshua J. Drake Toby Hutton
Rene Freingruber Sergey Davidoff
Sami Liedes Craig Young
Andrzej Jackowski Daniel Hodson
Nathan Voss Dominik Maier
Andrea Biondo Vincent Le Garrec
Khaled Yakdan Kuang-che Wu
Josephine Calliotte Konrad Welc
```
<details>
Thank you!
(For people sending pull requests - please add yourself to this list :-)
<summary>List of contributors</summary>
## Contact
```
Jann Horn Hanno Boeck
Felix Groebert Jakub Wilk
Richard W. M. Jones Alexander Cherepanov
Tom Ritter Hovik Manucharyan
Sebastian Roschke Eberhard Mattes
Padraig Brady Ben Laurie
@dronesec Luca Barbato
Tobias Ospelt Thomas Jarosch
Martin Carpenter Mudge Zatko
Joe Zbiciak Ryan Govostes
Michael Rash William Robinet
Jonathan Gray Filipe Cabecinhas
Nico Weber Jodie Cunningham
Andrew Griffiths Parker Thompson
Jonathan Neuschaefer Tyler Nighswander
Ben Nagy Samir Aguiar
Aidan Thornton Aleksandar Nikolich
Sam Hakim Laszlo Szekeres
David A. Wheeler Turo Lamminen
Andreas Stieger Richard Godbee
Louis Dassy teor2345
Alex Moneger Dmitry Vyukov
Keegan McAllister Kostya Serebryany
Richo Healey Martijn Bogaard
rc0r Jonathan Foote
Christian Holler Dominique Pelle
Jacek Wielemborek Leo Barnes
Jeremy Barnes Jeff Trull
Guillaume Endignoux ilovezfs
Daniel Godas-Lopez Franjo Ivancic
Austin Seipp Daniel Komaromy
Daniel Binderman Jonathan Metzman
Vegard Nossum Jan Kneschke
Kurt Roeckx Marcel Boehme
Van-Thuan Pham Abhik Roychoudhury
Joshua J. Drake Toby Hutton
Rene Freingruber Sergey Davidoff
Sami Liedes Craig Young
Andrzej Jackowski Daniel Hodson
Nathan Voss Dominik Maier
Andrea Biondo Vincent Le Garrec
Khaled Yakdan Kuang-che Wu
Josephine Calliotte Konrad Welc
Thomas Rooijakkers David Carlier
Ruben ten Hove Joey Jiao
fuzzah @intrigus-lgtm
```
Questions? Concerns? Bug reports? The contributors can be reached via
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
</details>
## Cite
If you use AFL++ in scientific work, consider citing
[our paper](https://www.usenix.org/conference/woot20/presentation/fioraldi)
presented at WOOT'20:
Andrea Fioraldi, Dominik Maier, Heiko Eißfeldt, and Marc Heuse. “AFL++: Combining incremental steps of fuzzing research”. In 14th USENIX Workshop on Offensive Technologies (WOOT 20). USENIX Association, Aug. 2020.
<details>
<summary>BibTeX</summary>
```bibtex
@inproceedings {AFLplusplus-Woot20,
author = {Andrea Fioraldi and Dominik Maier and Heiko Ei{\ss}feldt and Marc Heuse},
title = {{AFL++}: Combining Incremental Steps of Fuzzing Research},
booktitle = {14th {USENIX} Workshop on Offensive Technologies ({WOOT} 20)},
year = {2020},
publisher = {{USENIX} Association},
month = aug,
}
```
</details>
There is also a mailing list for the afl project; to join, send a mail to
<afl-users+subscribe@googlegroups.com>. Or, if you prefer to browse
archives first, try: [https://groups.google.com/group/afl-users](https://groups.google.com/group/afl-users)

49
TODO.md
View File

@ -1,37 +1,32 @@
# TODO list for AFL++
## Should
## Roadmap 2.66+
- support afl_custom_{send,post_process}, 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
## 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
- AFL_MAP_SIZE for qemu_mode and unicorn_mode
- namespace for targets? e.g. network
- learn from honggfuzz (mutations, maybe ptrace?)
- CPU affinity for many cores? There seems to be an issue > 96 cores
## Further down the road
QEMU mode/FRIDA mode:
afl-fuzz:
- ascii_only mode for mutation output - or use a custom mutator for this?
- setting min_len/max_len/start_offset/end_offset limits for mutation output
llvm_mode:
- LTO - imitate sancov
gcc_plugin:
- (wait for submission then decide)
- laf-intel
- better instrumentation (seems to be better with gcc-9+)
qemu_mode:
- update to 5.x (if the performance bug if gone)
- non colliding instrumentation
- rename qemu specific envs to AFL_QEMU (AFL_ENTRYPOINT, AFL_CODE_START/END,
AFL_COMPCOV_LEVEL?)
- add AFL_QEMU_EXITPOINT (maybe multiple?), maybe pointless as there is
- add AFL_QEMU_EXITPOINT (maybe multiple?), maybe pointless as we have
persistent mode
## Ideas
- LTO/sancov: write current edge to prev_loc and use that information when
using cmplog or __sanitizer_cov_trace_cmp*. maybe we can deduct by follow up
edge numbers that both following cmp paths have been found and then disable
working on this edge id -> cmplog_intelligence branch
- use cmplog colorization taint result for havoc locations?
- add/implement AFL_QEMU_INST_LIBLIST and AFL_QEMU_NOINST_PROGRAM
- add/implement AFL_QEMU_INST_REGIONS as a list of _START/_END addresses

189
afl-cmin
View File

@ -105,33 +105,21 @@ function usage() {
"Execution control settings:\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 (default: none)\n" \
" -O - use binary-only instrumentation (FRIDA mode)\n" \
" -t msec - run time limit for child process (none)\n" \
" -Q - use binary-only instrumentation (QEMU mode)\n" \
" -U - use unicorn-based instrumentation (unicorn 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" \
"For additional tips, please consult docs/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 termination\n" \
" (default: SIGTERM). If this is not set and AFL_KILL_SIGNAL is set,\n" \
" 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_PATH: path for the afl-showmap binary\n" \
"AFL_SKIP_BIN_CHECK: skip check for target binary\n" \
"AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n"
exit 1
}
@ -140,23 +128,14 @@ function exists_and_is_executable(binarypath) {
}
BEGIN {
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:eACOQU?")) != -1) {
while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eCQU?")) != -1) {
if (_go_c == "i") {
if (!Optarg) usage()
if (in_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
@ -189,32 +168,24 @@ BEGIN {
continue
} else
if (_go_c == "C") {
AFL_CMIN_CRASHES_ONLY = "AFL_CMIN_CRASHES_ONLY=1 "
continue
} else
if (_go_c == "A") {
AFL_CMIN_ALLOW_ANY = "AFL_CMIN_ALLOW_ANY=1 "
ENVIRON["AFL_CMIN_CRASHES_ONLY"] = 1
continue
} else
if (_go_c == "e") {
extra_par = extra_par " -e"
continue
} else
if (_go_c == "O") {
if (frida_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
extra_par = extra_par " -O"
frida_mode = 1
continue
} else
if (_go_c == "Q") {
if (qemu_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
extra_par = extra_par " -Q"
if ( !mem_limit_given ) mem_limit = "250"
qemu_mode = 1
continue
} else
if (_go_c == "U") {
if (unicorn_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
extra_par = extra_par " -U"
if ( !mem_limit_given ) mem_limit = "250"
unicorn_mode = 1
continue
} else
@ -224,7 +195,7 @@ BEGIN {
usage()
} # while options
if (!mem_limit) mem_limit = "none"
if (!mem_limit) mem_limit = 200
if (!timeout) timeout = "none"
# get program args
@ -233,7 +204,7 @@ BEGIN {
for (; Optind < ARGC; Optind++) {
prog_args[i++] = ARGV[Optind]
if (i > 1)
prog_args_string = prog_args_string" '"ARGV[Optind]"'"
prog_args_string = prog_args_string" "ARGV[Optind]
}
# sanity checks
@ -269,7 +240,7 @@ BEGIN {
if (!stdin_file) {
found_atat = 0
for (prog_args_ind in prog_args) {
if (match(prog_args[prog_args_ind], "@@") != 0) {
if ("@@" == prog_args[prog_args_ind]) {
found_atat = 1
break
}
@ -301,17 +272,7 @@ BEGIN {
target_bin = tnew
}
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) {
if (!ENVIRON["AFL_SKIP_BIN_CHECK"] && !qemu_mode && !unicorn_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
@ -323,13 +284,9 @@ BEGIN {
exit 1
}
#if (0 == system( "test -d "in_dir"/default" )) {
# in_dir = in_dir "/default"
#}
#
#if (0 == system( "test -d "in_dir"/queue" )) {
# in_dir = in_dir "/queue"
#}
if (0 == system( "test -d "in_dir"/queue" )) {
in_dir = in_dir "/queue"
}
system("rm -rf "trace_dir" 2>/dev/null");
system("rm "out_dir"/id[:_]* 2>/dev/null")
@ -352,18 +309,14 @@ BEGIN {
close( stdin_file )
}
# First we look in PATH
if (0 == system("command -v afl-showmap >/dev/null 2>&1")) {
"command -v afl-showmap 2>/dev/null" | getline showmap
} else {
# then we look in the current directory
if (0 == system("test -x ./afl-showmap")) {
if (!ENVIRON["AFL_PATH"]) {
if (0 == system("test -f afl-cmin")) {
showmap = "./afl-showmap"
} else {
if (ENVIRON["AFL_PATH"]) {
showmap = ENVIRON["AFL_PATH"] "/afl-showmap"
}
"command -v afl-showmap 2>/dev/null" | getline showmap
}
} else {
showmap = ENVIRON["AFL_PATH"] "/afl-showmap"
}
if (!showmap || 0 != system("test -x "showmap )) {
@ -382,65 +335,56 @@ BEGIN {
} else {
stat_format = "-f '%z %N'" # *BSD, MacOS
}
cmdline = "(cd "in_dir" && find . \\( ! -name \".*\" -a -type d \\) -o -type f -exec stat "stat_format" \\{\\} + | sort -k1n -k2r)"
#cmdline = "ls "in_dir" | (cd "in_dir" && xargs stat "stat_format" 2>/dev/null) | sort -k1n -k2r"
#cmdline = "(cd "in_dir" && stat "stat_format" *) | sort -k1n -k2r"
#cmdline = "(cd "in_dir" && ls | xargs stat "stat_format" ) | sort -k1n -k2r"
cmdline = "cd "in_dir" && find . \\( ! -name . -a -type d -prune \\) -o -type f -exec stat "stat_format" \\{\\} \\; | sort -k1n -k2r"
cmdline = "ls "in_dir" | (cd "in_dir" && xargs stat "stat_format") | sort -k1n -k2r"
while (cmdline | getline) {
sub(/^[0-9]+ (\.\/)?/,"",$0)
infilesSmallToBigFull[i] = $0
sub(/.*\//, "", $0)
infilesSmallToBig[i] = $0
infilesSmallToBigMap[infilesSmallToBig[i]] = infilesSmallToBigFull[i]
infilesSmallToBigFullMap[infilesSmallToBigFull[i]] = infilesSmallToBig[i]
i++
infilesSmallToBig[i++] = $0
}
in_count = i
first_file = infilesSmallToBigFull[0]
first_file = infilesSmallToBig[0]
#if (0 == system("test -d ""\""in_dir"/"first_file"\"")) {
# print "[-] Error: The input directory is empty or contains subdirectories - please fix." > "/dev/stderr"
# exit 1
#}
# Make sure that we're not dealing with a directory.
system(">\""in_dir"/.afl-cmin.test\"")
if (0 == system("ln \""in_dir"/.afl-cmin.test\" "trace_dir"/.link_test")) {
if (0 == system("test -d "in_dir"/"first_file)) {
print "[-] Error: The input directory contains subdirectories - please fix." > "/dev/stderr"
exit 1
}
if (0 == system("ln "in_dir"/"first_file" "trace_dir"/.link_test")) {
cp_tool = "ln"
} else {
cp_tool = "cp"
}
system("rm -f \""in_dir"/.afl-cmin.test\"")
if (!ENVIRON["AFL_SKIP_BIN_CHECK"]) {
# Make sure that we can actually get anything out of afl-showmap before we
# waste too much time.
# Make sure that we can actually get anything out of afl-showmap before we
# waste too much time.
print "[*] Testing the target binary..."
print "[*] Testing the target binary..."
if (!stdin_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_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
runtest = trace_dir"/.run_test"
while ((getline < runtest) > 0) {
++first_count
}
if (first_count) {
print "[+] OK, "first_count" tuples recorded."
} else {
print "[-] Error: no instrumentation output detected (perhaps crash or timeout)." > "/dev/stderr"
if (!ENVIRON["AFL_KEEP_TRACES"]) {
system("rm -rf "trace_dir" 2>/dev/null")
}
exit 1
if (!stdin_file) {
system( "AFL_CMIN_ALLOW_ANY=1 \""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 \""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/.run_test\" -Z "extra_par" -A \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null")
}
first_count = 0
runtest = trace_dir"/.run_test"
while ((getline < runtest) > 0) {
++first_count
}
if (first_count) {
print "[+] OK, "first_count" tuples recorded."
} else {
print "[-] Error: no instrumentation output detected (perhaps crash or timeout)." > "/dev/stderr"
if (!ENVIRON["AFL_KEEP_TRACES"]) {
system("rm -rf "trace_dir" 2>/dev/null")
}
exit 1
}
# Let's roll!
@ -454,16 +398,14 @@ BEGIN {
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_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)
retval = system( "AFL_CMIN_ALLOW_ANY=1 \""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_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")
retval = system( "AFL_CMIN_ALLOW_ANY=1 \""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string" </dev/null")
}
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 (retval) {
print "[!]Exit code != 0 received from afl-showmap, terminating..."
if (!ENVIRON["AFL_KEEP_TRACES"]) {
system("rm -rf "trace_dir" 2>/dev/null")
@ -489,8 +431,7 @@ BEGIN {
while (cur < in_count) {
fn = infilesSmallToBig[cur]
++cur
if (redirected == 0) { printf "\r Processing file "cur"/"in_count }
else { print " Processing file "cur"/"in_count }
printf "\r 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
@ -529,9 +470,7 @@ BEGIN {
key = field[nrFields]
++tcnt;
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]"..." }
printf "\r Processing tuple "tcnt"/"tuple_count" with count "key_count[key]"..."
if (key in keyAlreadyKnown) {
continue
}
@ -546,14 +485,14 @@ BEGIN {
# copy file unless already done
if (! (fn in file_already_copied)) {
realfile = infilesSmallToBigMap[fn]
system(cp_tool" \""in_dir"/"realfile"\" \""out_dir"/"fn"\"")
system(cp_tool" "in_dir"/"fn" "out_dir"/"fn)
file_already_copied[fn] = ""
++out_count
#printf "tuple nr %d (%d cnt=%d) -> %s\n",tcnt,key,key_count[key],fn > trace_dir"/.log"
}
}
close(sortedKeys)
print ""
print "[+] Found "tuple_count" unique tuples across "in_count" files."
if (out_count == 1) {

View File

@ -11,7 +11,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
# https://www.apache.org/licenses/LICENSE-2.0
# http://www.apache.org/licenses/LICENSE-2.0
#
# This tool tries to find the smallest subset of files in the input directory
# that still trigger the full range of instrumentation data points seen in
@ -45,7 +45,7 @@ echo
# Process command-line options...
MEM_LIMIT=none
MEM_LIMIT=200
TIMEOUT=none
unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN \
@ -53,7 +53,7 @@ unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN \
export AFL_QUIET=1
while getopts "+i:o:f:m:t:eOQUACh" opt; do
while getopts "+i:o:f:m:t:eQUCh" opt; do
case "$opt" in
@ -80,22 +80,17 @@ while getopts "+i:o:f:m:t:eOQUACh" opt; do
"e")
EXTRA_PAR="$EXTRA_PAR -e"
;;
"A")
export AFL_CMIN_ALLOW_ANY=1
;;
"C")
export AFL_CMIN_CRASHES_ONLY=1
;;
"O")
EXTRA_PAR="$EXTRA_PAR -O"
FRIDA_MODE=1
;;
"Q")
EXTRA_PAR="$EXTRA_PAR -Q"
test "$MEM_LIMIT_GIVEN" = "" && MEM_LIMIT=250
QEMU_MODE=1
;;
"U")
EXTRA_PAR="$EXTRA_PAR -U"
test "$MEM_LIMIT_GIVEN" = "" && MEM_LIMIT=250
UNICORN_MODE=1
;;
"?")
@ -125,22 +120,19 @@ 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)
-O - use binary-only instrumentation (FRIDA mode)
-Q - use binary-only instrumentation (QEMU mode)
-U - use unicorn-based instrumentation (Unicorn 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
For additional tips, please consult README.md.
For additional tips, please consult docs/README.md.
Environment variables used:
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_PATH: path for the afl-showmap binary
AFL_SKIP_BIN_CHECK: skip check for target binary
_EOF_
exit 1
@ -219,16 +211,7 @@ if [ ! -f "$TARGET_BIN" -o ! -x "$TARGET_BIN" ]; then
fi
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" = "" ]; then
if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" -a "$UNICORN_MODE" = "" ]; then
if ! grep -qF "__AFL_SHM_ID" "$TARGET_BIN"; then
echo "[-] Error: binary '$TARGET_BIN' doesn't appear to be instrumented." 1>&2
@ -242,7 +225,6 @@ if [ ! -d "$IN_DIR" ]; then
exit 1
fi
test -d "$IN_DIR/default" && IN_DIR="$IN_DIR/default"
test -d "$IN_DIR/queue" && IN_DIR="$IN_DIR/queue"
find "$OUT_DIR" -name 'id[:_]*' -maxdepth 1 -exec rm -- {} \; 2>/dev/null
@ -262,21 +244,10 @@ if [ ! "$STDIN_FILE" = "" ]; then
touch "$STDIN_FILE" || exit 1
fi
SHOWMAP=`command -v afl-showmap 2>/dev/null`
if [ -z "$SHOWMAP" ]; then
TMP="${0%/afl-cmin.bash}/afl-showmap"
if [ -x "$TMP" ]; then
SHOWMAP=$TMP
fi
fi
if [ -z "$SHOWMAP" -a -x "./afl-showmap" ]; then
SHOWMAP="./afl-showmap"
if [ "$AFL_PATH" = "" ]; then
SHOWMAP="${0%/afl-cmin.bash}/afl-showmap"
else
if [ -n "$AFL_PATH" ]; then
SHOWMAP="$AFL_PATH/afl-showmap"
fi
SHOWMAP="$AFL_PATH/afl-showmap"
fi
if [ ! -x "$SHOWMAP" ]; then
@ -323,7 +294,7 @@ if [ "$STDIN_FILE" = "" ]; then
else
cp "$IN_DIR/$FIRST_FILE" "$STDIN_FILE"
AFL_CMIN_ALLOW_ANY=1 "$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/.run_test" -Z $EXTRA_PAR -H "$STDIN_FILE" -- "$@" </dev/null
AFL_CMIN_ALLOW_ANY=1 "$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/.run_test" -Z $EXTRA_PAR -A "$STDIN_FILE" -- "$@" </dev/null
fi
@ -373,7 +344,7 @@ echo "[*] Obtaining traces for input files in '$IN_DIR'..."
cp "$IN_DIR/$fn" "$STDIN_FILE"
"$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -H "$STDIN_FILE" -- "$@" </dev/null
"$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -A "$STDIN_FILE" -- "$@" </dev/null
done

View File

@ -1,133 +0,0 @@
#!/bin/bash
# written by jhertz
#
test "$1" = "-h" -o "$1" = "-hh" && {
echo 'afl-persistent-config'
echo
echo $0
echo
echo afl-persistent-config has no command line options
echo
echo afl-persistent-config permanently reconfigures the system to a high performance fuzzing state.
echo "WARNING: this reduces the security of the system!"
echo
echo Note that there is also afl-system-config which sets additional runtime
echo configuration options.
exit 0
}
echo
echo "WARNING: This scripts makes permanent configuration changes to the system to"
echo " increase the performance for fuzzing. As a result, the system also"
echo " becomes less secure against attacks! If you use this script, setup"
echo " strong firewall rules and only make SSH available as a network"
echo " service!"
echo
echo -n "Type \"YES\" to continue: "
read ANSWER
if [[ "$ANSWER" != "YES" ]]; then
echo Input was not YES, aborting ...
exit 1
fi
echo
PLATFORM=`uname -s`
# check that we're on Mac
if [[ "$PLATFORM" = "Darwin" ]] ; then
# check if UID == 0
if [[ "$EUID" -ne 0 ]]; then
echo "You need to be root to do this. E.g. use \"sudo\""
exit 1
fi
# check if SIP is disabled
if [[ ! $(csrutil status | grep "disabled") ]]; then
echo "SIP needs to be disabled. Restart and press Command-R at reboot, Utilities => Terminal => enter \"csrutil disable\""
exit 1
fi
echo "Checks passed."
echo "Installing /Library/LaunchDaemons/shm_setup.plist"
cat << EOF > /Library/LaunchDaemons/shm_setup.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>shmemsetup</string>
<key>UserName</key>
<string>root</string>
<key>GroupName</key>
<string>wheel</string>
<key>ProgramArguments</key>
<array>
<string>/usr/sbin/sysctl</string>
<string>-w</string>
<string>kern.sysv.shmmax=524288000</string>
<string>kern.sysv.shmmin=1</string>
<string>kern.sysv.shmmni=128</string>
<string>kern.sysv.shmseg=48</string>
<string>kern.sysv.shmall=131072000</string>
</array>
<key>KeepAlive</key>
<false/>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
EOF
echo
echo "Reboot and enjoy your fuzzing"
exit 0
fi
if [[ "$PLATFORM" = "Linux" ]] ; then
# check if UID == 0
if [[ "$EUID" -ne 0 ]]; then
echo "You need to be root to do this. E.g. use \"sudo\""
exit 1
fi
echo "Checks passed."
test -d /etc/sysctl.d || echo Error: /etc/sysctl.d directory not found, cannot install shmem config
test -d /etc/sysctl.d -a '!' -e /etc/sysctl.d/99-fuzzing && {
echo "Installing /etc/sysctl.d/99-fuzzing"
cat << EOF > /etc/sysctl.d/99-fuzzing
kernel.core_uses_pid=0
kernel.core_pattern=core
kernel.randomize_va_space=0
kernel.sched_child_runs_first=1
kernel.sched_autogroup_enabled=1
kernel.sched_migration_cost_ns=50000000
kernel.sched_latency_ns=250000000
EOF
}
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=`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
}
}
echo
echo "Reboot and enjoy your fuzzing"
exit 0
fi
echo "Error: Unknown platform \"$PLATFORM\", currently supported are Linux and MacOS."
exit 1

202
afl-plot
View File

@ -12,7 +12,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
# https://www.apache.org/licenses/LICENSE-2.0
# http://www.apache.org/licenses/LICENSE-2.0
#
get_abs_path() {
@ -22,28 +22,16 @@ get_abs_path() {
echo "progress plotting utility for afl-fuzz by Michal Zalewski"
echo
GRAPHICAL="0"
if [ "$1" = "-g" ] || [ "$1" = "--graphical" ]; then
GRAPHICAL="1"
shift
fi
if [ "$#" != "2" ]; then
if [ ! "$#" = "2" ]; then
cat 1>&2 <<_EOF_
$0 [ -g | --graphical ] afl_state_dir graph_output_dir
$0 afl_state_dir graph_output_dir
This program generates gnuplot images from afl-fuzz output data.
This program generates gnuplot images from afl-fuzz output data. Usage:
Usage:
afl_state_dir should point to an existing state directory for any
active or stopped instance of afl-fuzz
graph_output_dir should point to an empty directory where this
tool can write the resulting plots to
-g, --graphical (optional) display the plots in a graphical window
(you should have built afl-plot-ui to use this option)
The afl_state_dir parameter should point to an existing state directory for any
active or stopped instance of afl-fuzz; while graph_output_dir should point to
an empty directory where this tool can write the resulting plots to.
The program will put index.html and three PNG images in the output directory;
you should be able to view it with any web browser of your choice.
@ -80,15 +68,6 @@ if [ ! -f "$inputdir/plot_data" ]; then
fi
LINES=`cat "$inputdir/plot_data" | wc -l`
if [ "$LINES" -lt 3 ]; then
echo "[-] Error: plot_data carries too little data, let it run longer." 1>&2
exit 1
fi
BANNER="`cat "$inputdir/fuzzer_stats" 2> /dev/null | grep '^afl_banner ' | cut -d: -f2- | cut -b2-`"
test "$BANNER" = "" && BANNER="(none)"
@ -111,13 +90,21 @@ if [ ! -d "$outputdir" ]; then
fi
rm -f "$outputdir/high_freq.png" "$outputdir/low_freq.png" "$outputdir/exec_speed.png" "$outputdir/edges.png"
rm -f "$outputdir/high_freq.png" "$outputdir/low_freq.png" "$outputdir/exec_speed.png"
mv -f "$outputdir/index.html" "$outputdir/index.html.orig" 2>/dev/null
GNUPLOT_SETUP="
#set xdata time
#set timefmt '%s'
#set format x \"%b %d\n%H:%M\"
echo "[*] Generating plots..."
(
cat <<_EOF_
set terminal png truecolor enhanced size 1000,300 butt
set output '$outputdir/high_freq.png'
set xdata time
set timefmt '%s'
set format x "%b %d\n%H:%M"
set tics font 'small'
unset mxtics
unset mytics
@ -131,167 +118,29 @@ set key outside
set autoscale xfixmin
set autoscale xfixmax
set xlabel \"relative time in seconds\" font \"small\"
"
PLOT_HF="
set terminal png truecolor enhanced size 1000,300 butt
set output '$outputdir/high_freq.png'
$GNUPLOT_SETUP
plot '$inputdir/plot_data' using 1:4 with filledcurve x1 title 'corpus count' linecolor rgb '#000000' fillstyle transparent solid 0.2 noborder, \\
'' using 1:3 with filledcurve x1 title 'current fuzz item' linecolor rgb '#f0f0f0' fillstyle transparent solid 0.5 noborder, \\
'' using 1:5 with lines title 'pending items' linecolor rgb '#0090ff' linewidth 3, \\
plot '$inputdir/plot_data' using 1:4 with filledcurve x1 title 'total paths' linecolor rgb '#000000' fillstyle transparent solid 0.2 noborder, \\
'' using 1:3 with filledcurve x1 title 'current path' linecolor rgb '#f0f0f0' fillstyle transparent solid 0.5 noborder, \\
'' using 1:5 with lines title 'pending paths' linecolor rgb '#0090ff' linewidth 3, \\
'' using 1:6 with lines title 'pending favs' linecolor rgb '#c00080' linewidth 3, \\
'' using 1:2 with lines title 'cycles done' linecolor rgb '#c000f0' linewidth 3
"
PLOT_LF="
set terminal png truecolor enhanced size 1000,200 butt
set output '$outputdir/low_freq.png'
$GNUPLOT_SETUP
plot '$inputdir/plot_data' using 1:8 with filledcurve x1 title '' linecolor rgb '#c00080' fillstyle transparent solid 0.2 noborder, \\
'' using 1:8 with lines title ' uniq crashes' linecolor rgb '#c00080' linewidth 3, \\
'' using 1:9 with lines title 'uniq hangs' linecolor rgb '#c000f0' linewidth 3, \\
'' using 1:10 with lines title 'levels' linecolor rgb '#0090ff' linewidth 3
"
PLOT_ES="
set terminal png truecolor enhanced size 1000,200 butt
set output '$outputdir/exec_speed.png'
$GNUPLOT_SETUP
plot '$inputdir/plot_data' using 1:11 with filledcurve x1 title '' linecolor rgb '#0090ff' fillstyle transparent solid 0.2 noborder, \\
'$inputdir/plot_data' using 1:11 with lines title ' execs/sec' linecolor rgb '#0090ff' linewidth 3 smooth bezier;
"
PLOT_EG="
set terminal png truecolor enhanced size 1000,300 butt
set output '$outputdir/edges.png'
$GNUPLOT_SETUP
plot '$inputdir/plot_data' using 1:13 with lines title ' edges' linecolor rgb '#0090ff' linewidth 3
"
if [ "$#" = "2" ] && [ "$GRAPHICAL" = "1" ]; then
afl-plot-ui -h > /dev/null 2>&1
if [ "$?" != "0" ]; then
cat 1>&2 <<_EOF_
You do not seem to have the afl-plot-ui utility installed. If you have installed afl-plot-ui, make sure the afl-plot-ui executable is in your PATH.
If you are still facing any problems, please open an issue at https://github.com/AFLplusplus/AFLplusplus/issues.
No plots have been generated. Please rerun without the "-g" or "--graphical" flag to generate the plots.
_EOF_
exit 1
fi
rm -rf "$outputdir/.tmp"
mkdir -p "$outputdir/.tmp"
mkfifo "$outputdir/.tmp/win_ids" || exit 1
afl-plot-ui > "$outputdir/.tmp/win_ids" &
W_IDS=$(cat "$outputdir/.tmp/win_ids")
rm -rf "$outputdir/.tmp"
W_ID1=$(echo "$W_IDS" | head -n 1)
W_ID2=$(echo "$W_IDS" | head -n 2 | tail -n 1)
W_ID3=$(echo "$W_IDS" | head -n 3 | tail -n 1)
W_ID4=$(echo "$W_IDS" | tail -n 1)
echo "[*] Generating plots..."
(
cat << _EOF_
$PLOT_HF
set term x11 window "$W_ID3"
set output
replot
pause mouse close
_EOF_
) | gnuplot 2> /dev/null &
(
cat << _EOF_
$PLOT_LF
set term x11 window "$W_ID4"
set output
replot
pause mouse close
_EOF_
) | gnuplot 2> /dev/null &
(
cat << _EOF_
$PLOT_ES
set term x11 window "$W_ID2"
set output
replot
pause mouse close
_EOF_
) | gnuplot 2> /dev/null &
(
cat << _EOF_
$PLOT_EG
set term x11 window "$W_ID1"
set output
replot
pause mouse close
_EOF_
) | gnuplot 2> /dev/null &
sleep 1
else
echo "[*] Generating plots..."
(
cat << _EOF_
$PLOT_HF
$PLOT_LF
$PLOT_ES
$PLOT_EG
_EOF_
) | gnuplot
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
) | gnuplot
if [ ! -s "$outputdir/exec_speed.png" ]; then
@ -309,7 +158,6 @@ cat >"$outputdir/index.html" <<_EOF_
<tr><td><b>Generated on:</b></td><td>`date`</td></tr>
</table>
<p>
<img src="edges.png" width=1000 height=300>
<img src="high_freq.png" width=1000 height=300><p>
<img src="low_freq.png" width=1000 height=200><p>
<img src="exec_speed.png" width=1000 height=200>
@ -321,7 +169,7 @@ _EOF_
# sensitive, this seems like a reasonable trade-off.
chmod 755 "$outputdir"
chmod 644 "$outputdir/high_freq.png" "$outputdir/low_freq.png" "$outputdir/exec_speed.png" "$outputdir/edges.png" "$outputdir/index.html"
chmod 644 "$outputdir/high_freq.png" "$outputdir/low_freq.png" "$outputdir/exec_speed.png" "$outputdir/index.html"
echo "[+] All done - enjoy your charts!"

View File

@ -1,59 +1,45 @@
#!/bin/sh
test "$1" = "-h" -o "$1" = "-hh" && {
test "$1" = "-h" && {
echo 'afl-system-config by Marc Heuse <mh@mh-sec.de>'
echo
echo $0
echo
echo afl-system-config has no command line options
echo
echo afl-system-config reconfigures the system to a high performance fuzzing state.
echo "WARNING: this reduces the security of the system!"
echo afl-system reconfigures the system to a high performance fuzzing state
echo WARNING: this reduces the security of the system
echo
echo Note that there is also afl-persistent-config which sets additional permanent
echo configuration options.
exit 0
exit 1
}
DONE=
PLATFORM=`uname -s`
echo This reconfigures the system to have a better fuzzing performance.
echo "WARNING: this reduces the security of the system!"
echo
if [ '!' "$EUID" = 0 ] && [ '!' `id -u` = 0 ] ; then
echo "Warning: you need to be root to run this!"
# we do not exit as other mechanisms exist that allows to do this than
# being root. let the errors speak for themselves.
fi
sleep 1
if [ "$PLATFORM" = "Linux" ] ; then
{
sysctl -w kernel.core_uses_pid=0
# Arch Linux requires core_pattern to be empty :(
test -e /etc/arch-release && sysctl -w kernel.core_pattern=
test -e /etc/arch-release || sysctl -w kernel.core_pattern=core
sysctl -w kernel.core_pattern=core
sysctl -w kernel.randomize_va_space=0
sysctl -w kernel.sched_child_runs_first=1
sysctl -w kernel.sched_autogroup_enabled=1
sysctl -w kernel.sched_migration_cost_ns=50000000 2>/dev/null
sysctl -w kernel.sched_latency_ns=250000000 2>/dev/null
sysctl -w kernel.sched_migration_cost_ns=50000000
sysctl -w kernel.sched_latency_ns=250000000
echo never > /sys/kernel/mm/transparent_hugepage/enabled
test -e /sys/devices/system/cpu/cpufreq/scaling_governor && echo performance | tee /sys/devices/system/cpu/cpufreq/scaling_governor
test -e /sys/devices/system/cpu/cpufreq/policy0/scaling_governor && echo performance | tee /sys/devices/system/cpu/cpufreq/policy*/scaling_governor
test -e /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor && echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
test -e /sys/devices/system/cpu/intel_pstate/no_turbo && echo 0 > /sys/devices/system/cpu/intel_pstate/no_turbo
test -e /sys/devices/system/cpu/cpufreq/boost && echo 1 > /sys/devices/system/cpu/cpufreq/boost
test -e /sys/devices/system/cpu/intel_pstate/max_perf_pct && echo 100 > /sys/devices/system/cpu/intel_pstate/max_perf_pct
test -n "$(which auditctl)" && auditctl -a never,task >/dev/null 2>&1
} > /dev/null
echo Settings applied.
echo
dmesg | grep -E -q 'noibrs pcid nopti' || {
dmesg | egrep -q 'nospectre_v2|spectre_v2=off' || {
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 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 ' /etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="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"'
}
echo If you run fuzzing instances in docker, run them with \"--security-opt seccomp=unconfined\" for more speed.
echo
DONE=1
fi
if [ "$PLATFORM" = "FreeBSD" ] ; then
@ -62,76 +48,36 @@ if [ "$PLATFORM" = "FreeBSD" ] ; then
sysctl kern.elf64.aslr.enable=0
} > /dev/null
echo Settings applied.
echo
cat <<EOF
In order to suppress core file generation during fuzzing it is recommended to set
me:\\
:coredumpsize=0:
in the ~/.login_conf file for the user used for fuzzing.
EOF
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 ' sysctl hw.ibrs_disable=1'
echo 'Setting kern.pmap.pg_ps_enabled=0 into /boot/loader.conf might be helpful too.'
echo
DONE=1
fi
if [ "$PLATFORM" = "OpenBSD" ] ; then
doas sysctl vm.malloc_conf=
echo 'Freecheck on allocation in particular can be detrimental to performance.'
echo 'Also we might not want necessarily to abort at any allocation failure.'
echo
echo 'System security features cannot be disabled on OpenBSD.'
echo
DONE=1
fi
if [ "$PLATFORM" = "DragonFly" ] ; then
#/sbin/sysctl kern.corefile=/dev/null
#echo Settings applied.
cat <<EOF
In order to suppress core file generation during fuzzing it is recommended to set
me:\\
:coredumpsize=0:
in the ~/.login_conf file for the user used for fuzzing.
EOF
echo
DONE=1
fi
if [ "$PLATFORM" = "NetBSD" ] ; then
{
#echo It is recommended to enable unprivileged users to set cpu affinity
#echo to be able to use afl-gotcpu meaningfully.
/sbin/sysctl -w security.models.extensions.user_set_cpu_affinity=1
} > /dev/null
echo Settings applied.
echo
DONE=1
fi
if [ "$PLATFORM" = "Darwin" ] ; then
sysctl kern.sysv.shmmax=524288000
sysctl kern.sysv.shmmin=1
sysctl kern.sysv.shmseg=48
sysctl kern.sysv.shmall=131072000
echo Settings applied.
echo
if [ $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') ] ; then
echo
echo Unloading the default crash reporter
echo We unload the default crash reporter here
SL=/System/Library; PL=com.apple.ReportCrash
launchctl unload -w ${SL}/LaunchAgents/${PL}.plist >/dev/null 2>&1
sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist >/dev/null 2>&1
echo
launchctl unload -w ${SL}/LaunchAgents/${PL}.plist
sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist
echo Settings applied.
else
echo Nothing to do.
fi
echo It is recommended to disable System Integrity Protection for increased performance.
echo
DONE=1
fi
if [ "$PLATFORM" = "Haiku" ] ; then
DEBUG_SERVER_DIR=~/config/settings/system/debug_server
[ ! -d ${DEBUG_SERVER_DIR} ] && mkdir -p ${DEBUG_SERVER_DIR}
SETTINGS=${DEBUG_SERVER_DIR}/settings
[ -r ${SETTINGS} ] && grep -qE "default_action\s+kill" ${SETTINGS} && { echo "Nothing to do"; } || { \
echo We change the debug_server default_action from user to silently kill; \
[ ! -r ${SETTINGS} ] && echo "default_action kill" >${SETTINGS} || { mv ${SETTINGS} s.tmp; sed -e "s/default_action\s\s*user/default_action kill/" s.tmp > ${SETTINGS}; rm s.tmp; }; \
echo Settings applied.; echo; \
}
DONE=1
fi
test -z "$DONE" && echo Error: Unknown platform: $PLATFORM
exit 0
test -z "$AFL_TMPDIR" && echo Also use AFL_TMPDIR and point it to a tmpfs for the input file caching

View File

@ -6,13 +6,13 @@
# Originally written by Michal Zalewski
#
# Copyright 2015 Google Inc. All rights reserved.
# Copyright 2019-2023 AFLplusplus Project. All rights reserved.
# Copyright 2019-2020 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:
#
# https://www.apache.org/licenses/LICENSE-2.0
# http://www.apache.org/licenses/LICENSE-2.0
#
# This tool summarizes the status of any locally-running synchronized
# instances of afl-fuzz.
@ -20,42 +20,33 @@
echo "$0 status check tool for afl-fuzz by Michal Zalewski"
echo
test "$1" = "-h" -o "$1" = "-hh" && {
echo "Usage: $0 [-s] [-d] afl_output_directory"
test "$1" = "-h" && {
echo $0 [-s] output_directory
echo
echo Options:
echo " -s - skip details and output summary results only"
echo " -d - include dead fuzzer stats"
echo -s - skip details and output summary results only
echo
exit 1
}
unset SUMMARY_ONLY
unset PROCESS_DEAD
if [ "$1" = "-s" ]; then
while [ "$1" = "-s" -o "$1" = "-d" ]; do
SUMMARY_ONLY=1
DIR="$2"
if [ "$1" = "-s" ]; then
SUMMARY_ONLY=1
fi
else
if [ "$1" = "-d" ]; then
PROCESS_DEAD=1
fi
shift
unset SUMMARY_ONLY
DIR="$1"
done
DIR="$1"
fi
if [ "$DIR" = "" ]; then
echo "Usage: $0 [-s] [-d] afl_output_directory" 1>&2
echo "Usage: $0 [ -s ] afl_sync_dir" 1>&2
echo 1>&2
echo Options: 1>&2
echo " -s - skip details and output summary results only" 1>&2
echo " -d - include dead fuzzer stats" 1>&2
echo "The -s option causes the tool to skip all the per-fuzzer trivia and show" 1>&2
echo "just the summary results. See docs/parallel_fuzzing.md for additional tips." 1>&2
echo 1>&2
exit 1
@ -91,9 +82,9 @@ TOTAL_CRASHES=0
TOTAL_PFAV=0
TOTAL_PENDING=0
# Time since last find / crash / hang, formatted as string
# Time since last path / crash / hang, formatted as string
FMT_TIME="0 days 0 hours"
FMT_FIND="${RED}none seen yet${NC}"
FMT_PATH="${RED}none seen yet${NC}"
FMT_CRASH="none seen yet"
FMT_HANG="none seen yet"
@ -108,7 +99,7 @@ fi
fmt_duration()
{
DUR_STRING=
if [ $1 -le 0 ]; then
if [ $1 -eq 0 ]; then
return 1
fi
@ -118,11 +109,7 @@ fmt_duration()
local minutes=$(((duration / 60) % 60))
local seconds=$((duration % 60))
if [ $duration -le 0 ]; then
DUR_STRING="0 seconds"
elif [ $duration -eq 1 ]; then
DUR_STRING="1 second"
elif [ $days -gt 0 ]; then
if [ $days -gt 0 ]; then
DUR_STRING="$days days, $hours hours"
elif [ $hours -gt 0 ]; then
DUR_STRING="$hours hours, $minutes minutes"
@ -135,14 +122,14 @@ fmt_duration()
FIRST=true
TOTAL_WCOP=
TOTAL_LAST_FIND=0
TOTAL_LAST_PATH=0
for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
sed 's/^command_line.*$/_skip:1/;s/[ ]*:[ ]*/="/;s/$/"/' "$i" >"$TMP"
. "$TMP"
RUN_UNIX=$run_time
RUN_UNIX=$((CUR_TIME - start_time))
RUN_DAYS=$((RUN_UNIX / 60 / 60 / 24))
RUN_HRS=$(((RUN_UNIX / 60 / 60) % 24))
@ -169,31 +156,24 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
fi
DEAD_CNT=$((DEAD_CNT + 1))
last_find=0
if [ "$PROCESS_DEAD" = "" ]; then
continue
fi
continue
fi
ALIVE_CNT=$((ALIVE_CNT + 1))
EXEC_SEC=0
test -z "$RUN_UNIX" -o "$RUN_UNIX" = 0 || EXEC_SEC=$((execs_done / RUN_UNIX))
PATH_PERC=$((cur_item * 100 / corpus_count))
EXEC_SEC=$((execs_done / RUN_UNIX))
PATH_PERC=$((cur_path * 100 / paths_total))
TOTAL_TIME=$((TOTAL_TIME + RUN_UNIX))
TOTAL_EPS=$((TOTAL_EPS + EXEC_SEC))
TOTAL_EXECS=$((TOTAL_EXECS + execs_done))
TOTAL_CRASHES=$((TOTAL_CRASHES + saved_crashes))
TOTAL_CRASHES=$((TOTAL_CRASHES + unique_crashes))
TOTAL_PENDING=$((TOTAL_PENDING + pending_total))
TOTAL_PFAV=$((TOTAL_PFAV + pending_favs))
if [ "$last_find" -gt "$TOTAL_LAST_FIND" ]; then
TOTAL_LAST_FIND=$last_find
if [ "$last_path" -gt "$TOTAL_LAST_PATH" ]; then
TOTAL_LAST_PATH=$last_path
fi
if [ "$SUMMARY_ONLY" = "" ]; then
@ -204,13 +184,11 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
echo " ${RED}timeout_ratio $TIMEOUT_PERC%${NC}"
fi
if [ $EXEC_SEC -eq 0 ]; then
echo " ${YELLOW}no data yet, 0 execs/sec${NC}"
elif [ $EXEC_SEC -lt 100 ]; then
if [ $EXEC_SEC -lt 100 ]; then
echo " ${RED}slow execution, $EXEC_SEC execs/sec${NC}"
fi
fmt_duration $last_find && FMT_FIND=$DUR_STRING
fmt_duration $last_path && FMT_PATH=$DUR_STRING
fmt_duration $last_crash && FMT_CRASH=$DUR_STRING
fmt_duration $last_hang && FMT_HANG=$DUR_STRING
FMT_CWOP="not available"
@ -220,7 +198,7 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
test "$cycles_wo_finds" -gt 50 && FMT_CWOP="${RED}$cycles_wo_finds${NC}"
}
echo " last_find : $FMT_FIND"
echo " last_path : $FMT_PATH"
echo " last_crash : $FMT_CRASH"
echo " last_hang : $FMT_HANG"
echo " cycles_wo_finds : $FMT_CWOP"
@ -229,12 +207,12 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
MEM_USAGE=$(ps aux | grep $fuzzer_pid | grep -v grep | awk '{print $4}')
echo " cpu usage $CPU_USAGE%, memory usage $MEM_USAGE%"
echo " cycles $((cycles_done + 1)), lifetime speed $EXEC_SEC execs/sec, items $cur_item/$corpus_count (${PATH_PERC}%)"
echo " cycle $((cycles_done + 1)), lifetime speed $EXEC_SEC execs/sec, path $cur_path/$paths_total (${PATH_PERC}%)"
if [ "$saved_crashes" = "0" ]; then
if [ "$unique_crashes" = "0" ]; then
echo " pending $pending_favs/$pending_total, coverage $bitmap_cvg, no crashes yet"
else
echo " pending $pending_favs/$pending_total, coverage $bitmap_cvg, crashes saved $saved_crashes (!)"
echo " pending $pending_favs/$pending_total, coverage $bitmap_cvg, crash count $unique_crashes (!)"
fi
echo
@ -243,7 +221,7 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
done
# Formatting for total time, time since last find, crash, and hang
# Formatting for total time, time since last path, crash, and hang
fmt_duration $((CUR_TIME - TOTAL_TIME)) && FMT_TIME=$DUR_STRING
# Formatting for total execution
FMT_EXECS="0 millions"
@ -263,28 +241,17 @@ TOTAL_DAYS=$((TOTAL_TIME / 60 / 60 / 24))
TOTAL_HRS=$(((TOTAL_TIME / 60 / 60) % 24))
test -z "$TOTAL_WCOP" && TOTAL_WCOP="not available"
fmt_duration $TOTAL_LAST_FIND && TOTAL_LAST_FIND=$DUR_STRING
fmt_duration $TOTAL_LAST_PATH && TOTAL_LAST_PATH=$DUR_STRING
test "$TOTAL_TIME" = "0" && TOTAL_TIME=1
if [ "$PROCESS_DEAD" = "" ]; then
TXT="excluded from stats"
else
TXT="included in stats"
ALIVE_CNT=$(($ALIVE_CNT - $DEAD_CNT))
fi
echo "Summary stats"
echo "============="
echo
echo " Fuzzers alive : $ALIVE_CNT"
if [ ! "$DEAD_CNT" = "0" ]; then
echo " Dead or remote : $DEAD_CNT ($TXT)"
echo " Dead or remote : $DEAD_CNT (excluded from stats)"
fi
echo " Total run time : $FMT_TIME"
@ -293,15 +260,15 @@ echo " Cumulative speed : $TOTAL_EPS execs/sec"
if [ "$ALIVE_CNT" -gt "0" ]; then
echo " Average speed : $((TOTAL_EPS / ALIVE_CNT)) execs/sec"
fi
echo " Pending items : $TOTAL_PFAV faves, $TOTAL_PENDING total"
echo " Pending paths : $TOTAL_PFAV faves, $TOTAL_PENDING total"
if [ "$ALIVE_CNT" -gt "1" ]; then
echo " Pending per fuzzer : $((TOTAL_PFAV/ALIVE_CNT)) faves, $((TOTAL_PENDING/ALIVE_CNT)) total (on average)"
fi
echo " Crashes saved : $TOTAL_CRASHES"
echo " Crashes found : $TOTAL_CRASHES locally unique"
echo "Cycles without finds : $TOTAL_WCOP"
echo " Time without finds : $TOTAL_LAST_FIND"
echo " Time without finds : $TOTAL_LAST_PATH"
echo
exit 0

View File

@ -28,9 +28,9 @@ if not os.getenv("AFL_INST_LIBS"):
os.environ["AFL_CODE_END"] = "0x%x" % (pe.OPTIONAL_HEADER.ImageBase + pe.OPTIONAL_HEADER.BaseOfCode + pe.OPTIONAL_HEADER.SizeOfCode)
if pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_AMD64"] or pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_IA64"]:
os.environ["QEMU_SET_ENV"] = "LD_PRELOAD=" + os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction64.so") + ",WINEARCH=win64"
os.environ["LD_PRELOAD"] = os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction64.so")
else:
os.environ["QEMU_SET_ENV"] = "LD_PRELOAD=" + os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction32.so") + ",WINEARCH=win32"
os.environ["LD_PRELOAD"] = os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction32.so")
if os.getenv("WINECOV_QEMU_PATH"):
qemu_path = os.getenv("WINECOV_QEMU_PATH")
@ -68,12 +68,7 @@ else:
argv = sys.argv[1:]
for i in range(len(argv)):
if ".cur_input" in argv[i]:
# Get the Wine translated path using the winepath tool
arg_translated = subprocess.run([os.path.join(os.path.dirname(wine_path), "winepath"), "--windows", argv[i]], universal_newlines=True, stdout=subprocess.PIPE).stdout
# Remove the spurious LF at the end of the path
if len(arg_translated) > 0 and arg_translated[-1] == '\n':
arg_translated = arg_translated[:-1]
argv[i] = arg_translated
argv[i] = subprocess.run([os.path.join(os.path.dirname(wine_path), "winepath"), "--windows", argv[i]], universal_newlines=True, stdout=subprocess.PIPE).stdout
break
print("[afl-wine-trace] exec:", " ".join([qemu_path, wine_path] + argv))

View File

@ -1,2 +0,0 @@
.local
glibc*

View File

@ -1,62 +0,0 @@
#!/usr/bin/env make
# SPDX-License-Identifier: Apache-2.0
# Copyright 2021 Ricerca Security, Inc. All rights reserved.
SHELL:=bash
PREFIX?=$(shell pwd)/.local
CS_TRACE:=coresight-trace
PATCHELF?=$(PREFIX)/bin/patchelf
PATCH_DIR:=patches
GLIBC_VER:=2.33
GLIBC_NAME:=glibc-$(GLIBC_VER)
GLIBC_URL_BASE:=http://ftp.gnu.org/gnu/glibc
GLIBC_LDSO?=$(PREFIX)/lib/ld-linux-aarch64.so.1
OUTPUT?="$(TARGET).patched"
all: build
build:
git submodule update --init --recursive $(CS_TRACE)
$(MAKE) -C $(CS_TRACE)
cp $(CS_TRACE)/cs-proxy ../afl-cs-proxy
patch: | $(PATCHELF) $(GLIBC_LDSO)
@if test -z "$(TARGET)"; then echo "TARGET is not set"; exit 1; fi
$(PATCHELF) \
--set-interpreter $(GLIBC_LDSO) \
--set-rpath $(dir $(GLIBC_LDSO)) \
--output $(OUTPUT) \
$(TARGET)
$(PATCHELF): patchelf
git submodule update --init $<
cd $< && \
./bootstrap.sh && \
./configure --prefix=$(PREFIX) && \
$(MAKE) && \
$(MAKE) check && \
$(MAKE) install
$(GLIBC_LDSO): | $(GLIBC_NAME).tar.xz
tar -xf $(GLIBC_NAME).tar.xz
for file in $(shell find $(PATCH_DIR) -maxdepth 1 -type f); do \
patch -p1 < $$file ; \
done
mkdir -p $(GLIBC_NAME)/build
cd $(GLIBC_NAME)/build && \
../configure --prefix=$(PREFIX) && \
$(MAKE) && \
$(MAKE) install
$(GLIBC_NAME).tar.xz:
wget -qO $@ $(GLIBC_URL_BASE)/$@
clean:
$(MAKE) -C $(CS_TRACE) clean
.PHONY: all build patch clean

View File

@ -1,21 +0,0 @@
#!/usr/bin/env make
# SPDX-License-Identifier: Apache-2.0
# Copyright 2021 Ricerca Security, Inc. All rights reserved.
all:
@echo trying to use GNU make...
@gmake all || echo please install GNUmake
build:
@echo trying to use GNU make...
@gmake build || echo please install GNUmake
patch:
@echo trying to use GNU make...
@gmake patch || echo please install GNUmake
clean:
@echo trying to use GNU make...
@gmake clean || echo please install GNUmake
.PHONY: all build patch clean

View File

@ -1,70 +0,0 @@
# AFL++ CoreSight mode
CoreSight mode enables binary-only fuzzing on ARM64 Linux using CoreSight (ARM's hardware tracing technology).
NOTE: CoreSight mode is in the early development stage. Not applicable for production use.
Currently the following hardware boards are supported:
* NVIDIA Jetson TX2 (NVIDIA Parker)
* NVIDIA Jetson Nano (NVIDIA Tegra X1)
* GIGABYTE R181-T90 (Marvell ThunderX2 CN99XX)
## Getting started
Please read the [RICSec/coresight-trace README](https://github.com/RICSecLab/coresight-trace/blob/master/README.md) and check the prerequisites (capstone) before getting started.
CoreSight mode supports the AFL++ fork server mode to reduce `exec` system call
overhead. To support it for binary-only fuzzing, it needs to modify the target
ELF binary to re-link to the patched glibc. We employ this design from
[PTrix](https://github.com/junxzm1990/afl-pt).
Check out all the git submodules in the `cs_mode` directory:
```bash
git submodule update --init --recursive
```
### Build coresight-trace
There are some notes on building coresight-trace. Refer to the [README](https://github.com/RICSecLab/coresight-trace/blob/master/README.md) for the details. Run make in the `cs_mode` directory:
```bash
make build
```
Make sure `cs-proxy` is placed in the AFL++ root directory as `afl-cs-proxy`.
### Patch COTS binary
The fork server mode requires patchelf and the patched glibc. The dependency build can be done by just run make:
```bash
make patch TARGET=$BIN
```
The above make command builds and installs the dependencies to `$PREFIX` (default to `$PWD/.local`) at the first time. Then, it runs `patchelf` to `$BIN` with output `$OUTPUT` (`$BIN.patched` by default).
### Run afl-fuzz
Run `afl-fuzz` with `-A` option to use CoreSight mode.
```bash
sudo afl-fuzz -A -i input -o output -- $OUTPUT @@
```
## Environment Variables
There are AFL++ CoreSight mode-specific environment variables for run-time configuration.
* `AFL_CS_CUSTOM_BIN` overrides the proxy application path. `afl-cs-proxy` will be used if not defined.
* `AFLCS_COV` specifies coverage type on CoreSight trace decoding. `edge` and `path` is supported. The default value is `edge`.
* `AFLCS_UDMABUF` is the u-dma-buf device number used to store trace data in the DMA region. The default value is `0`.
## TODO List
* Eliminate modified glibc dependency
* Support parallel fuzzing
## Acknowledgements
This project has received funding from the Acquisition, Technology & Logistics Agency (ATLA) under the National Security Technology Research Promotion Fund 2021 (JPJ004596).

View File

@ -1,117 +0,0 @@
diff --git a/glibc-2.33/elf/rtld.c b/glibc-2.33/elf/rtld.c
index 596b6ac3..2ee270d4 100644
--- a/glibc-2.33/elf/rtld.c
+++ b/glibc-2.33/elf/rtld.c
@@ -169,6 +169,99 @@ uintptr_t __pointer_chk_guard_local
strong_alias (__pointer_chk_guard_local, __pointer_chk_guard)
#endif
+#define AFLCS_RTLD 1
+
+#if AFLCS_RTLD
+
+#include <sys/shm.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <dlfcn.h>
+#include <signal.h>
+
+#include <asm/unistd.h>
+#include <unistd.h>
+
+#define FORKSRV_FD 198
+
+#define AFLCS_ENABLE "__AFLCS_ENABLE"
+
+/* We use this additional AFLCS_# AFLCS_#+1 pair to communicate with proxy */
+#define AFLCS_FORKSRV_FD (FORKSRV_FD - 3)
+#define AFLCS_RTLD_SNIPPET do { __cs_start_forkserver(); } while(0)
+
+/* Fork server logic, invoked before we return from _dl_start. */
+
+static void __cs_start_forkserver(void) {
+ int status;
+ pid_t child_pid;
+ static char tmp[4] = {0, 0, 0, 0};
+
+ if (!getenv(AFLCS_ENABLE)) {
+ return;
+ }
+
+ if (write(AFLCS_FORKSRV_FD + 1, tmp, 4) != 4) {
+ _exit(-1);
+ }
+
+ /* All right, let's await orders... */
+ while (1) {
+ /* Whoops, parent dead? */
+ if (read(AFLCS_FORKSRV_FD, tmp, 4) != 4) {
+ _exit(1);
+ }
+
+ child_pid = INLINE_SYSCALL(clone, 5,
+ CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0,
+ NULL, NULL, &THREAD_SELF->tid);
+ if (child_pid < 0) {
+ _exit(4);
+ }
+ if (!child_pid) {
+ /* Child process. Wait for parent start tracing */
+ kill(getpid(), SIGSTOP);
+ /* Close descriptors and run free. */
+ close(AFLCS_FORKSRV_FD);
+ close(AFLCS_FORKSRV_FD + 1);
+ return;
+ }
+
+ /* Parent. */
+ if (write(AFLCS_FORKSRV_FD + 1, &child_pid, 4) != 4) {
+ _exit(5);
+ }
+
+ /* Wait until SIGCONT is signaled. */
+ if (waitpid(child_pid, &status, WCONTINUED) < 0) {
+ _exit(6);
+ }
+ if (!WIFCONTINUED(status)) {
+ /* Relay status to proxy. */
+ if (write(AFLCS_FORKSRV_FD + 1, &status, 4) != 4) {
+ _exit(7);
+ }
+ continue;
+ }
+ while (1) {
+ /* Get status. */
+ if (waitpid(child_pid, &status, WUNTRACED) < 0) {
+ _exit(8);
+ }
+ /* Relay status to proxy. */
+ if (write(AFLCS_FORKSRV_FD + 1, &status, 4) != 4) {
+ _exit(9);
+ }
+ if (!(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP)) {
+ /* The child process is exited. */
+ break;
+ }
+ }
+ }
+}
+
+#endif /* AFLCS_RTLD */
+
/* Check that AT_SECURE=0, or that the passed name does not contain
directories and is not overly long. Reject empty names
unconditionally. */
@@ -588,6 +681,12 @@ _dl_start (void *arg)
# define ELF_MACHINE_START_ADDRESS(map, start) (start)
#endif
+ /* AFL-CS-START */
+#if AFLCS_RTLD
+ AFLCS_RTLD_SNIPPET;
+#endif
+ /* AFL-CS-END */
+
return ELF_MACHINE_START_ADDRESS (GL(dl_ns)[LM_ID_BASE]._ns_loaded, entry);
}
}

View File

@ -1,121 +0,0 @@
cc_library_shared {
name: "libfuzzer-mutator",
vendor_available: true,
host_supported: true,
cflags: [
"-g",
"-O0",
"-funroll-loops",
"-fPIC",
"-fpermissive",
"-std=c++11",
"-Wno-unused-parameter",
"-Wno-unused-variable",
],
srcs: [
"libfuzzer/FuzzerCrossOver.cpp",
"libfuzzer/FuzzerDataFlowTrace.cpp",
"libfuzzer/FuzzerDriver.cpp",
"libfuzzer/FuzzerExtFunctionsDlsym.cpp",
"libfuzzer/FuzzerExtFunctionsWeak.cpp",
"libfuzzer/FuzzerExtFunctionsWindows.cpp",
"libfuzzer/FuzzerExtraCounters.cpp",
"libfuzzer/FuzzerFork.cpp",
"libfuzzer/FuzzerIO.cpp",
"libfuzzer/FuzzerIOPosix.cpp",
"libfuzzer/FuzzerIOWindows.cpp",
"libfuzzer/FuzzerLoop.cpp",
"libfuzzer/FuzzerMerge.cpp",
"libfuzzer/FuzzerMutate.cpp",
"libfuzzer/FuzzerSHA1.cpp",
"libfuzzer/FuzzerTracePC.cpp",
"libfuzzer/FuzzerUtil.cpp",
"libfuzzer/FuzzerUtilDarwin.cpp",
"libfuzzer/FuzzerUtilFuchsia.cpp",
"libfuzzer/FuzzerUtilLinux.cpp",
"libfuzzer/FuzzerUtilPosix.cpp",
"libfuzzer/FuzzerUtilWindows.cpp",
"libfuzzer/libfuzzer.cpp",
],
header_libs: [
"libafl_headers",
],
}
/*cc_library_shared {
name: "honggfuzz-mutator",
vendor_available: true,
host_supported: true,
cflags: [
"-g",
"-O0",
"-funroll-loops",
"-fPIC",
"-Wl,-Bsymbolic",
],
srcs: [
"honggfuzz/honggfuzz.c",
"honggfuzz/mangle.c",
// "../src/afl-perfomance.c",
],
header_libs: [
"libafl_headers",
],
}*/
cc_library_shared {
name: "radamsa-mutator",
vendor_available: true,
host_supported: true,
cflags: [
"-g",
"-O0",
"-funroll-loops",
"-fPIC",
"-Wno-unused-parameter",
"-Wno-unused-function",
],
srcs: [
"radamsa/libradamsa.c",
"radamsa/radamsa-mutator.c",
],
header_libs: [
"libafl_headers",
],
}
cc_library_shared {
name: "symcc-mutator",
vendor_available: true,
host_supported: true,
cflags: [
"-g",
"-O0",
"-funroll-loops",
"-fPIC",
"-Wno-unused-parameter",
"-Wno-pointer-sign",
],
srcs: [
"symcc/symcc.c",
],
header_libs: [
"libafl_headers",
],
}
subdirs = [
"libprotobuf-mutator-example",
]

View File

@ -1,30 +1,4 @@
# Custom Mutators
Custom mutators enhance and alter the mutation strategies of AFL++.
For further information and documentation on how to write your own, read [the docs](../docs/custom_mutators.md).
## Examples
The `./examples` folder contains examples for custom mutators in python and C.
## Rust
In `./rust`, you will find rust bindings, including a simple example in `./rust/example` and an example for structured fuzzing, based on lain, in`./rust/example_lain`.
## The AFL++ Grammar Mutator
If you use git to clone AFL++, then the following will incorporate our
excellent grammar custom mutator:
```sh
git submodule update --init
```
Read the README in the [Grammar-Mutator] repository on how to use it.
[Grammar-Mutator]: https://github.com/AFLplusplus/Grammar-Mutator
## Production-Ready Custom Mutators
# production ready custom mutators
This directory holds ready to use custom mutators.
Just type "make" in the individual subdirectories.
@ -36,25 +10,3 @@ Use with e.g.
and add `AFL_CUSTOM_MUTATOR_ONLY=1` if you only want to use the custom mutator.
Multiple custom mutators can be used by separating their paths with `:` in the environment variable.
## 3rd Party Custom Mutators
### Superion Mutators
Adrian Tiron ported the Superion grammar fuzzer to AFL++, it is WIP and
requires cmake (among other things):
[https://github.com/adrian-rt/superion-mutator](https://github.com/adrian-rt/superion-mutator)
### libprotobuf Mutators
There are two WIP protobuf projects, that require work to be working though:
transforms protobuf raw:
https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator
has a transform function you need to fill for your protobuf format, however
needs to be ported to the updated AFL++ custom mutator API (not much work):
https://github.com/thebabush/afl-libprotobuf-mutator
same as above but is for current AFL++:
https://github.com/P1umer/AFLplusplus-protobuf-mutator

View File

@ -1,56 +0,0 @@
// cc -O3 -fPIC -shared -g -o custom_send.so -I../../include custom_send.c
// cd ../..
// afl-cc -o test-instr test-instr.c
// afl-fuzz -i in -o out -- ./test-instr -f /tmp/foo
#include "custom_mutator_helpers.h"
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
typedef struct my_mutator {
afl_t *afl;
} my_mutator_t;
my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
if (!data) {
perror("afl_custom_init alloc");
return NULL;
}
data->afl = afl;
return data;
}
void afl_custom_fuzz_send(my_mutator_t *data, uint8_t *buf, size_t buf_size) {
int fd = open("/tmp/foo", O_CREAT | O_NOFOLLOW | O_TRUNC | O_RDWR, 0644);
if (fd >= 0) {
(void)write(fd, buf, buf_size);
close(fd);
}
return;
}
void afl_custom_deinit(my_mutator_t *data) {
free(data);
}

View File

@ -1 +0,0 @@
af8dd4a307e7b837f9fa2959549548ace4afe08b

View File

@ -1,49 +0,0 @@
# GramaTron
GramaTron is a coverage-guided fuzzer that uses grammar automatons to perform
grammar-aware fuzzing. Technical details about our framework are available in
the [ISSTA'21 paper](https://nebelwelt.net/files/21ISSTA.pdf). The artifact to
reproduce the experiments presented in the paper are present in `artifact/`.
Instructions to run a sample campaign and incorporate new grammars is presented
below:
## Compiling
Execute `./build_gramatron_mutator.sh`.
## Running
You have to set the grammar file to use with `GRAMATRON_AUTOMATION`:
```
export AFL_DISABLE_TRIM=1
export AFL_CUSTOM_MUTATOR_ONLY=1
export AFL_CUSTOM_MUTATOR_LIBRARY=./gramatron.so
export GRAMATRON_AUTOMATION=grammars/ruby/source_automata.json
afl-fuzz -i in -o out -- ./target
```
## Adding and testing a new grammar
- Specify in a JSON format for CFG. Examples are correspond `source.json` files.
- Run the automaton generation script (in `src/gramfuzz-mutator/preprocess`)
which will place the generated automaton in the same folder.
```
./preprocess/prep_automaton.sh <grammar_file> <start_symbol> [stack_limit]
E.g., ./preprocess/prep_automaton.sh ~/grammars/ruby/source.json PROGRAM
```
- If the grammar has no self-embedding rules, then you do not need to pass the
stack limit parameter. However, if it does have self-embedding rules, then you
need to pass the stack limit parameter. We recommend starting with `5` and
then increasing it if you need more complexity.
- To sanity-check that the automaton is generating inputs as expected, you can
use the `test` binary housed in `src/gramfuzz-mutator`.
```
./test SanityCheck <automaton_file>
E.g., ./test SanityCheck ~/grammars/ruby/source_automata.json
```

View File

@ -1,149 +0,0 @@
#!/bin/sh
#
# american fuzzy lop++ - gramatron build script
# ------------------------------------------------
#
# Originally written by Nathan Voss <njvoss99@gmail.com>
#
# Adapted from code by Andrew Griffiths <agriffiths@google.com> and
# Michal Zalewski
#
# Adapted for AFLplusplus by Dominik Maier <mail@dmnk.co>
#
# Copyright 2017 Battelle Memorial Institute. 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:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# This script downloads, patches, and builds a version of Unicorn with
# minor tweaks to allow Unicorn-emulated binaries to be run under
# afl-fuzz.
#
# The modifications reside in patches/*. The standalone Unicorn library
# will be written to /usr/lib/libunicornafl.so, and the Python bindings
# will be installed system-wide.
#
# You must make sure that Unicorn Engine is not already installed before
# running this script. If it is, please uninstall it first.
JSONC_VERSION="$(cat ./JSONC_VERSION)"
JSONC_REPO="https://github.com/json-c/json-c"
echo "================================================="
echo "Gramatron Mutator build script"
echo "================================================="
echo
echo "[*] Performing basic sanity checks..."
PLT=`uname -s`
if [ ! -f "../../config.h" ]; then
echo "[-] Error: key files not found - wrong working directory?"
exit 1
fi
if [ ! -f "../../src/afl-performance.o" ]; then
echo "[-] Error: you must build afl-fuzz first and not do a \"make clean\""
exit 1
fi
PYTHONBIN=`command -v python3 || command -v python || command -v python2 || echo python3`
MAKECMD=make
TARCMD=tar
if [ "$PLT" = "Darwin" ]; then
CORES=`sysctl -n hw.ncpu`
TARCMD=tar
fi
if [ "$PLT" = "FreeBSD" ]; then
MAKECMD=gmake
CORES=`sysctl -n hw.ncpu`
TARCMD=gtar
fi
if [ "$PLT" = "NetBSD" ] || [ "$PLT" = "OpenBSD" ]; then
MAKECMD=gmake
CORES=`sysctl -n hw.ncpu`
TARCMD=gtar
fi
PREREQ_NOTFOUND=
for i in git $MAKECMD $TARCMD; do
T=`command -v "$i" 2>/dev/null`
if [ "$T" = "" ]; then
echo "[-] Error: '$i' not found. Run 'sudo apt-get install $i' or similar."
PREREQ_NOTFOUND=1
fi
done
test -z "$CC" && export CC=cc
if echo "$CC" | grep -qF /afl-; then
echo "[-] Error: do not use afl-gcc or afl-clang to compile this tool."
PREREQ_NOTFOUND=1
fi
if [ "$PREREQ_NOTFOUND" = "1" ]; then
exit 1
fi
echo "[+] All checks passed!"
echo "[*] Making sure json-c is checked out"
git status 1>/dev/null 2>/dev/null
if [ $? -eq 0 ]; then
echo "[*] initializing json-c submodule"
git submodule init || exit 1
git submodule update ./json-c 2>/dev/null # ignore errors
else
echo "[*] cloning json-c"
test -d json-c/.git || {
CNT=1
while [ '!' -d json-c/.git -a "$CNT" -lt 4 ]; do
echo "Trying to clone json-c (attempt $CNT/3)"
git clone "$JSONC_REPO"
CNT=`expr "$CNT" + 1`
done
}
fi
test -e json-c/.git || { echo "[-] not checked out, please install git or check your internet connection." ; exit 1 ; }
echo "[+] Got json-c."
test -e json-c/.libs/libjson-c.a || {
cd "json-c" || exit 1
echo "[*] Checking out $JSONC_VERSION"
sh -c 'git stash && git stash drop' 1>/dev/null 2>/dev/null
git checkout "$JSONC_VERSION" || exit 1
sh autogen.sh || exit 1
export CFLAGS=-fPIC
./configure --disable-shared || exit 1
make || exit 1
cd ..
}
echo
echo
echo "[+] Json-c successfully prepared!"
echo "[+] Builing gramatron now."
$CC -O3 -g -fPIC -Wno-unused-result -Wl,--allow-multiple-definition -I../../include -o gramatron.so -shared -I. -I/prg/dev/include gramfuzz.c gramfuzz-helpers.c gramfuzz-mutators.c gramfuzz-util.c hashmap.c ../../src/afl-performance.o json-c/.libs/libjson-c.a || exit 1
echo
echo "[+] gramatron successfully built!"

View File

@ -1,336 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "afl-fuzz.h"
#include "gramfuzz.h"
/*Slices from beginning till idx*/
Array *slice(Array *input, int idx) {
// printf("\nSlice idx:%d", idx);
terminal *origptr;
terminal *term_ptr;
Array * sliced = (Array *)malloc(sizeof(Array));
initArray(sliced, input->size);
// Populate dynamic array members
if (idx == 0) { return sliced; }
for (int x = 0; x < idx; x++) {
origptr = &input->start[x];
insertArray(sliced, origptr->state, origptr->symbol, origptr->symbol_len,
origptr->trigger_idx);
}
return sliced;
}
/* Slices from idx till end*/
Array *slice_inverse(Array *input, int idx) {
// printf("\nSlice idx:%d", idx);
terminal *origptr;
terminal *term_ptr;
Array * sliced = (Array *)malloc(sizeof(Array));
initArray(sliced, input->size);
for (int x = idx; x < input->used; x++) {
origptr = &input->start[x];
insertArray(sliced, origptr->state, origptr->symbol, origptr->symbol_len,
origptr->trigger_idx);
}
return sliced;
}
/*Carves with `start` included and `end` excluded*/
Array *carve(Array *input, int start, int end) {
terminal *origptr;
terminal *term_ptr;
Array * sliced = (Array *)malloc(sizeof(Array));
initArray(sliced, input->size);
for (int x = start; x < end; x++) {
origptr = &input->start[x];
insertArray(sliced, origptr->state, origptr->symbol, origptr->symbol_len,
origptr->trigger_idx);
}
return sliced;
}
/*Concats prefix + feature *mult*/
void concatPrefixFeature(Array *prefix, Array *feature) {
// XXX: Currently we have hardcoded the multiplication threshold for adding
// the recursive feature. Might want to fix it to choose a random number upper
// bounded by a static value instead.
terminal *featureptr;
int len = rand_below(global_afl, RECUR_THRESHOLD);
for (int x = 0; x < len; x++) {
for (int y = 0; y < feature->used; y++) {
featureptr = &feature->start[y];
insertArray(prefix, featureptr->state, featureptr->symbol,
featureptr->symbol_len, featureptr->trigger_idx);
}
}
}
void concatPrefixFeatureBench(Array *prefix, Array *feature) {
// XXX: Currently we have hardcoded the multiplication threshold for adding
// the recursive feature. Might want to fix it to choose a random number upper
// bounded by a static value instead.
terminal *featureptr;
int len =
5; // 5 is the number of times we compare performing random recursion.
for (int x = 0; x < len; x++) {
for (int y = 0; y < feature->used; y++) {
featureptr = &feature->start[y];
insertArray(prefix, featureptr->state, featureptr->symbol,
featureptr->symbol_len, featureptr->trigger_idx);
}
}
}
Array *spliceGF(Array *orig, Array *toSplice, int idx) {
terminal *toSplicePtr;
terminal *tempPtr;
// Iterate through the splice candidate from the `idx` till end
for (int x = idx; x < toSplice->used; x++) {
toSplicePtr = &toSplice->start[x];
insertArray(orig, toSplicePtr->state, toSplicePtr->symbol,
toSplicePtr->symbol_len, toSplicePtr->trigger_idx);
}
return orig;
}
Array *gen_input(state *pda, Array *input) {
state * state_ptr;
trigger * trigger_ptr;
terminal *term_ptr;
int offset = 0;
int randval, error;
// Generating an input for the first time
if (input == NULL) {
input = (Array *)calloc(1, sizeof(Array));
initArray(input, INIT_SIZE);
curr_state = init_state;
}
while (curr_state != final_state) {
// Retrieving the state from the pda
state_ptr = pda + curr_state;
// Get a random trigger
randval = rand_below(global_afl, state_ptr->trigger_len);
trigger_ptr = (state_ptr->ptr) + randval;
// Insert into the dynamic array
insertArray(input, curr_state, trigger_ptr->term, trigger_ptr->term_len,
randval);
curr_state = trigger_ptr->dest;
offset += 1;
}
return input;
}
Array *gen_input_count(state *pda, Array *input, int *mut_count) {
state * state_ptr;
trigger * trigger_ptr;
terminal *term_ptr;
int offset = 0;
int randval, error;
// Generating an input for the first time
if (input == NULL) {
input = (Array *)calloc(1, sizeof(Array));
initArray(input, INIT_SIZE);
curr_state = init_state;
}
while (curr_state != final_state) {
*mut_count += 1;
// Retrieving the state from the pda
state_ptr = pda + curr_state;
// Get a random trigger
randval = rand_below(global_afl, state_ptr->trigger_len);
trigger_ptr = (state_ptr->ptr) + randval;
// Insert into the dynamic array
insertArray(input, curr_state, trigger_ptr->term, trigger_ptr->term_len,
randval);
curr_state = trigger_ptr->dest;
offset += 1;
}
return input;
}
/*Creates a candidate from walk with state hashmap and
* recursion hashmap
*/
Candidate *gen_candidate(Array *input) {
terminal * term_ptr;
IdxMap_new *idxmapPtr;
// Declare the State Hash Table
IdxMap_new *idxmapStart =
(IdxMap_new *)malloc(sizeof(IdxMap_new) * numstates);
for (int x = 0; x < numstates; x++) {
idxmapPtr = &idxmapStart[x];
utarray_new(idxmapPtr->nums, &ut_int_icd);
}
char * trigger;
int state;
char * key;
Candidate *candidate = (Candidate *)malloc(sizeof(Candidate));
candidate->walk = input;
int offset = 0, error;
// Generate statemap for splicing
while (offset < input->used) {
term_ptr = &input->start[offset];
state = term_ptr->state;
// char *statenum = state + 1;
// int num = atoi(statenum);
idxmapPtr = &idxmapStart[state];
utarray_push_back(idxmapPtr->nums, &offset);
offset += 1;
}
candidate->statemap = idxmapStart;
return candidate;
}
char *get_state(char *trigger) {
// Get the state from transition
int trigger_idx = 0;
printf("\nTrigger:%s", trigger);
char *state = (char *)malloc(sizeof(char) * 10);
while (trigger[trigger_idx] != '_') {
state[trigger_idx] = trigger[trigger_idx];
trigger_idx += 1;
}
printf("\nTrigger Idx:%d", trigger_idx);
state[trigger_idx] = '\0';
return state;
}
void print_repr(Array *input, char *prefix) {
size_t offset = 0;
terminal *term_ptr;
char geninput[input->used * 100];
if (!input->used) {
printf("\n=============");
printf("\n%s:%s", prefix, "");
printf("\n=============");
return;
}
// This is done to create a null-terminated initial string
term_ptr = &input->start[offset];
strcpy(geninput, term_ptr->symbol);
offset += 1;
while (offset < input->used) {
term_ptr = &input->start[offset];
strcat(geninput, term_ptr->symbol);
offset += 1;
}
printf("\n=============");
printf("\n%s:%s", prefix, geninput);
printf("\n=============");
}
// int main(int argc, char*argv[]) {
// char *mode;
// if (argc == 1) {
// printf("\nUsage: ./gramfuzzer <mode>");
// return -1;
// }
// if (argc >= 2) {
// mode = argv[1];
// printf("\nMode:%s", mode);
// }
// if (! strcmp(mode, "Generate")) {
// GenInputBenchmark();
// }
// else if (! strcmp(mode, "RandomMutation")) {
// RandomMutationBenchmark();
// }
// else if (! strcmp(mode, "Splice")) {
// SpliceMutationBenchmark();
// }
// else if (! strcmp(mode, "Recursive")) {
// RandomRecursiveBenchmark();
// }
// else {
// printf("\nUnrecognized mode");
// return -1;
// }
// return 0;
// }

View File

@ -1,247 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "afl-fuzz.h"
#include "gramfuzz.h"
Array *performRandomMutation(state *pda, Array *input) {
terminal *term_ptr;
// terminal *prev_ptr;
Array *mutated;
Array *sliced;
// Get offset at which to generate new input and slice it
int idx = rand_below(global_afl, input->used);
sliced = slice(input, idx);
// print_repr(sliced, "Slice");
// prev_ptr = & input->start[idx - 1];
// printf("\nState:%s Symbol:%s", prev_ptr->state, prev_ptr->symbol);
// Reset current state to that of the slice's last member
term_ptr = &input->start[idx];
curr_state = term_ptr->state;
// printf("\nState:%s Symbol:%s", curr_state, term_ptr->symbol);
// Set the next available cell to the one adjacent to this chosen point
mutated = gen_input(pda, sliced);
return mutated;
}
// Tries to perform splice operation between two automaton walks
UT_icd intpair_icd = {sizeof(intpair_t), NULL, NULL, NULL};
Array *performSpliceOne(Array *originput, IdxMap_new *statemap_orig,
Array *splicecand) {
UT_array * stateptr, *pairs;
intpair_t ip;
intpair_t *cand;
terminal *term_ptr;
Array * prefix;
int state;
// Initialize the dynamic holding the splice indice pairs
utarray_new(pairs, &intpair_icd);
// print_repr(originput, "Orig");
// print_repr(splicecand, "SpliceCand");
// Iterate through the splice candidate identifying potential splice points
// and pushing pair (orig_idx, splice_idx) to a dynamic array
for (int x = 0; x < splicecand->used; x++) {
term_ptr = &splicecand->start[x];
stateptr = statemap_orig[term_ptr->state].nums;
int length = utarray_len(stateptr);
if (length) {
int *splice_idx = (int *)utarray_eltptr(stateptr, rand_below(global_afl, length));
ip.orig_idx = *splice_idx;
ip.splice_idx = x;
utarray_push_back(pairs, &ip);
}
}
// Pick a random pair
int length = utarray_len(pairs);
cand = (intpair_t *)utarray_eltptr(pairs, rand_below(global_afl, length));
// printf("\n Orig_idx:%d Splice_idx:%d", cand->orig_idx, cand->splice_idx);
// Perform the splicing
prefix = slice(originput, cand->orig_idx);
Array *spliced = spliceGF(prefix, splicecand, cand->splice_idx);
// print_repr(spliced, "Spliced");
//
utarray_free(pairs);
return spliced;
}
UT_array **get_dupes(Array *input, int *recur_len) {
// Variables related to finding duplicates
int offset = 0;
int state;
terminal * term_ptr;
IdxMap_new *idxMapPtr;
UT_array ** recurIdx;
// Declare the Recursive Map Table
IdxMap_new *idxmapStart =
(IdxMap_new *)malloc(sizeof(IdxMap_new) * numstates);
//
// UT_array *(recurIdx[numstates]);
recurIdx = malloc(sizeof(UT_array *) * numstates);
for (int x = 0; x < numstates; x++) {
idxMapPtr = &idxmapStart[x];
utarray_new(idxMapPtr->nums, &ut_int_icd);
}
// Obtain frequency distribution of states
while (offset < input->used) {
term_ptr = &input->start[offset];
state = term_ptr->state;
// int num = atoi(state + 1);
idxMapPtr = &idxmapStart[state];
utarray_push_back(idxMapPtr->nums, &offset);
offset += 1;
}
// Retrieve the duplicated states
offset = 0;
while (offset < numstates) {
idxMapPtr = &idxmapStart[offset];
int length = utarray_len(idxMapPtr->nums);
if (length >= 2) {
recurIdx[*recur_len] = idxMapPtr->nums;
*recur_len += 1;
}
// else {
// utarray_free(idxMapPtr->nums);
// }
offset += 1;
}
if (*recur_len) {
// Declare the return struct
// We use this struct so that we save the reference to IdxMap_new and free
// it after we have used it in doMult
// Get_Dupes_Ret* getdupesret =
// (Get_Dupes_Ret*)malloc(sizeof(Get_Dupes_Ret));
return recurIdx;
// getdupesret->idxmap = idxmapStart;
// getdupesret->recurIdx = recurIdx;
// return getdupesret;
} else {
return NULL;
}
}
Array *doMult(Array *input, UT_array **recur, int recurlen) {
int offset = 0;
int idx = rand_below(global_afl, recurlen);
UT_array *recurMap = recur[idx];
UT_array *recurPtr;
Array * prefix;
Array * postfix;
Array * feature;
// Choose two indices to get the recursive feature
int recurIndices = utarray_len(recurMap);
int firstIdx = 0;
int secondIdx = 0;
getTwoIndices(recurMap, recurIndices, &firstIdx, &secondIdx);
// Perform the recursive mut
// print_repr(input, "Orig");
prefix = slice(input, firstIdx);
// print_repr(prefix, "Prefix");
if (firstIdx < secondIdx) {
feature = carve(input, firstIdx, secondIdx);
} else {
feature = carve(input, secondIdx, firstIdx);
}
// print_repr(feature, "Feature");
concatPrefixFeature(prefix, feature);
// GC allocated structures
free(feature->start);
free(feature);
// for(int x = 0; x < recurlen; x++) {
// utarray_free(recur[x]);
// }
// free(recur);
// print_repr(prefix, "Concat");
return spliceGF(prefix, input, secondIdx);
}
void getTwoIndices(UT_array *recur, int recurlen, int *firstIdx,
int *secondIdx) {
int ArrayRecurIndices[recurlen];
int offset = 0, *p;
// Unroll into an array
for (p = (int *)utarray_front(recur); p != NULL;
p = (int *)utarray_next(recur, p)) {
ArrayRecurIndices[offset] = *p;
offset += 1;
}
/*Source:
* https://www.geeksforgeeks.org/shuffle-a-given-array-using-fisher-yates-shuffle-algorithm/
*/
for (int i = offset - 1; i > 0; i--) {
// Pick a random index from 0 to i
int j = rand_below(global_afl, i + 1);
// Swap arr[i] with the element at random index
swap(&ArrayRecurIndices[i], &ArrayRecurIndices[j]);
}
*firstIdx = ArrayRecurIndices[0];
*secondIdx = ArrayRecurIndices[1];
}
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}

View File

@ -1,268 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "afl-fuzz.h"
#include "gramfuzz.h"
#ifdef _GNU_SOURCE
#undef _GNU_SOURCE
#endif
#define _GNU_SOURCE
#include <sys/mman.h>
/* Dynamic Array for adding to the input repr
* */
void initArray(Array *a, size_t initialSize) {
a->start = (terminal *)calloc(1, sizeof(terminal) * initialSize);
a->used = 0;
a->size = initialSize;
a->inputlen = 0;
}
void insertArray(Array *a, int state, char *symbol, size_t symbol_len,
int trigger_idx) {
// a->used is the number of used entries, because a->array[a->used++] updates
// a->used only *after* the array has been accessed. Therefore a->used can go
// up to a->size
terminal *term_ptr;
if (a->used == a->size) {
a->size = a->size * sizeof(terminal);
a->start = (terminal *)realloc(a->start, a->size * sizeof(terminal));
}
// Add the element
term_ptr = &a->start[a->used];
term_ptr->state = state;
term_ptr->symbol = symbol;
term_ptr->symbol_len = symbol_len;
term_ptr->trigger_idx = trigger_idx;
// Increment the pointer
a->used += 1;
a->inputlen += symbol_len;
}
void freeArray(Array *a) {
terminal *ptr;
for (int x = 0; x < a->used; x++) {
ptr = &a->start[x];
free(ptr);
}
a->start = NULL;
a->used = a->size = 0;
}
/* Dynamic array for adding indices of states/recursive features
* Source:
* https://stackoverflow.com/questions/3536153/c-dynamically-growing-array
*/
void initArrayIdx(IdxMap *a, size_t initialSize) {
a->array = (int *)malloc(initialSize * sizeof(int));
a->used = 0;
a->size = initialSize;
}
void insertArrayIdx(IdxMap *a, int idx) {
// a->used is the number of used entries, because a->array[a->used++] updates
// a->used only *after* the array has been accessed. Therefore a->used can go
// up to a->size
if (a->used == a->size) {
a->size *= 2;
a->array = (int *)realloc(a->array, a->size * sizeof(int));
}
a->array[a->used++] = idx;
}
void freeArrayIdx(IdxMap *a) {
free(a->array);
a->array = NULL;
a->used = a->size = 0;
}
/* Dynamic array for adding potential splice points
*/
void initArraySplice(SpliceCandArray *a, size_t initialSize) {
a->start = (SpliceCand *)malloc(initialSize * sizeof(SpliceCand));
a->used = 0;
a->size = initialSize;
}
void insertArraySplice(SpliceCandArray *a, Candidate *candidate, int idx) {
// a->used is the number of used entries, because a->array[a->used++] updates
// a->used only *after* the array has been accessed. Therefore a->used can go
// up to a->size
SpliceCand *candptr;
if (a->used == a->size) {
a->size = a->size * sizeof(SpliceCand);
a->start = (SpliceCand *)realloc(a->start, a->size * sizeof(SpliceCand));
}
// Add the element
candptr = &a->start[a->used];
candptr->splice_cand = candidate;
candptr->idx = idx;
a->used += 1;
}
void freeArraySplice(IdxMap *a) {
free(a->array);
a->array = NULL;
a->used = a->size = 0;
}
int fact(int n) {
int i, f = 1;
for (i = 1; i <= n; i++) {
f *= i;
}
return f;
}
/* Uses the walk to create the input in-memory */
u8 *unparse_walk(Array *input) {
terminal *term_ptr;
int offset = 0;
u8 * unparsed = (u8 *)malloc(input->inputlen + 1);
term_ptr = &input->start[offset];
strcpy(unparsed, term_ptr->symbol);
offset += 1;
while (offset < input->used) {
term_ptr = &input->start[offset];
strcat(unparsed, term_ptr->symbol);
offset += 1;
}
return unparsed;
}
/*Dump the input representation into a file*/
void write_input(Array *input, u8 *fn) {
FILE *fp;
// If file already exists, then skip creating the file
if (access(fn, F_OK) != -1) { return; }
fp = fopen(fn, "wbx+");
// If the input has already been flushed, then skip silently
if (fp == NULL) {
fprintf(stderr, "\n File '%s' could not be open, exiting\n", fn);
exit(1);
}
// Write the length parameters
fwrite(&input->used, sizeof(size_t), 1, fp);
fwrite(&input->size, sizeof(size_t), 1, fp);
fwrite(&input->inputlen, sizeof(size_t), 1, fp);
// Write the dynamic array to file
fwrite(input->start, input->size * sizeof(terminal), 1, fp);
// printf("\nUsed:%zu Size:%zu Inputlen:%zu", input->used, input->size,
// input->inputlen);
fclose(fp);
}
Array *parse_input(state *pda, FILE *fp) {
terminal *term;
state * state_ptr;
trigger * trigger;
int trigger_idx;
Array * input = (Array *)calloc(1, sizeof(Array));
// Read the length parameters
fread(&input->used, sizeof(size_t), 1, fp);
fread(&input->size, sizeof(size_t), 1, fp);
fread(&input->inputlen, sizeof(size_t), 1, fp);
terminal *start_ptr = (terminal *)calloc(input->size, sizeof(terminal));
if (!start_ptr) {
fprintf(stderr, "alloc failed!\n");
return NULL;
}
// Read the dynamic array to memory
fread(start_ptr, input->size * sizeof(terminal), 1, fp);
// Update the pointers to the terminals since they would have
// changed
int idx = 0;
while (idx < input->used) {
terminal *term = &start_ptr[idx];
// Find the state
state_ptr = pda + term->state;
// Find the trigger and update the terminal address
trigger_idx = term->trigger_idx;
trigger = (state_ptr->ptr) + trigger_idx;
term->symbol = trigger->term;
idx += 1;
}
input->start = start_ptr;
// printf("\nUsed:%zu Size:%zu Inputlen:%zu", input->used, input->size,
// input->inputlen);
return input;
}
// Read the input representation into memory
Array *read_input(state *pda, u8 *fn) {
FILE *fp;
fp = fopen(fn, "rb");
if (fp == NULL) {
fprintf(stderr, "\n File '%s' does not exist, exiting\n", fn);
exit(1);
}
Array *res = parse_input(pda, fp);
fclose(fp);
return res;
}

View File

@ -1,429 +0,0 @@
// This simple example just creates random buffer <= 100 filled with 'A'
// needs -I /path/to/AFLplusplus/include
//#include "custom_mutator_helpers.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "afl-fuzz.h"
#include "gramfuzz.h"
#define MUTATORS 4 // Specify the total number of mutators
typedef struct my_mutator {
afl_state_t *afl;
u8 * mutator_buf;
u8 * unparsed_input;
Array *mutated_walk;
Array *orig_walk;
IdxMap_new *statemap; // Keeps track of the statemap
UT_array ** recurIdx;
// Get_Dupes_Ret* getdupesret; // Recursive feature map
int recurlen;
int mut_alloced;
int orig_alloced;
int mut_idx; // Signals the current mutator being used, used to cycle through
// each mutator
unsigned int seed;
} my_mutator_t;
state *create_pda(u8 *automaton_file) {
struct json_object *parsed_json;
state * pda;
json_object * source_obj, *attr;
int arraylen, ii, ii2, trigger_len, error;
printf("\n[GF] Automaton file passed:%s", automaton_file);
// parsed_json =
// json_object_from_file("./gramfuzz/php_gnf_processed_full.json");
parsed_json = json_object_from_file(automaton_file);
// Getting final state
source_obj = json_object_object_get(parsed_json, "final_state");
printf("\t\nFinal=%s\n", json_object_get_string(source_obj));
final_state = atoi(json_object_get_string(source_obj));
// Getting initial state
source_obj = json_object_object_get(parsed_json, "init_state");
init_state = atoi(json_object_get_string(source_obj));
printf("\tInit=%s\n", json_object_get_string(source_obj));
// Getting number of states
source_obj = json_object_object_get(parsed_json, "numstates");
numstates = atoi(json_object_get_string(source_obj)) + 1;
printf("\tNumStates=%d\n", numstates);
// Allocate state space for each pda state
pda = (state *)calloc(atoi(json_object_get_string(source_obj)) + 1,
sizeof(state));
// Getting PDA representation
source_obj = json_object_object_get(parsed_json, "pda");
enum json_type type;
json_object_object_foreach(source_obj, key, val) {
state * state_ptr;
trigger *trigger_ptr;
int offset;
// Get the correct offset into the pda to store state information
state_ptr = pda;
offset = atoi(key);
state_ptr += offset;
// Store state string
state_ptr->state_name = offset;
// Create trigger array of structs
trigger_len = json_object_array_length(val);
state_ptr->trigger_len = trigger_len;
trigger_ptr = (trigger *)calloc(trigger_len, sizeof(trigger));
state_ptr->ptr = trigger_ptr;
for (ii = 0; ii < trigger_len; ii++) {
json_object *obj = json_object_array_get_idx(val, ii);
// Get all the trigger trigger attributes
attr = json_object_array_get_idx(obj, 0);
(trigger_ptr)->id = strdup(json_object_get_string(attr));
attr = json_object_array_get_idx(obj, 1);
trigger_ptr->dest = atoi(json_object_get_string(attr));
attr = json_object_array_get_idx(obj, 2);
if (!strcmp("\\n", json_object_get_string(attr))) {
trigger_ptr->term = strdup("\n");
} else {
trigger_ptr->term = strdup(json_object_get_string(attr));
}
trigger_ptr->term_len = strlen(trigger_ptr->term);
trigger_ptr++;
}
}
// Delete the JSON object
json_object_put(parsed_json);
return pda;
}
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
if (!data) {
perror("afl_custom_init alloc");
return NULL;
}
if ((data->mutator_buf = malloc(MAX_FILE)) == NULL) {
perror("mutator_buf alloc");
return NULL;
}
data->afl = afl;
global_afl = afl; // dirty
data->seed = seed;
data->mut_alloced = 0;
data->orig_alloced = 0;
data->mut_idx = 0;
data->recurlen = 0;
// data->mutator_buf = NULL;
// data->unparsed_input = NULL;
// data->mutated_walk = NULL;
// data->orig_walk = NULL;
//
// data->statemap = NULL; // Keeps track of the statemap
// data->recur_idx = NULL; // Will keep track of recursive feature indices
// u32 recur_len = 0; // The number of recursive features
// data->mutator_buf = NULL;
char *automaton_file = getenv("GRAMATRON_AUTOMATION");
if (automaton_file) {
pda = create_pda(automaton_file);
} else {
fprintf(stderr,
"\nError: GrammaTron needs an automation json file set in "
"GRAMATRON_AUTOMATION\n");
exit(-1);
}
return data;
}
size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
u8 **out_buf, uint8_t *add_buf, size_t add_buf_size,
size_t max_size) {
u8 *unparsed_input;
// Pick a mutator
// int choice = rand() % MUTATORS;
// data->mut_idx = 1;
// GC old mutant
if (data->mut_alloced) {
free(data->mutated_walk->start);
free(data->mutated_walk);
data->mut_alloced = 0;
};
// printf("\nChoice:%d", choice);
if (data->mut_idx == 0) { // Perform random mutation
data->mutated_walk = performRandomMutation(pda, data->orig_walk);
data->mut_alloced = 1;
} else if (data->mut_idx == 1 &&
data->recurlen) { // Perform recursive mutation
data->mutated_walk =
doMult(data->orig_walk, data->recurIdx, data->recurlen);
data->mut_alloced = 1;
} else if (data->mut_idx == 2) { // Perform splice mutation
// we cannot use the supplied splice data so choose a new random file
u32 tid = rand_below(global_afl, data->afl->queued_items);
struct queue_entry *q = data->afl->queue_buf[tid];
// Read the input representation for the splice candidate
u8 * automaton_fn = alloc_printf("%s.aut", q->fname);
Array *spliceCandidate = read_input(pda, automaton_fn);
if (spliceCandidate) {
data->mutated_walk =
performSpliceOne(data->orig_walk, data->statemap, spliceCandidate);
data->mut_alloced = 1;
free(spliceCandidate->start);
free(spliceCandidate);
} else {
data->mutated_walk = gen_input(pda, NULL);
data->mut_alloced = 1;
}
ck_free(automaton_fn);
} else { // Generate an input from scratch
data->mutated_walk = gen_input(pda, NULL);
data->mut_alloced = 1;
}
// Cycle to the next mutator
if (data->mut_idx == MUTATORS - 1)
data->mut_idx =
0; // Wrap around if we have reached end of the mutator list
else
data->mut_idx += 1;
// Unparse the mutated automaton walk
if (data->unparsed_input) { free(data->unparsed_input); }
data->unparsed_input = unparse_walk(data->mutated_walk);
*out_buf = data->unparsed_input;
return data->mutated_walk->inputlen;
}
/**
* Create the automaton-based representation for the corresponding input
*
* @param data pointer returned in afl_custom_init for this fuzz case
* @param filename_new_queue File name of the new queue entry
* @param filename_orig_queue File name of the original queue entry
*/
u8 afl_custom_queue_new_entry(my_mutator_t * data,
const uint8_t *filename_new_queue,
const uint8_t *filename_orig_queue) {
// get the filename
u8 * automaton_fn, *unparsed_input;
Array *new_input;
s32 fd;
automaton_fn = alloc_printf("%s.aut", filename_new_queue);
// Check if this method is being called during initialization
// fprintf(stderr, "new: %s, old: %s, auto: %s\n",
// filename_new_queue,filename_orig_queue,automaton_fn);
if (filename_orig_queue) {
write_input(data->mutated_walk, automaton_fn);
} else {
new_input = gen_input(pda, NULL);
write_input(new_input, automaton_fn);
// Update the placeholder file
if (unlink(filename_new_queue)) {
PFATAL("Unable to delete '%s'", filename_new_queue);
}
unparsed_input = unparse_walk(new_input);
fd = open(filename_new_queue, O_WRONLY | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR);
if (fd < 0) { PFATAL("Failed to update file '%s'", filename_new_queue); }
int written = write(fd, unparsed_input, new_input->inputlen + 1);
close(fd);
free(new_input->start);
free(new_input);
free(unparsed_input);
}
ck_free(automaton_fn);
return 1;
}
/**
* Get the corresponding tree representation for the candidate that is to be
* mutated
*
* @param[in] data pointer returned in afl_custom_init for this fuzz case
* @param filename File name of the test case in the queue entry
* @return Return True(1) if the fuzzer will fuzz the queue entry, and
* False(0) otherwise.
*/
uint8_t afl_custom_queue_get(my_mutator_t *data, const uint8_t *filename) {
// get the filename
u8 * automaton_fn = alloc_printf("%s.aut", filename);
IdxMap_new *statemap_ptr;
terminal * term_ptr;
int state;
// TODO: I don't think we need to update pointers when reading back
// Probably build two different versions of read_input one for flushing
// inputs to disk and the other that
if (data->orig_alloced) {
free(data->orig_walk->start);
free(data->orig_walk);
data->orig_alloced = 0;
}
if (data->statemap) {
for (int x = 0; x < numstates; x++) {
utarray_free(data->statemap[x].nums);
}
free(data->statemap);
}
if (data->recurIdx) {
data->recurlen = 0;
free(data->recurIdx);
}
data->orig_walk = read_input(pda, automaton_fn);
data->orig_alloced = 1;
// Create statemap for the fuzz candidate
IdxMap_new *statemap_start =
(IdxMap_new *)malloc(sizeof(IdxMap_new) * numstates);
for (int x = 0; x < numstates; x++) {
statemap_ptr = &statemap_start[x];
utarray_new(statemap_ptr->nums, &ut_int_icd);
}
int offset = 0;
while (offset < data->orig_walk->used) {
term_ptr = &data->orig_walk->start[offset];
state = term_ptr->state;
statemap_ptr = &statemap_start[state];
utarray_push_back(statemap_ptr->nums, &offset);
offset += 1;
}
data->statemap = statemap_start;
// Create recursive feature map (if it exists)
data->recurIdx = malloc(sizeof(UT_array *) * numstates);
// Retrieve the duplicated states
offset = 0;
while (offset < numstates) {
statemap_ptr = &data->statemap[offset];
int length = utarray_len(statemap_ptr->nums);
if (length >= 2) {
data->recurIdx[data->recurlen] = statemap_ptr->nums;
data->recurlen += 1;
}
offset += 1;
}
// data->getdupesret = get_dupes(data->orig_walk, &data->recurlen);
ck_free(automaton_fn);
return 1;
}
/**
* Deinitialize everything
*
* @param data The data ptr from afl_custom_init
*/
void afl_custom_deinit(my_mutator_t *data) {
free(data->mutator_buf);
free(data);
}

View File

@ -1,255 +0,0 @@
#ifndef _GRAMFUZZ_H
#define _GRAMFUZZ_H
#include <json-c/json.h>
#include <unistd.h>
#include "hashmap.h"
#include "uthash.h"
#include "utarray.h"
#define INIT_INPUTS 100 // No. of initial inputs to be generated
// Set this as `numstates` + 1 where `numstates` is retrieved from gen automata
// json #define STATES 63
#define INIT_SIZE 100 // Initial size of the dynamic array holding the input
#define SPLICE_CORPUS 10000
#define RECUR_THRESHOLD 6
#define SIZE_THRESHOLD 2048
#define FLUSH_INTERVAL \
3600 // Inputs that gave new coverage will be dumped every FLUSH_INTERVAL
// seconds
afl_state_t *global_afl;
typedef struct trigger {
char * id;
int dest;
char * term;
size_t term_len;
} trigger;
typedef struct state {
int state_name; // Integer State name
int trigger_len; // Number of triggers associated with this state
trigger *ptr; // Pointer to beginning of the list of triggers
} state;
typedef struct terminal {
int state;
int trigger_idx;
size_t symbol_len;
char * symbol;
} terminal;
typedef struct buckethash {
int freq;
} buckethash;
int init_state;
int curr_state;
int final_state;
int numstates;
/*****************
/ DYNAMIC ARRAY FOR WALKS
*****************/
typedef struct {
size_t used;
size_t size;
size_t inputlen;
terminal *start;
} Array;
/*****************
/ DYNAMIC ARRAY FOR STATEMAPS/RECURSION MAPS
*****************/
typedef struct {
int * array;
size_t used;
size_t size;
} IdxMap;
typedef struct {
UT_array *nums;
} IdxMap_new;
typedef struct {
IdxMap_new *idxmap;
UT_array ** recurIdx;
} Get_Dupes_Ret;
/* Candidate Struct */
typedef struct {
Array * walk;
IdxMap_new *statemap;
} Candidate;
/* Splice Mutation helpers*/
typedef struct {
Candidate *splice_cand;
int idx;
} SpliceCand;
typedef struct {
SpliceCand *start;
size_t used;
size_t size;
} SpliceCandArray;
// Initialize dynamic array for potential splice points
SpliceCand potential[SPLICE_CORPUS];
typedef struct {
int orig_idx;
int splice_idx;
} intpair_t;
// Initialize dynamic array for potential splice points
// SpliceCand potential[SPLICE_CORPUS];
// IdxMap_new* rcuridx[STATES];
/* Prototypes*/
Array * slice(Array *, int);
state * create_pda(u8 *);
Array * gen_input(state *, Array *);
Array * gen_input_count(state *, Array *, int *);
int updatebucket(map_t, int);
void itoa(int, char *, int);
void strrreverse(char *, char *);
void dbg_hashmap(map_t);
void print_repr(Array *, char *);
int isSatisfied(map_t);
char * get_state(char *);
Candidate *gen_candidate(Array *);
Array *spliceGF(Array *, Array *, int);
Array *performSpliceOne(Array *, IdxMap_new *, Array *);
/* Mutation Methods*/
Array * performRandomMutation(state *, Array *);
Array * performRandomMutationCount(state *, Array *, int *);
Array * performSpliceMutationBench(state *, Array *, Candidate **);
UT_array **get_dupes(Array *, int *);
Array * doMult(Array *, UT_array **, int);
Array * doMultBench(Array *, UT_array **, int);
/* Benchmarks*/
void SpaceBenchmark(char *);
void GenInputBenchmark(char *, char *);
void RandomMutationBenchmark(char *, char *);
void MutationAggrBenchmark(char *, char *);
void SpliceMutationBenchmark(char *, char *);
void SpliceMutationBenchmarkOne(char *, char *);
void RandomRecursiveBenchmark(char *, char *);
/* Testers */
void SanityCheck(char *);
/*Helpers*/
void initArray(Array *, size_t);
void insertArray(Array *, int, char *, size_t, int);
void freeArray(Array *);
void initArrayIdx(IdxMap *, size_t);
void insertArrayIdx(IdxMap *, int);
void freeArrayIdx(IdxMap *);
void initArraySplice(SpliceCandArray *, size_t);
void insertArraySplice(SpliceCandArray *, Candidate *, int);
void freeArraySplice(IdxMap *);
void getTwoIndices(UT_array *, int, int *, int *);
void swap(int *, int *);
Array *slice_inverse(Array *, int);
void concatPrefixFeature(Array *, Array *);
void concatPrefixFeatureBench(Array *, Array *);
Array *carve(Array *, int, int);
int fact(int);
void add_to_corpus(struct json_object *, Array *);
struct json_object *term_to_json(terminal *);
/* Gramatron specific prototypes */
u8 * unparse_walk(Array *);
Array *performSpliceGF(state *, Array *, afl_state_t *);
void dump_input(u8 *, char *, int *);
void write_input(Array *, u8 *);
Array *read_input(state *, u8 *);
state *pda;
// // AFL-specific struct
// typedef uint8_t u8;
// typedef uint16_t u16;
// typedef uint32_t u32;
// #ifdef __x86_64__
// typedef unsigned long long u64;
// #else
// typedef uint64_t u64;
// #endif /* ^__x86_64__ */
//
// struct queue_entry {
// Array* walk; /* Pointer to the automaton walk*/
// u32 walk_len; /* Number of tokens in the input*/
// Candidate* cand; /* Preprocessed info about the
// candidate to allow for faster mutations*/
//
// u8* fname; /* File name for the test case */
// u32 len; /* Input length */
// UT_array** recur_idx; /* Keeps track of recursive feature
// indices*/
//
// u32 recur_len; /* The number of recursive features*/
//
// u8 cal_failed, /* Calibration failed? */
// trim_done, /* Trimmed? */
// was_fuzzed, /* Had any fuzzing done yet? */
// passed_det, /* Deterministic stages passed? */
// has_new_cov, /* Triggers new coverage? */
// var_behavior, /* Variable behavior? */
// favored, /* Currently favored? */
// fs_redundant; /* Marked as redundant in the fs? */
//
// u32 bitmap_size, /* Number of bits set in bitmap */
// exec_cksum; /* Checksum of the execution trace */
//
// u64 exec_us, /* Execution time (us) */
// handicap, /* Number of queue cycles behind */
// depth; /* Path depth */
//
// u8* trace_mini; /* Trace bytes, if kept */
// u32 tc_ref; /* Trace bytes ref count */
//
// struct queue_entry *next, /* Next element, if any */
// *next_100; /* 100 elements ahead */
//
// };
#endif

View File

@ -1,606 +0,0 @@
{
"ARGLIST": [
"EXPR ',' ARGLIST",
"EXPR",
"EXPR ',' ARGLIST",
"EXPR"
],
"ARGS": [
"'()'",
"'(' ARGLIST ')'",
"'()'",
"'(' ARGLIST ')'"
],
"ARITHMETICOPERATION": [
"EXPR '/' EXPR",
"EXPR '*' EXPR",
"EXPR '+' EXPR",
"EXPR '-' EXPR",
"EXPR '%' EXPR",
"EXPR '**' EXPR",
"EXPR '++'"
],
"ARRAY": [
"'[' ARRAYCONTENT ']'",
"'[]'"
],
"ARRAYCONTENT": [
"EXPR ',' ARRAYCONTENT",
"EXPR"
],
"BOOLEAN": [
"'true'",
"'false'"
],
"BYTEWISEOPERATION": [
"EXPR '&' EXPR",
"EXPR '|' EXPR"
],
"COMPARISONOPERATION": [
"EXPR '<' EXPR"
],
"DECIMALDIGITS": [
"'20'",
"'1234'",
"'66'",
"'234_9'",
"'99999999999999999999'"
],
"DECIMALNUMBER": [
"DECIMALDIGITS"
],
"EXPR": [
"'(' EXPR ')'",
"VAR",
"'delete' SP EXPR",
"'new' SP IDENTIFIER ARGS",
"LITERAL",
"IDENTIFIER",
"METHODCALL",
"'(' ARITHMETICOPERATION ')'",
"'(' COMPARISONOPERATION ')'",
"'(' BYTEWISEOPERATION ')'",
"'(' LOGICALOPERATION ')'"
],
"IDENTIFIER": [
"'Object'",
"VAR",
"'Function'",
"'main'",
"'opt'",
"'Boolean'",
"'Symbol'",
"'JSON'",
"'Error'",
"'EvalError'",
"'RangeError'",
"'ReferenceError'",
"'SyntaxError'",
"'TypeError'",
"'URIError'",
"'this'",
"'Number'",
"'Math'",
"'Date'",
"'String'",
"'RegExp'",
"'Array'",
"'Int8Array'",
"'Uint8Array'",
"'Uint8ClampedArray'",
"'Int16Array'",
"'Uint16Array'",
"'Int32Array'",
"'Uint32Array'",
"'Float32Array'",
"'Float64Array'",
"'DataView'",
"'ArrayBuffer'",
"'Map'",
"'Set'",
"'WeakMap'",
"'WeakSet'",
"'Promise'",
"'AsyncFunction'",
"'asyncGenerator'",
"'Reflect'",
"'Proxy'",
"'Intl'",
"'Intl.Collator'",
"'Intl.DateTimeFormat'",
"'Intl.NumberFormat'",
"'Intl.PluralRules'",
"'WebAssembly'",
"'WebAssembly.Module'",
"'WebAssembly.Instance'",
"'WebAssembly.Memory'",
"'WebAssembly.Table'",
"'WebAssembly.CompileError'",
"'WebAssembly.LinkError'",
"'WebAssembly.RuntimeError'",
"'arguments'",
"'Infinity'",
"'NaN'",
"'undefined'",
"'null'",
"'console'",
"' '"
],
"IDENTIFIERLIST": [
"IDENTIFIER ',' IDENTIFIERLIST",
"'(' IDENTIFIERLIST '),' IDENTIFIERLIST",
"IDENTIFIER"
],
"JSBLOCK": [
"JSSTATEMENT",
"JSSTATEMENT JSBLOCK"
],
"JSSTATEMENT": [
"STATEMENT NEWLINE"
],
"LITERAL": [
"'null'",
"BOOLEAN",
"NUMBER",
"ARRAY"
],
"LOGICALOPERATION": [
"EXPR '&&' EXPR",
"EXPR '||' EXPR"
],
"METHODCALL": [
"OBJECT PROPERTY METHODCALL1"
],
"METHODCALL1": [
"'.' METHOD_NAME ARGS METHODCALL1",
"' '"
],
"METHOD_NAME": [
"IDENTIFIER",
"'print'",
"'eval'",
"'uneval'",
"'isFinite'",
"'isNaN'",
"'parseFloat'",
"'parseInt'",
"'decodeURI'",
"'decodeURIComponent'",
"'encodeURI'",
"'encodeURIComponent'",
"'escape'",
"'unescape'",
"'assign'",
"'create'",
"'defineProperty'",
"'defineProperties'",
"'entries'",
"'freeze'",
"'getOwnPropertyDescriptor'",
"'getOwnPropertyDescriptors'",
"'getOwnPropertyNames'",
"'getOwnPropertySymbols'",
"'getPrototypeOf'",
"'is'",
"'isExtensible'",
"'isFrozen'",
"'isSealed'",
"'keys'",
"'preventExtensions'",
"'seal'",
"'setPrototypeOf'",
"'values'",
"'__defineGetter__'",
"'__defineSetter__'",
"'__lookupGetter__'",
"'__lookupSetter__'",
"'hasOwnProperty'",
"'isPrototypeOf'",
"'propertyIsEnumerable'",
"'toSource'",
"'toLocaleString'",
"'toString'",
"'unwatch'",
"'valueOf'",
"'watch'",
"'apply'",
"'bind'",
"'call'",
"'isGenerator'",
"'valueOf'",
"'for'",
"'keyFor'",
"'stringify'",
"'isInteger'",
"'isSafeInteger'",
"'toInteger'",
"'toExponential'",
"'toFixed'",
"'toLocaleString'",
"'toPrecision'",
"'abs'",
"'acos'",
"'acosh'",
"'asin'",
"'asinh'",
"'atan'",
"'atanh'",
"'atan2'",
"'cbrt'",
"'ceil'",
"'clz32'",
"'cos'",
"'cosh'",
"'exp'",
"'expm1'",
"'floor'",
"'fround'",
"'hypot'",
"'imul'",
"'log'",
"'log1p'",
"'log10'",
"'log2'",
"'max'",
"'min'",
"'pow'",
"'random'",
"'round'",
"'sign'",
"'sin'",
"'sinh'",
"'sqrt'",
"'tan'",
"'tanh'",
"'trunc'",
"'now'",
"'parse'",
"'UTC'",
"'getDate'",
"'getDay'",
"'getFullYear'",
"'getHours'",
"'getMilliseconds'",
"'getMinutes'",
"'getMonth'",
"'getSeconds'",
"'getTime'",
"'getTimezoneOffset'",
"'getUTCDate'",
"'getUTCDay'",
"'getUTCFullYear'",
"'getUTCHours'",
"'getUTCMilliseconds'",
"'getUTCMinutes'",
"'getUTCMonth'",
"'getUTCSeconds'",
"'getYear'",
"'setDate'",
"'setFullYear'",
"'setHours'",
"'setMilliseconds'",
"'setMinutes'",
"'setMonth'",
"'setSeconds'",
"'setTime'",
"'setUTCDate'",
"'setUTCFullYear'",
"'setUTCHours'",
"'setUTCMilliseconds'",
"'setUTCMinutes'",
"'setUTCMonth'",
"'setUTCSeconds'",
"'setYear'",
"'toDateString'",
"'toISOString'",
"'toJSON'",
"'toGMTString'",
"'toLocaleDateString'",
"'toLocaleFormat'",
"'toLocaleString'",
"'toLocaleTimeString'",
"'toTimeString'",
"'toUTCString'",
"'indexOf'",
"'substring'",
"'charAt'",
"'strcmp'",
"'fromCharCode'",
"'fromCodePoint'",
"'raw'",
"'charCodeAt'",
"'slice'",
"'codePointAt'",
"'concat'",
"'includes'",
"'endsWith'",
"'lastIndexOf'",
"'localeCompare'",
"'match'",
"'normalize'",
"'padEnd'",
"'padStart'",
"'quote'",
"'repeat'",
"'replace'",
"'search'",
"'split'",
"'startsWith'",
"'substr'",
"'toLocaleLowerCase'",
"'toLocaleUpperCase'",
"'toLowerCase'",
"'toUpperCase'",
"'trim'",
"'trimleft'",
"'trimright'",
"'anchor'",
"'big'",
"'blink'",
"'bold'",
"'fixed'",
"'fontcolor'",
"'fontsize'",
"'italics'",
"'link'",
"'small'",
"'strike'",
"'sub'",
"'sup'",
"'compile'",
"'exec'",
"'test'",
"'from'",
"'isArray'",
"'of'",
"'copyWithin'",
"'fill'",
"'pop'",
"'push'",
"'reverse'",
"'shift'",
"'sort'",
"'splice'",
"'unshift'",
"'concat'",
"'join'",
"'every'",
"'filter'",
"'findIndex'",
"'forEach'",
"'map'",
"'reduce'",
"'reduceRight'",
"'some'",
"'move'",
"'getInt8'",
"'getUint8'",
"'getInt16'",
"'getUint16'",
"'getInt32'",
"'getUint32'",
"'getFloat32'",
"'getFloat64'",
"'setInt8'",
"'setUint8'",
"'setInt16'",
"'setUint16'",
"'setInt32'",
"'setUint32'",
"'setFloat32'",
"'setFloat64'",
"'isView'",
"'transfer'",
"'clear'",
"'get'",
"'has'",
"'set'",
"'add'",
"'splat'",
"'check'",
"'extractLane'",
"'replaceLane'",
"'load'",
"'load1'",
"'load2'",
"'load3'",
"'store'",
"'store1'",
"'store2'",
"'store3'",
"'addSaturate'",
"'div'",
"'mul'",
"'neg'",
"'reciprocalApproximation'",
"'reciprocalSqrtApproximation'",
"'subSaturate'",
"'shuffle'",
"'swizzle'",
"'maxNum'",
"'minNum'",
"'select'",
"'equal'",
"'notEqual'",
"'lessThan'",
"'lessThanOrEqual'",
"'greaterThan'",
"'greaterThanOrEqual'",
"'and'",
"'or'",
"'xor'",
"'not'",
"'shiftLeftByScalar'",
"'shiftRightByScalar'",
"'allTrue'",
"'anyTrue'",
"'fromFloat32x4'",
"'fromFloat32x4Bits'",
"'fromFloat64x2Bits'",
"'fromInt32x4'",
"'fromInt32x4Bits'",
"'fromInt16x8Bits'",
"'fromInt8x16Bits'",
"'fromUint32x4'",
"'fromUint32x4Bits'",
"'fromUint16x8Bits'",
"'fromUint8x16Bits'",
"'neg'",
"'compareExchange'",
"'exchange'",
"'wait'",
"'wake'",
"'isLockFree'",
"'all'",
"'race'",
"'reject'",
"'resolve'",
"'catch'",
"'then'",
"'finally'",
"'next'",
"'throw'",
"'close'",
"'send'",
"'apply'",
"'construct'",
"'deleteProperty'",
"'ownKeys'",
"'getCanonicalLocales'",
"'supportedLocalesOf'",
"'resolvedOptions'",
"'formatToParts'",
"'resolvedOptions'",
"'instantiate'",
"'instantiateStreaming'",
"'compileStreaming'",
"'validate'",
"'customSections'",
"'exports'",
"'imports'",
"'grow'",
"'super'",
"'in'",
"'instanceof'",
"' '"
],
"NEWLINE": [
"'\\n'"
],
"NUMBER": [
"'1/2'",
"'1E2'",
"'1E02'",
"'1E+02'",
"'-1'",
"'-1.00'",
"'-1/2'",
"'-1E2'",
"'-1E02'",
"'-1E+02'",
"'1/0'",
"'0/0'",
"'-2147483648/-1'",
"'-9223372036854775808/-1'",
"'-0'",
"'-0.0'",
"'+0'"
],
"OBJECT": [
"IDENTIFIER"
],
"PROGRAM": [
"JSBLOCK"
],
"PROPERTY": [
"'.length' PROPERTY",
"'.prototype' PROPERTY",
"'.constructor' PROPERTY",
"'.__proto__' PROPERTY",
"'.__noSuchMethod__' PROPERTY",
"'.__count__' PROPERTY",
"'.__parent__' PROPERTY",
"'.arguments' PROPERTY",
"'.arity' PROPERTY",
"'.caller' PROPERTY",
"'.name' PROPERTY",
"'.displayName' PROPERTY",
"'.iterator' PROPERTY",
"'.asyncIterator' PROPERTY",
"'.match' PROPERTY",
"'.replace' PROPERTY",
"'.search' PROPERTY",
"'.split' PROPERTY",
"'.hasInstance' PROPERTY",
"'.isConcatSpreadable' PROPERTY",
"'.unscopables' PROPERTY",
"'.species' PROPERTY",
"'.toPrimitive' PROPERTY",
"'.toStringTag' PROPERTY",
"'.fileName' PROPERTY",
"'.lineNumber' PROPERTY",
"'.columnNumber' PROPERTY",
"'.message' PROPERTY",
"'.name' PROPERTY",
"'.EPSILON' PROPERTY",
"'.MAX_SAFE_INTEGER' PROPERTY",
"'.MAX_VALUE' PROPERTY",
"'.MIN_SAFE_INTEGER' PROPERTY",
"'.MIN_VALUE' PROPERTY",
"'.NaN' PROPERTY",
"'.NEGATIVE_INFINITY' PROPERTY",
"'.POSITIVE_INFINITY' PROPERTY",
"'.E' PROPERTY",
"'.LN2' PROPERTY",
"'.LN10' PROPERTY",
"'.LOG2E' PROPERTY",
"'.LOG10E' PROPERTY",
"'.PI' PROPERTY",
"'.SQRT1_2' PROPERTY",
"'.SQRT2' PROPERTY",
"'.flags' PROPERTY",
"'.global' PROPERTY",
"'.ignoreCase' PROPERTY",
"'.multiline' PROPERTY",
"'.source' PROPERTY",
"'.sticky' PROPERTY",
"'.unicode' PROPERTY",
"'.buffer' PROPERTY",
"'.byteLength' PROPERTY",
"'.byteOffset' PROPERTY",
"'.BYTES_PER_ELEMENT' PROPERTY",
"'.compare' PROPERTY",
"'.format' PROPERTY",
"'.callee' PROPERTY",
"'.caller' PROPERTY",
"'.memory' PROPERTY",
"'.exports' PROPERTY",
"' '"
],
"SP": [
"' '"
],
"STATEMENT": [
"EXPR ';'",
"'var' SP VAR '=' EXPR ';'",
"'let' SP VAR '=' EXPR ';'",
"VAR '=' EXPR ';'",
"VAR PROPERTY '=' EXPR ';'",
"VAR '[' DECIMALNUMBER ']' '=' EXPR ';'",
"'const' SP VAR '=' EXPR ';'",
"'typeof' SP EXPR ';'",
"'void' SP EXPR ';'",
"'return' SP EXPR ';'",
"VAR ':'"
],
"VAR": [
"'a'",
"'b'",
"'c'",
"'d'",
"'e'",
"'f'",
"'g'",
"'h'"
]
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,434 +0,0 @@
/*
* Generic map implementation.
*/
#include "hashmap.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define INITIAL_SIZE (256)
#define MAX_CHAIN_LENGTH (8)
/* We need to keep keys and values */
typedef struct _hashmap_element {
char *key;
int in_use;
any_t data;
} hashmap_element;
/* A hashmap has some maximum size and current size,
* as well as the data to hold. */
typedef struct _hashmap_map {
int table_size;
int size;
hashmap_element *data;
} hashmap_map;
/*
* Return an empty hashmap, or NULL on failure.
*/
map_t hashmap_new() {
hashmap_map *m = (hashmap_map *)malloc(sizeof(hashmap_map));
if (!m) goto err;
m->data = (hashmap_element *)calloc(INITIAL_SIZE, sizeof(hashmap_element));
if (!m->data) goto err;
m->table_size = INITIAL_SIZE;
m->size = 0;
return m;
err:
if (m) hashmap_free(m);
return NULL;
}
/* The implementation here was originally done by Gary S. Brown. I have
borrowed the tables directly, and made some minor changes to the
crc32-function (including changing the interface). //ylo */
/* ============================================================= */
/* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or */
/* code or tables extracted from it, as desired without restriction. */
/* */
/* First, the polynomial itself and its table of feedback terms. The */
/* polynomial is */
/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
/* */
/* Note that we take it "backwards" and put the highest-order term in */
/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */
/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */
/* the MSB being 1. */
/* */
/* Note that the usual hardware shift register implementation, which */
/* is what we're using (we're merely optimizing it by doing eight-bit */
/* chunks at a time) shifts bits into the lowest-order term. In our */
/* implementation, that means shifting towards the right. Why do we */
/* do it this way? Because the calculated CRC must be transmitted in */
/* order from highest-order term to lowest-order term. UARTs transmit */
/* characters in order from LSB to MSB. By storing the CRC this way, */
/* we hand it to the UART in the order low-byte to high-byte; the UART */
/* sends each low-bit to hight-bit; and the result is transmission bit */
/* by bit from highest- to lowest-order term without requiring any bit */
/* shuffling on our part. Reception works similarly. */
/* */
/* The feedback terms table consists of 256, 32-bit entries. Notes: */
/* */
/* The table can be generated at runtime if desired; code to do so */
/* is shown later. It might not be obvious, but the feedback */
/* terms simply represent the results of eight shift/xor opera- */
/* tions for all combinations of data and CRC register values. */
/* */
/* The values must be right-shifted by eight bits by the "updcrc" */
/* logic; the shift must be unsigned (bring in zeroes). On some */
/* hardware you could probably optimize the shift in assembler by */
/* using byte-swap instructions. */
/* polynomial $edb88320 */
/* */
/* -------------------------------------------------------------------- */
static unsigned long crc32_tab[] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
0x2d02ef8dL};
/* Return a 32-bit CRC of the contents of the buffer. */
unsigned long crc32(const unsigned char *s, unsigned int len) {
unsigned int i;
unsigned long crc32val;
crc32val = 0;
for (i = 0; i < len; i++) {
crc32val = crc32_tab[(crc32val ^ s[i]) & 0xff] ^ (crc32val >> 8);
}
return crc32val;
}
/*
* Hashing function for a string
*/
unsigned int hashmap_hash_int(hashmap_map *m, char *keystring) {
unsigned long key = crc32((unsigned char *)(keystring), strlen(keystring));
/* Robert Jenkins' 32 bit Mix Function */
key += (key << 12);
key ^= (key >> 22);
key += (key << 4);
key ^= (key >> 9);
key += (key << 10);
key ^= (key >> 2);
key += (key << 7);
key ^= (key >> 12);
/* Knuth's Multiplicative Method */
key = (key >> 3) * 2654435761;
return key % m->table_size;
}
/*
* Return the integer of the location in data
* to store the point to the item, or MAP_FULL.
*/
int hashmap_hash(map_t in, char *key) {
int curr;
int i;
/* Cast the hashmap */
hashmap_map *m = (hashmap_map *)in;
/* If full, return immediately */
if (m->size >= (m->table_size / 2)) return MAP_FULL;
/* Find the best index */
curr = hashmap_hash_int(m, key);
/* Linear probing */
for (i = 0; i < MAX_CHAIN_LENGTH; i++) {
if (m->data[curr].in_use == 0) return curr;
if (m->data[curr].in_use == 1 && (strcmp(m->data[curr].key, key) == 0))
return curr;
curr = (curr + 1) % m->table_size;
}
return MAP_FULL;
}
/*
* Doubles the size of the hashmap, and rehashes all the elements
*/
int hashmap_rehash(map_t in) {
int i;
int old_size;
hashmap_element *curr;
/* Setup the new elements */
hashmap_map * m = (hashmap_map *)in;
hashmap_element *temp =
(hashmap_element *)calloc(2 * m->table_size, sizeof(hashmap_element));
if (!temp) return MAP_OMEM;
/* Update the array */
curr = m->data;
m->data = temp;
/* Update the size */
old_size = m->table_size;
m->table_size = 2 * m->table_size;
m->size = 0;
/* Rehash the elements */
for (i = 0; i < old_size; i++) {
int status;
if (curr[i].in_use == 0) continue;
status = hashmap_put(m, curr[i].key, curr[i].data);
if (status != MAP_OK) return status;
}
free(curr);
return MAP_OK;
}
/*
* Add a pointer to the hashmap with some key
*/
int hashmap_put(map_t in, char *key, any_t value) {
int index;
hashmap_map *m;
/* Cast the hashmap */
m = (hashmap_map *)in;
/* Find a place to put our value */
index = hashmap_hash(in, key);
while (index == MAP_FULL) {
if (hashmap_rehash(in) == MAP_OMEM) { return MAP_OMEM; }
index = hashmap_hash(in, key);
}
/* Set the data */
m->data[index].data = value;
m->data[index].key = key;
m->data[index].in_use = 1;
m->size++;
return MAP_OK;
}
/*
* Get your pointer out of the hashmap with a key
*/
int hashmap_get(map_t in, char *key, any_t *arg) {
int curr;
int i;
hashmap_map *m;
/* Cast the hashmap */
m = (hashmap_map *)in;
/* Find data location */
curr = hashmap_hash_int(m, key);
/* Linear probing, if necessary */
for (i = 0; i < MAX_CHAIN_LENGTH; i++) {
int in_use = m->data[curr].in_use;
if (in_use == 1) {
if (strcmp(m->data[curr].key, key) == 0) {
*arg = (m->data[curr].data);
return MAP_OK;
}
}
curr = (curr + 1) % m->table_size;
}
*arg = NULL;
/* Not found */
return MAP_MISSING;
}
/*
* Iterate the function parameter over each element in the hashmap. The
* additional any_t argument is passed to the function as its first
* argument and the hashmap element is the second.
*/
int hashmap_iterate(map_t in, PFany f, any_t item) {
int i;
/* Cast the hashmap */
hashmap_map *m = (hashmap_map *)in;
/* On empty hashmap, return immediately */
if (hashmap_length(m) <= 0) return MAP_MISSING;
/* Linear probing */
for (i = 0; i < m->table_size; i++)
if (m->data[i].in_use != 0) {
any_t data = (any_t)(m->data[i].data);
int status = f(item, data);
if (status != MAP_OK) { return status; }
}
return MAP_OK;
}
/*
* Remove an element with that key from the map
*/
int hashmap_remove(map_t in, char *key) {
int i;
int curr;
hashmap_map *m;
/* Cast the hashmap */
m = (hashmap_map *)in;
/* Find key */
curr = hashmap_hash_int(m, key);
/* Linear probing, if necessary */
for (i = 0; i < MAX_CHAIN_LENGTH; i++) {
int in_use = m->data[curr].in_use;
if (in_use == 1) {
if (strcmp(m->data[curr].key, key) == 0) {
/* Blank out the fields */
m->data[curr].in_use = 0;
m->data[curr].data = NULL;
m->data[curr].key = NULL;
/* Reduce the size */
m->size--;
return MAP_OK;
}
}
curr = (curr + 1) % m->table_size;
}
/* Data not found */
return MAP_MISSING;
}
/* Deallocate the hashmap */
void hashmap_free(map_t in) {
hashmap_map *m = (hashmap_map *)in;
free(m->data);
free(m);
}
/* Return the length of the hashmap */
int hashmap_length(map_t in) {
hashmap_map *m = (hashmap_map *)in;
if (m != NULL)
return m->size;
else
return 0;
}

View File

@ -1,83 +0,0 @@
/*
* Generic hashmap manipulation functions
*
* Originally by Elliot C Back -
* http://elliottback.com/wp/hashmap-implementation-in-c/
*
* Modified by Pete Warden to fix a serious performance problem, support strings
* as keys and removed thread synchronization - http://petewarden.typepad.com
*/
#ifndef __HASHMAP_H__
#define __HASHMAP_H__
#define MAP_MISSING -3 /* No such element */
#define MAP_FULL -2 /* Hashmap is full */
#define MAP_OMEM -1 /* Out of Memory */
#define MAP_OK 0 /* OK */
/*
* any_t is a pointer. This allows you to put arbitrary structures in
* the hashmap.
*/
typedef void *any_t;
/*
* PFany is a pointer to a function that can take two any_t arguments
* and return an integer. Returns status code..
*/
typedef int (*PFany)(any_t, any_t);
/*
* map_t is a pointer to an internally maintained data structure.
* Clients of this package do not need to know how hashmaps are
* represented. They see and manipulate only map_t's.
*/
typedef any_t map_t;
/*
* Return an empty hashmap. Returns NULL if empty.
*/
extern map_t hashmap_new();
/*
* Iteratively call f with argument (item, data) for
* each element data in the hashmap. The function must
* return a map status code. If it returns anything other
* than MAP_OK the traversal is terminated. f must
* not reenter any hashmap functions, or deadlock may arise.
*/
extern int hashmap_iterate(map_t in, PFany f, any_t item);
/*
* Add an element to the hashmap. Return MAP_OK or MAP_OMEM.
*/
extern int hashmap_put(map_t in, char *key, any_t value);
/*
* Get an element from the hashmap. Return MAP_OK or MAP_MISSING.
*/
extern int hashmap_get(map_t in, char *key, any_t *arg);
/*
* Remove an element from the hashmap. Return MAP_OK or MAP_MISSING.
*/
extern int hashmap_remove(map_t in, char *key);
/*
* Get any element. Return MAP_OK or MAP_MISSING.
* remove - should the element be removed from the hashmap
*/
extern int hashmap_get_one(map_t in, any_t *arg, int remove);
/*
* Free the hashmap
*/
extern void hashmap_free(map_t in);
/*
* Get the current size of a hashmap
*/
extern int hashmap_length(map_t in);
#endif

View File

@ -1,275 +0,0 @@
import sys
import json
import re
from collections import defaultdict
# import pygraphviz as pgv
gram_data = None
state_count = 1
pda = []
worklist = []
state_stacks = {}
# === If user provides upper bound on the stack size during FSA creation ===
# Specifies the upper bound to which the stack is allowed to grow
# If for any generated state, the stack size is >= stack_limit then this
# state is not expanded further.
stack_limit = None
# Holds the set of unexpanded rules owing to the user-passed stack constraint limit
unexpanded_rules = set()
def main(grammar, limit):
global worklist, gram_data, stack_limit
current = '0'
stack_limit = limit
if stack_limit:
print ('[X] Operating in bounded stack mode')
with open(grammar, 'r') as fd:
gram_data = json.load(fd)
start_symbol = gram_data["Start"][0]
worklist.append([current, [start_symbol]])
# print (grammar)
filename = (grammar.split('/')[-1]).split('.')[0]
while worklist:
# Take an element from the worklist
# print ('================')
# print ('Worklist:', worklist)
element = worklist.pop(0)
prep_transitions(element)
pda_file = filename + '_transition.json'
graph_file = filename + '.png'
# print ('XXXXXXXXXXXXXXXX')
# print ('PDA file:%s Png graph file:%s' % (pda_file, graph_file))
# XXX Commented out because visualization of current version of PHP causes segfault
# Create the graph and dump the transitions to a file
# create_graph(filename)
transformed = postprocess()
with open(filename + '_automata.json', 'w+') as fd:
json.dump(transformed, fd)
with open(filename + '_transition.json', 'w+') as fd:
json.dump(pda, fd)
if not unexpanded_rules:
print ('[X] No unexpanded rules, absolute FSA formed')
exit(0)
else:
print ('[X] Certain rules were not expanded due to stack size limit. Inexact approximation has been created and the disallowed rules have been put in {}_disallowed.json'.format(filename))
print ('[X] Number of unexpanded rules:', len(unexpanded_rules))
with open(filename + '_disallowed.json', 'w+') as fd:
json.dump(list(unexpanded_rules), fd)
def create_graph(filename):
'''
Creates a DOT representation of the PDA
'''
global pda
G = pgv.AGraph(strict = False, directed = True)
for transition in pda:
print ('Transition:', transition)
G.add_edge(transition['source'], transition['dest'],
label = 'Term:{}'.format(transition['terminal']))
G.layout(prog = 'dot')
print ('Do it up 2')
G.draw(filename + '.png')
def prep_transitions(element):
'''
Generates transitions
'''
global gram_data, state_count, pda, worklist, state_stacks, stack_limit, unexpanded_rules
state = element[0]
try:
nonterminal = element[1][0]
except IndexError:
# Final state was encountered, pop from worklist without doing anything
return
rules = gram_data[nonterminal]
count = 1
for rule in rules:
isRecursive = False
# print ('Current state:', state)
terminal, ss, termIsRegex = tokenize(rule)
transition = get_template()
transition['trigger'] = '_'.join([state, str(count)])
transition['source'] = state
transition['dest'] = str(state_count)
transition['ss'] = ss
transition['terminal'] = terminal
transition['rule'] = "{} -> {}".format(nonterminal, rule )
if termIsRegex:
transition['termIsRegex'] = True
# Creating a state stack for the new state
try:
state_stack = state_stacks[state][:]
except:
state_stack = []
if len(state_stack):
state_stack.pop(0)
if ss:
for symbol in ss[::-1]:
state_stack.insert(0, symbol)
transition['stack'] = state_stack
# Check if a recursive transition state being created, if so make a backward
# edge and don't add anything to the worklist
# print (state_stacks)
if state_stacks:
for state_element, stack in state_stacks.items():
# print ('Stack:', sorted(stack))
# print ('State stack:', sorted(state_stack))
if sorted(stack) == sorted(state_stack):
transition['dest'] = state_element
# print ('Recursive:', transition)
pda.append(transition)
count += 1
isRecursive = True
break
# If a recursive transition exercised don't add the same transition as a new
# edge, continue onto the next transitions
if isRecursive:
continue
# If the generated state has a stack size > stack_limit then that state is abandoned
# and not added to the FSA or the worklist for further expansion
if stack_limit:
if (len(transition['stack']) > stack_limit):
unexpanded_rules.add(transition['rule'])
continue
# Create transitions for the non-recursive relations and add to the worklist
# print ('Normal:', transition)
# print ('State2:', state)
pda.append(transition)
worklist.append([transition['dest'], transition['stack']])
state_stacks[transition['dest']] = state_stack
state_count += 1
count += 1
def tokenize(rule):
'''
Gets the terminal and the corresponding stack symbols from a rule in GNF form
'''
pattern = re.compile("([r])*\'([\s\S]+)\'([\s\S]*)")
terminal = None
ss = None
termIsRegex = False
match = pattern.match(rule)
if match.group(1):
termIsRegex = True
if match.group(2):
terminal = match.group(2)
else:
raise AssertionError("Rule is not in GNF form")
if match.group(3):
ss = (match.group(3)).split()
return terminal, ss, termIsRegex
def get_template():
transition_template = {
'trigger':None,
'source': None,
'dest': None,
'termIsRegex': False,
'terminal' : None,
'stack': []
}
return transition_template
def postprocess():
'''
Creates a representation to be passed on to the C-module
'''
global pda
final_struct = {}
memoized = defaultdict(list)
# Supporting data structures for if stack limit is imposed
culled_pda = []
culled_final = []
num_transitions = 0 # Keep track of number of transitions
states, final, initial = _get_states()
print (initial)
assert len(initial) == 1, 'More than one init state found'
# Cull transitions to states which were not expanded owing to the stack limit
if stack_limit:
blocklist = []
for final_state in final:
for transition in pda:
if (transition["dest"] == final_state) and (len(transition["stack"]) > 0):
blocklist.append(transition["dest"])
continue
else:
culled_pda.append(transition)
culled_final = [state for state in final if state not in blocklist]
assert len(culled_final) == 1, 'More than one final state found'
for transition in culled_pda:
state = transition["source"]
if transition["dest"] in blocklist:
continue
num_transitions += 1
memoized[state].append([transition["trigger"], transition["dest"],
transition["terminal"]])
final_struct["init_state"] = initial
final_struct["final_state"] = culled_final[0]
# The reason we do this is because when states are culled, the indexing is
# still relative to the actual number of states hence we keep numstates recorded
# as the original number of states
print ('[X] Actual Number of states:', len(memoized.keys()))
print ('[X] Number of transitions:', num_transitions)
print ('[X] Original Number of states:', len(states))
final_struct["numstates"] = len(states)
final_struct["pda"] = memoized
return final_struct
# Running FSA construction in exact approximation mode and postprocessing it like so
for transition in pda:
state = transition["source"]
memoized[state].append([transition["trigger"], transition["dest"],
transition["terminal"]])
final_struct["init_state"] = initial
final_struct["final_state"] = final[0]
print ('[X] Actual Number of states:', len(memoized.keys()))
final_struct["numstates"] = len(memoized.keys())
final_struct["pda"] = memoized
return final_struct
def _get_states():
source = set()
dest = set()
global pda
for transition in pda:
source.add(transition["source"])
dest.add(transition["dest"])
source_copy = source.copy()
source_copy.update(dest)
return list(source_copy), list(dest.difference(source)), str(''.join(list(source.difference(dest))))
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser(description = 'Script to convert GNF grammar to PDA')
parser.add_argument(
'--gf',
type = str,
help = 'Location of GNF grammar')
parser.add_argument(
'--limit',
type = int,
default = None,
help = 'Specify the upper bound for the stack size')
args = parser.parse_args()
main(args.gf, args.limit)

View File

@ -1,289 +0,0 @@
import sys
import re
import copy
import json
from string import ascii_uppercase
from itertools import combinations
from collections import defaultdict
NONTERMINALSET = []
COUNT = 1
def main(grammar_file, out, start):
grammar = None
# If grammar file is a preprocessed NT file, then skip preprocessing
if '.json' in grammar_file:
with open(grammar_file, 'r') as fd:
grammar = json.load(fd)
elif '.g4' in grammar_file:
with open(grammar_file, 'r') as fd:
data = fd.readlines()
grammar = preprocess(data)
else:
raise('Unknwown file format passed. Accepts (.g4/.json)')
with open('debug_preprocess.json', 'w+') as fd:
json.dump(grammar, fd)
grammar = remove_unit(grammar) # eliminates unit productions
with open('debug_unit.json', 'w+') as fd:
json.dump(grammar, fd)
grammar = remove_mixed(grammar) # eliminate terminals existing with non-terminals
with open('debug_mixed.json', 'w+') as fd:
json.dump(grammar, fd)
grammar = break_rules(grammar) # eliminate rules with more than two non-terminals
with open('debug_break.json', 'w+') as fd:
json.dump(grammar, fd)
grammar = gnf(grammar)
# Dump GNF form of the grammar with only reachable rules
# reachable_grammar = get_reachable(grammar, start)
# with open('debug_gnf_reachable.json', 'w+') as fd:
# json.dump(reachable_grammar, fd)
with open('debug_gnf.json', 'w+') as fd:
json.dump(grammar, fd)
grammar["Start"] = [start]
with open(out, 'w+') as fd:
json.dump(grammar, fd)
def get_reachable(grammar, start):
'''
Returns a grammar without dead rules
'''
reachable_nt = set()
worklist = list()
processed = set()
reachable_grammar = dict()
worklist.append(start)
while worklist:
nt = worklist.pop(0)
processed.add(nt)
reachable_grammar[nt] = grammar[nt]
rules = grammar[nt]
for rule in rules:
tokens = gettokens(rule)
for token in tokens:
if not isTerminal(token):
if token not in processed:
worklist.append(token)
return reachable_grammar
def gettokens(rule):
pattern = re.compile("([^\s\"\']+)|\"([^\"]*)\"|\'([^\']*)\'")
return [matched.group(0) for matched in pattern.finditer(rule)]
def gnf(grammar):
old_grammar = copy.deepcopy(grammar)
new_grammar = defaultdict(list)
isgnf = False
while not isgnf:
for lhs, rules in old_grammar.items():
for rule in rules:
tokens = gettokens(rule)
if len(tokens) == 1 and isTerminal(rule):
new_grammar[lhs].append(rule)
continue
startoken = tokens[0]
endrule = tokens[1:]
if not isTerminal(startoken):
newrules = []
extendrules = old_grammar[startoken]
for extension in extendrules:
temprule = endrule[:]
temprule.insert(0, extension)
newrules.append(temprule)
for newnew in newrules:
new_grammar[lhs].append(' '.join(newnew))
else:
new_grammar[lhs].append(rule)
isgnf = True
for lhs, rules in new_grammar.items():
for rule in rules:
# if "\' \'" or isTerminal(rule):
tokens = gettokens(rule)
if len(tokens) == 1 and isTerminal(rule):
continue
startoken = tokens[0]
if not isTerminal(startoken):
isgnf = False
break
if not isgnf:
old_grammar = copy.deepcopy(new_grammar)
new_grammar = defaultdict(list)
return new_grammar
def preprocess(data):
productions = []
production = []
for line in data:
if line != '\n':
production.append(line)
else:
productions.append(production)
production = []
final_rule_set = {}
for production in productions:
rules = []
init = production[0]
nonterminal = init.split(':')[0]
rules.append(strip_chars(init.split(':')[1]).strip('| '))
for production_rule in production[1:]:
rules.append(strip_chars(production_rule.split('|')[0]))
final_rule_set[nonterminal] = rules
# for line in data:
# if line != '\n':
# production.append(line)
return final_rule_set
def remove_unit(grammar):
nounitproductions = False
old_grammar = copy.deepcopy(grammar)
new_grammar = defaultdict(list)
while not nounitproductions:
for lhs, rules in old_grammar.items():
for rhs in rules:
# Checking if the rule is a unit production rule
if len(gettokens(rhs)) == 1:
if not isTerminal(rhs):
new_grammar[lhs].extend([rule for rule in old_grammar[rhs]])
else:
new_grammar[lhs].append(rhs)
else:
new_grammar[lhs].append(rhs)
# Checking there are no unit productions left in the grammar
nounitproductions = True
for lhs, rules in new_grammar.items():
for rhs in rules:
if len(gettokens(rhs)) == 1:
if not isTerminal(rhs):
nounitproductions = False
break
if not nounitproductions:
break
# Unit productions are still there in the grammar -- repeat the process
if not nounitproductions:
old_grammar = copy.deepcopy(new_grammar)
new_grammar = defaultdict(list)
return new_grammar
def isTerminal(rule):
# pattern = re.compile("([r]*\'[\s\S]+\')")
pattern = re.compile("\'(.*?)\'")
match = pattern.match(rule)
if match:
return True
else:
return False
def remove_mixed(grammar):
'''
Remove rules where there are terminals mixed in with non-terminals
'''
new_grammar = defaultdict(list)
for lhs, rules in grammar.items():
for rhs in rules:
# tokens = rhs.split(' ')
regen_rule = []
tokens = gettokens(rhs)
if len(gettokens(rhs)) == 1:
new_grammar[lhs].append(rhs)
continue
for token in tokens:
# Identify if there is a terminal in the RHS
if isTerminal(token):
# Check if a corresponding nonterminal already exists
nonterminal = terminal_exist(token, new_grammar)
if nonterminal:
regen_rule.append(nonterminal)
else:
new_nonterm = get_nonterminal()
new_grammar[new_nonterm].append(token)
regen_rule.append(new_nonterm)
else:
regen_rule.append(token)
new_grammar[lhs].append(' '.join(regen_rule))
return new_grammar
def break_rules(grammar):
new_grammar = defaultdict(list)
old_grammar = copy.deepcopy(grammar)
nomulti = False
while not nomulti:
for lhs, rules in old_grammar.items():
for rhs in rules:
tokens = gettokens(rhs)
if len(tokens) > 2 and (not isTerminal(rhs)):
split = tokens[:-1]
nonterminal = terminal_exist(' '.join(split), new_grammar)
if nonterminal:
newrule = ' '.join([nonterminal, tokens[-1]])
new_grammar[lhs].append(newrule)
else:
nonterminal = get_nonterminal()
new_grammar[nonterminal].append(' '.join(split))
newrule = ' '.join([nonterminal, tokens[-1]])
new_grammar[lhs].append(newrule)
else:
new_grammar[lhs].append(rhs)
nomulti = True
for lhs, rules in new_grammar.items():
for rhs in rules:
# tokens = rhs.split(' ')
tokens = gettokens(rhs)
if len(tokens) > 2 and (not isTerminal(rhs)):
nomulti = False
break
if not nomulti:
old_grammar = copy.deepcopy(new_grammar)
new_grammar = defaultdict(list)
return new_grammar
def strip_chars(rule):
return rule.strip('\n\t ')
def get_nonterminal():
global NONTERMINALSET
if NONTERMINALSET:
return NONTERMINALSET.pop(0)
else:
_repopulate()
return NONTERMINALSET.pop(0)
def _repopulate():
global COUNT
global NONTERMINALSET
NONTERMINALSET = [''.join(x) for x in list(combinations(ascii_uppercase, COUNT))]
COUNT += 1
def terminal_exist(token, grammar):
for nonterminal, rules in grammar.items():
if token in rules:
return nonterminal
return None
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser(description = 'Script to convert grammar to GNF form')
parser.add_argument(
'--gf',
type = str,
required = True,
help = 'Location of grammar file')
parser.add_argument(
'--out',
type = str,
required = True,
help = 'Location of output file')
parser.add_argument(
'--start',
type = str,
required = True,
help = 'Start token')
args = parser.parse_args()
main(args.gf, args.out, args.start)

View File

@ -1,38 +0,0 @@
#!/bin/bash
# This script creates a FSA describing the input grammar *.g4
if [ ! "$#" -lt 4 ]; then
echo "Usage: ./prep_pda.sh <grammar_file> <start> [stack_limit]"
exit 1
fi
GRAMMAR_FILE=$1
GRAMMAR_DIR="$(dirname $GRAMMAR_FILE)"
START="$2"
STACK_LIMIT="$3"
# Get filename
FILE=$(basename -- "$GRAMMAR_FILE")
echo "File:$FILE"
FILENAME="${FILE%.*}"
echo "Name:$FILENAME"
# Create the GNF form of the grammar
CMD="python gnf_converter.py --gf $GRAMMAR_FILE --out ${FILENAME}.json --start $START"
$CMD
# Generate grammar automaton
# Check if user provided a stack limit
if [ -z "${STACK_LIMIT}" ]; then
CMD="python3 construct_automata.py --gf ${FILENAME}.json"
else
CMD="python construct_automata.py --gf ${FILENAME}.json --limit ${STACK_LIMIT}"
fi
echo $CMD
$CMD
# Move PDA to the source dir of the grammar
echo "Copying ${FILENAME}_automata.json to $GRAMMAR_DIR"
mv "${FILENAME}_automata.json" $GRAMMAR_DIR/

View File

@ -1,154 +0,0 @@
/* This is the testing module for Gramatron
*/
#include "afl-fuzz.h"
#include "gramfuzz.h"
#define NUMINPUTS 50
state *create_pda(u8 *automaton_file) {
struct json_object *parsed_json;
state * pda;
json_object * source_obj, *attr;
int arraylen, ii, ii2, trigger_len, error;
printf("\n[GF] Automaton file passed:%s", automaton_file);
// parsed_json =
// json_object_from_file("./gramfuzz/php_gnf_processed_full.json");
parsed_json = json_object_from_file(automaton_file);
// Getting final state
source_obj = json_object_object_get(parsed_json, "final_state");
printf("\t\nFinal=%s\n", json_object_get_string(source_obj));
final_state = atoi(json_object_get_string(source_obj));
// Getting initial state
source_obj = json_object_object_get(parsed_json, "init_state");
init_state = atoi(json_object_get_string(source_obj));
printf("\tInit=%s\n", json_object_get_string(source_obj));
// Getting number of states
source_obj = json_object_object_get(parsed_json, "numstates");
numstates = atoi(json_object_get_string(source_obj)) + 1;
printf("\tNumStates=%d\n", numstates);
// Allocate state space for each pda state
pda = (state *)calloc(atoi(json_object_get_string(source_obj)) + 1,
sizeof(state));
// Getting PDA representation
source_obj = json_object_object_get(parsed_json, "pda");
enum json_type type;
json_object_object_foreach(source_obj, key, val) {
state * state_ptr;
trigger *trigger_ptr;
int offset;
// Get the correct offset into the pda to store state information
state_ptr = pda;
offset = atoi(key);
state_ptr += offset;
// Store state string
state_ptr->state_name = offset;
// Create trigger array of structs
trigger_len = json_object_array_length(val);
state_ptr->trigger_len = trigger_len;
trigger_ptr = (trigger *)calloc(trigger_len, sizeof(trigger));
state_ptr->ptr = trigger_ptr;
printf("\nName:%d Trigger:%d", offset, trigger_len);
for (ii = 0; ii < trigger_len; ii++) {
json_object *obj = json_object_array_get_idx(val, ii);
// Get all the trigger trigger attributes
attr = json_object_array_get_idx(obj, 0);
(trigger_ptr)->id = strdup(json_object_get_string(attr));
attr = json_object_array_get_idx(obj, 1);
trigger_ptr->dest = atoi(json_object_get_string(attr));
attr = json_object_array_get_idx(obj, 2);
if (!strcmp("\\n", json_object_get_string(attr))) {
trigger_ptr->term = strdup("\n");
} else {
trigger_ptr->term = strdup(json_object_get_string(attr));
}
trigger_ptr->term_len = strlen(trigger_ptr->term);
trigger_ptr++;
}
}
// Delete the JSON object
json_object_put(parsed_json);
return pda;
}
void SanityCheck(char *automaton_path) {
state * pda = create_pda(automaton_path);
int count = 0, state;
Get_Dupes_Ret *getdupesret;
IdxMap_new * statemap;
IdxMap_new * statemap_ptr;
terminal * term_ptr;
while (count < NUMINPUTS) {
// Perform input generation
Array *generated = gen_input(pda, NULL);
print_repr(generated, "Gen");
count += 1;
}
}
int main(int argc, char *argv[]) {
char * mode;
char * automaton_path;
char * output_dir = NULL;
struct timeval tv;
struct timeval tz;
// gettimeofday(&tv, &tz);
srand(1337);
if (argc == 3) {
mode = argv[1];
automaton_path = strdup(argv[2]);
printf("\nMode:%s Path:%s", mode, automaton_path);
} else {
printf("\nUsage: ./test <mode> <automaton_path>");
return -1;
}
if (!strcmp(mode, "SanityCheck")) {
SanityCheck(automaton_path);
} else {
printf("\nUnrecognized mode");
return -1;
}
return 0;
}

View File

@ -1,57 +0,0 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <json-c/json.h>
#include <unistd.h>
#include "hashmap.h"
#include "uthash.h"
#include "utarray.h"
#define INIT_SIZE 100 // Initial size of the dynamic array holding the input
typedef struct terminal {
int state;
int trigger_idx;
size_t symbol_len;
char * symbol;
} terminal;
typedef struct trigger {
char * id;
int dest;
char * term;
size_t term_len;
} trigger;
typedef struct state {
int state_name; // Integer State name
int trigger_len; // Number of triggers associated with this state
trigger *ptr; // Pointer to beginning of the list of triggers
} state;
typedef struct {
size_t used;
size_t size;
size_t inputlen;
terminal *start;
} Array;
int init_state;
int curr_state;
int final_state;
state *create_pda(char *);
Array *gen_input(state *, Array *);
void print_repr(Array *, char *);
void initArray(Array *, size_t);
void insertArray(Array *, int, char *, size_t, int);

View File

@ -1,392 +0,0 @@
/*
Copyright (c) 2008-2018, Troy D. Hanson http://troydhanson.github.com/uthash/
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* a dynamic array implementation using macros
*/
#ifndef UTARRAY_H
#define UTARRAY_H
#define UTARRAY_VERSION 2.1.0
#include <stddef.h> /* size_t */
#include <string.h> /* memset, etc */
#include <stdlib.h> /* exit */
#ifdef __GNUC__
#define UTARRAY_UNUSED __attribute__((__unused__))
#else
#define UTARRAY_UNUSED
#endif
#ifdef oom
#error \
"The name of macro 'oom' has been changed to 'utarray_oom'. Please update your code."
#define utarray_oom() oom()
#endif
#ifndef utarray_oom
#define utarray_oom() exit(-1)
#endif
typedef void(ctor_f)(void *dst, const void *src);
typedef void(dtor_f)(void *elt);
typedef void(init_f)(void *elt);
typedef struct {
size_t sz;
init_f *init;
ctor_f *copy;
dtor_f *dtor;
} UT_icd;
typedef struct {
unsigned i, n; /* i: index of next available slot, n: num slots */
UT_icd icd; /* initializer, copy and destructor functions */
char * d; /* n slots of size icd->sz*/
} UT_array;
#define utarray_init(a, _icd) \
do { \
\
memset(a, 0, sizeof(UT_array)); \
(a)->icd = *(_icd); \
\
} while (0)
#define utarray_done(a) \
do { \
\
if ((a)->n) { \
\
if ((a)->icd.dtor) { \
\
unsigned _ut_i; \
for (_ut_i = 0; _ut_i < (a)->i; _ut_i++) { \
\
(a)->icd.dtor(utarray_eltptr(a, _ut_i)); \
\
} \
\
} \
free((a)->d); \
\
} \
(a)->n = 0; \
\
} while (0)
#define utarray_new(a, _icd) \
do { \
\
(a) = (UT_array *)malloc(sizeof(UT_array)); \
if ((a) == NULL) { utarray_oom(); } \
utarray_init(a, _icd); \
\
} while (0)
#define utarray_free(a) \
do { \
\
utarray_done(a); \
free(a); \
\
} while (0)
#define utarray_reserve(a, by) \
do { \
\
if (((a)->i + (by)) > (a)->n) { \
\
char *utarray_tmp; \
while (((a)->i + (by)) > (a)->n) { \
\
(a)->n = ((a)->n ? (2 * (a)->n) : 8); \
\
} \
utarray_tmp = (char *)realloc((a)->d, (a)->n * (a)->icd.sz); \
if (utarray_tmp == NULL) { utarray_oom(); } \
(a)->d = utarray_tmp; \
\
} \
\
} while (0)
#define utarray_push_back(a, p) \
do { \
\
utarray_reserve(a, 1); \
if ((a)->icd.copy) { \
\
(a)->icd.copy(_utarray_eltptr(a, (a)->i++), p); \
\
} else { \
\
memcpy(_utarray_eltptr(a, (a)->i++), p, (a)->icd.sz); \
\
}; \
\
} while (0)
#define utarray_pop_back(a) \
do { \
\
if ((a)->icd.dtor) { \
\
(a)->icd.dtor(_utarray_eltptr(a, --((a)->i))); \
\
} else { \
\
(a)->i--; \
\
} \
\
} while (0)
#define utarray_extend_back(a) \
do { \
\
utarray_reserve(a, 1); \
if ((a)->icd.init) { \
\
(a)->icd.init(_utarray_eltptr(a, (a)->i)); \
\
} else { \
\
memset(_utarray_eltptr(a, (a)->i), 0, (a)->icd.sz); \
\
} \
(a)->i++; \
\
} while (0)
#define utarray_len(a) ((a)->i)
#define utarray_eltptr(a, j) (((j) < (a)->i) ? _utarray_eltptr(a, j) : NULL)
#define _utarray_eltptr(a, j) ((a)->d + ((a)->icd.sz * (j)))
#define utarray_insert(a, p, j) \
do { \
\
if ((j) > (a)->i) utarray_resize(a, j); \
utarray_reserve(a, 1); \
if ((j) < (a)->i) { \
\
memmove(_utarray_eltptr(a, (j) + 1), _utarray_eltptr(a, j), \
((a)->i - (j)) * ((a)->icd.sz)); \
\
} \
if ((a)->icd.copy) { \
\
(a)->icd.copy(_utarray_eltptr(a, j), p); \
\
} else { \
\
memcpy(_utarray_eltptr(a, j), p, (a)->icd.sz); \
\
}; \
(a)->i++; \
\
} while (0)
#define utarray_inserta(a, w, j) \
do { \
\
if (utarray_len(w) == 0) break; \
if ((j) > (a)->i) utarray_resize(a, j); \
utarray_reserve(a, utarray_len(w)); \
if ((j) < (a)->i) { \
\
memmove(_utarray_eltptr(a, (j) + utarray_len(w)), _utarray_eltptr(a, j), \
((a)->i - (j)) * ((a)->icd.sz)); \
\
} \
if ((a)->icd.copy) { \
\
unsigned _ut_i; \
for (_ut_i = 0; _ut_i < (w)->i; _ut_i++) { \
\
(a)->icd.copy(_utarray_eltptr(a, (j) + _ut_i), \
_utarray_eltptr(w, _ut_i)); \
\
} \
\
} else { \
\
memcpy(_utarray_eltptr(a, j), _utarray_eltptr(w, 0), \
utarray_len(w) * ((a)->icd.sz)); \
\
} \
(a)->i += utarray_len(w); \
\
} while (0)
#define utarray_resize(dst, num) \
do { \
\
unsigned _ut_i; \
if ((dst)->i > (unsigned)(num)) { \
\
if ((dst)->icd.dtor) { \
\
for (_ut_i = (num); _ut_i < (dst)->i; ++_ut_i) { \
\
(dst)->icd.dtor(_utarray_eltptr(dst, _ut_i)); \
\
} \
\
} \
\
} else if ((dst)->i < (unsigned)(num)) { \
\
utarray_reserve(dst, (num) - (dst)->i); \
if ((dst)->icd.init) { \
\
for (_ut_i = (dst)->i; _ut_i < (unsigned)(num); ++_ut_i) { \
\
(dst)->icd.init(_utarray_eltptr(dst, _ut_i)); \
\
} \
\
} else { \
\
memset(_utarray_eltptr(dst, (dst)->i), 0, \
(dst)->icd.sz *((num) - (dst)->i)); \
\
} \
\
} \
(dst)->i = (num); \
\
} while (0)
#define utarray_concat(dst, src) \
do { \
\
utarray_inserta(dst, src, utarray_len(dst)); \
\
} while (0)
#define utarray_erase(a, pos, len) \
do { \
\
if ((a)->icd.dtor) { \
\
unsigned _ut_i; \
for (_ut_i = 0; _ut_i < (len); _ut_i++) { \
\
(a)->icd.dtor(utarray_eltptr(a, (pos) + _ut_i)); \
\
} \
\
} \
if ((a)->i > ((pos) + (len))) { \
\
memmove(_utarray_eltptr(a, pos), _utarray_eltptr(a, (pos) + (len)), \
((a)->i - ((pos) + (len))) * (a)->icd.sz); \
\
} \
(a)->i -= (len); \
\
} while (0)
#define utarray_renew(a, u) \
do { \
\
if (a) \
utarray_clear(a); \
else \
utarray_new(a, u); \
\
} while (0)
#define utarray_clear(a) \
do { \
\
if ((a)->i > 0) { \
\
if ((a)->icd.dtor) { \
\
unsigned _ut_i; \
for (_ut_i = 0; _ut_i < (a)->i; _ut_i++) { \
\
(a)->icd.dtor(_utarray_eltptr(a, _ut_i)); \
\
} \
\
} \
(a)->i = 0; \
\
} \
\
} while (0)
#define utarray_sort(a, cmp) \
do { \
\
qsort((a)->d, (a)->i, (a)->icd.sz, cmp); \
\
} while (0)
#define utarray_find(a, v, cmp) bsearch((v), (a)->d, (a)->i, (a)->icd.sz, cmp)
#define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a, 0)) : NULL)
#define utarray_next(a, e) \
(((e) == NULL) ? utarray_front(a) \
: (((a)->i != utarray_eltidx(a, e) + 1) \
? _utarray_eltptr(a, utarray_eltidx(a, e) + 1) \
: NULL))
#define utarray_prev(a, e) \
(((e) == NULL) ? utarray_back(a) \
: ((utarray_eltidx(a, e) != 0) \
? _utarray_eltptr(a, utarray_eltidx(a, e) - 1) \
: NULL))
#define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a, (a)->i - 1)) : NULL)
#define utarray_eltidx(a, e) (((char *)(e) - (a)->d) / (a)->icd.sz)
/* last we pre-define a few icd for common utarrays of ints and strings */
static void utarray_str_cpy(void *dst, const void *src) {
char **_src = (char **)src, **_dst = (char **)dst;
*_dst = (*_src == NULL) ? NULL : strdup(*_src);
}
static void utarray_str_dtor(void *elt) {
char **eltc = (char **)elt;
if (*eltc != NULL) free(*eltc);
}
static const UT_icd ut_str_icd UTARRAY_UNUSED = {
sizeof(char *), NULL, utarray_str_cpy, utarray_str_dtor};
static const UT_icd ut_int_icd UTARRAY_UNUSED = {sizeof(int), NULL, NULL, NULL};
static const UT_icd ut_ptr_icd UTARRAY_UNUSED = {sizeof(void *), NULL, NULL,
NULL};
#endif /* UTARRAY_H */

File diff suppressed because it is too large Load Diff

View File

@ -1 +0,0 @@
ff4e5a2

View File

@ -1,6 +0,0 @@
# Grammar-Mutator
This is just a stub directory that will clone the real grammar mutator
directory.
Execute `./build_grammar_mutator.sh` to set everything up.

View File

@ -1,141 +0,0 @@
#!/bin/sh
#
# american fuzzy lop++ - unicorn mode build script
# ------------------------------------------------
#
# Originally written by Nathan Voss <njvoss99@gmail.com>
#
# Adapted from code by Andrew Griffiths <agriffiths@google.com> and
# Michal Zalewski
#
# Adapted for AFLplusplus by Dominik Maier <mail@dmnk.co>
#
# CompareCoverage and NeverZero counters by Andrea Fioraldi
# <andreafioraldi@gmail.com>
#
# Copyright 2017 Battelle Memorial Institute. 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:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# This script downloads, patches, and builds a version of Unicorn with
# minor tweaks to allow Unicorn-emulated binaries to be run under
# afl-fuzz.
#
# The modifications reside in patches/*. The standalone Unicorn library
# will be written to /usr/lib/libunicornafl.so, and the Python bindings
# will be installed system-wide.
#
# You must make sure that Unicorn Engine is not already installed before
# running this script. If it is, please uninstall it first.
GRAMMAR_VERSION="$(cat ./GRAMMAR_VERSION)"
GRAMMAR_REPO="https://github.com/AFLplusplus/grammar-mutator"
echo "================================================="
echo "Grammar Mutator build script"
echo "================================================="
echo
echo "[*] Performing basic sanity checks..."
PLT=`uname -s`
if [ ! -f "../../config.h" ]; then
echo "[-] Error: key files not found - wrong working directory?"
exit 1
fi
PYTHONBIN=`command -v python3 || command -v python || command -v python2 || echo python3`
MAKECMD=make
TARCMD=tar
if [ "$PLT" = "Darwin" ]; then
CORES=`sysctl -n hw.ncpu`
TARCMD=tar
fi
if [ "$PLT" = "FreeBSD" ]; then
MAKECMD=gmake
CORES=`sysctl -n hw.ncpu`
TARCMD=gtar
fi
if [ "$PLT" = "NetBSD" ] || [ "$PLT" = "OpenBSD" ]; then
MAKECMD=gmake
CORES=`sysctl -n hw.ncpu`
TARCMD=gtar
fi
PREREQ_NOTFOUND=
for i in git $MAKECMD $TARCMD; do
T=`command -v "$i" 2>/dev/null`
if [ "$T" = "" ]; then
echo "[-] Error: '$i' not found. Run 'sudo apt-get install $i' or similar."
PREREQ_NOTFOUND=1
fi
done
if echo "$CC" | grep -qF /afl-; then
echo "[-] Error: do not use afl-gcc or afl-clang to compile this tool."
PREREQ_NOTFOUND=1
fi
if [ "$PREREQ_NOTFOUND" = "1" ]; then
exit 1
fi
echo "[+] All checks passed!"
echo "[*] Making sure grammar mutator is checked out"
git status 1>/dev/null 2>/dev/null
if [ $? -eq 0 ]; then
echo "[*] initializing grammar mutator submodule"
git submodule init || exit 1
git submodule update ./grammar_mutator 2>/dev/null # ignore errors
else
echo "[*] cloning grammar mutator"
test -d grammar_mutator/.git || {
CNT=1
while [ '!' -d grammar_mutator/.git -a "$CNT" -lt 4 ]; do
echo "Trying to clone grammar_mutator (attempt $CNT/3)"
git clone "$GRAMMAR_REPO"
CNT=`expr "$CNT" + 1`
done
}
fi
test -e grammar_mutator/.git || { echo "[-] not checked out, please install git or check your internet connection." ; exit 1 ; }
echo "[+] Got grammar mutator."
cd "grammar_mutator" || exit 1
echo "[*] Checking out $GRAMMAR_VERSION"
git pull >/dev/null 2>&1
sh -c 'git stash && git stash drop' 1>/dev/null 2>/dev/null
git checkout "$GRAMMAR_VERSION" || exit 1
echo "[*] Downloading antlr..."
wget -q https://www.antlr.org/download/antlr-4.8-complete.jar
cd ..
echo
echo
echo "[+] All successfully prepared!"
echo "[!] To build for your grammar just do:"
echo " cd grammar_mutator"
echo " make GRAMMAR_FILE=/path/to/your/grammar"
echo "[+] You will find a JSON and RUBY grammar in grammar_mutator/grammars to play with."
echo

View File

@ -1,50 +0,0 @@
#!/bin/sh
##################################################
# AFL++ tool to update a git ref.
# Usage: ./<script>.sh <new commit hash>
# If no commit hash was provided, it'll take HEAD.
##################################################
TOOL="grammar mutator"
VERSION_FILE='./GRAMMAR_VERSION'
REPO_FOLDER='./grammar_mutator'
THIS_SCRIPT=`basename $0`
BRANCH="stable"
NEW_VERSION="$1"
if [ "$NEW_VERSION" = "-h" ]; then
echo "Internal script to update bound $TOOL version."
echo
echo "Usage: $THIS_SCRIPT <new commit hash>"
echo "If no commit hash is provided, will use HEAD."
echo "-h to show this help screen."
exit 1
fi
git submodule init && git submodule update ./grammar_mutator || exit 1
cd "$REPO_FOLDER" || exit 1
git fetch origin $BRANCH 1>/dev/null || exit 1
git stash 1>/dev/null 2>/dev/null
git stash drop 1>/dev/null 2>/dev/null
git checkout $BRANCH
if [ -z "$NEW_VERSION" ]; then
# No version provided, take HEAD.
NEW_VERSION=$(git rev-parse --short HEAD)
fi
if [ -z "$NEW_VERSION" ]; then
echo "Error getting version."
exit 1
fi
git checkout "$NEW_VERSION" || exit 1
cd ..
rm "$VERSION_FILE"
echo "$NEW_VERSION" > "$VERSION_FILE"
echo "Done. New $TOOL version is $NEW_VERSION."

View File

@ -1,17 +0,0 @@
CFLAGS = -O3 -funroll-loops -fPIC -Wl,-Bsymbolic
all: honggfuzz-mutator.so
honggfuzz-mutator.so: honggfuzz.c input.h mangle.c ../../src/afl-performance.c
$(CC) $(CFLAGS) -I../../include -I. -shared -o honggfuzz-mutator.so honggfuzz.c mangle.c ../../src/afl-performance.c
update:
@# seriously? --unlink is a dud option? sigh ...
rm -f mangle.c mangle.h honggfuzz.h
wget --unlink https://github.com/google/honggfuzz/raw/master/mangle.c
wget --unlink https://github.com/google/honggfuzz/raw/master/mangle.h
wget --unlink https://github.com/google/honggfuzz/raw/master/honggfuzz.h
clean:
rm -f *.o *~ *.so core

View File

@ -1,12 +0,0 @@
# custum mutator: honggfuzz mangle
this is the honggfuzz mutator in mangle.c as a custom mutator
module for AFL++. It is the original mangle.c, mangle.h and honggfuzz.h
with a lot of mocking around it :-)
just type `make` to build
```AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/honggfuzz/honggfuzz-mutator.so afl-fuzz ...```
> Original repository: https://github.com/google/honggfuzz
> Source commit: d0fbcb0373c32436b8fb922e6937da93b17291f5

View File

@ -1,22 +0,0 @@
#ifndef CUSTOM_MUTATOR_HELPERS
#define CUSTOM_MUTATOR_HELPERS
#include "config.h"
#include "types.h"
#include "afl-fuzz.h"
#include <stdlib.h>
#define INITIAL_GROWTH_SIZE (64)
/* Use in a struct: creates a name_buf and a name_size variable. */
#define BUF_VAR(type, name) \
type * name##_buf; \
size_t name##_size;
/* this filles in `&structptr->something_buf, &structptr->something_size`. */
#define BUF_PARAMS(struct, name) \
(void **)&struct->name##_buf, &struct->name##_size
#undef INITIAL_GROWTH_SIZE
#endif

View File

@ -1,146 +0,0 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "custom_mutator_helpers.h"
#include "mangle.h"
#define NUMBER_OF_MUTATIONS 5
uint8_t * queue_input;
size_t queue_input_size;
afl_state_t * afl_struct;
run_t run;
honggfuzz_t global;
struct _dynfile_t dynfile;
typedef struct my_mutator {
afl_state_t *afl;
run_t * run;
u8 * mutator_buf;
unsigned int seed;
unsigned int extras_cnt, a_extras_cnt;
} my_mutator_t;
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
if (!data) {
perror("afl_custom_init alloc");
return NULL;
}
if ((data->mutator_buf = malloc(MAX_FILE)) == NULL) {
free(data);
perror("mutator_buf alloc");
return NULL;
}
run.dynfile = &dynfile;
run.global = &global;
data->afl = afl;
data->seed = seed;
data->run = &run;
afl_struct = afl;
run.global->mutate.maxInputSz = MAX_FILE;
run.global->mutate.mutationsPerRun = NUMBER_OF_MUTATIONS;
run.mutationsPerRun = NUMBER_OF_MUTATIONS;
run.global->timing.lastCovUpdate = 6;
// global->feedback.cmpFeedback
// global->feedback.cmpFeedbackMap
return data;
}
/* When a new queue entry is added we check if there are new dictionary
entries to add to honggfuzz structure */
uint8_t afl_custom_queue_new_entry(my_mutator_t * data,
const uint8_t *filename_new_queue,
const uint8_t *filename_orig_queue) {
if (run.global->mutate.dictionaryCnt >= 1024) return;
while (data->extras_cnt < data->afl->extras_cnt &&
run.global->mutate.dictionaryCnt < 1024) {
memcpy(run.global->mutate.dictionary[run.global->mutate.dictionaryCnt].val,
data->afl->extras[data->extras_cnt].data,
data->afl->extras[data->extras_cnt].len);
run.global->mutate.dictionary[run.global->mutate.dictionaryCnt].len =
data->afl->extras[data->extras_cnt].len;
run.global->mutate.dictionaryCnt++;
data->extras_cnt++;
}
while (data->a_extras_cnt < data->afl->a_extras_cnt &&
run.global->mutate.dictionaryCnt < 1024) {
memcpy(run.global->mutate.dictionary[run.global->mutate.dictionaryCnt].val,
data->afl->a_extras[data->a_extras_cnt].data,
data->afl->a_extras[data->a_extras_cnt].len);
run.global->mutate.dictionary[run.global->mutate.dictionaryCnt].len =
data->afl->a_extras[data->a_extras_cnt].len;
run.global->mutate.dictionaryCnt++;
data->a_extras_cnt++;
}
return 0;
}
/* we could set only_printable if is_ascii is set ... let's see
uint8_t afl_custom_queue_get(void *data, const uint8_t *filename) {
//run.global->cfg.only_printable = ...
}
*/
/* here we run the honggfuzz mutator, which is really good */
size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
u8 **out_buf, uint8_t *add_buf, size_t add_buf_size,
size_t max_size) {
/* set everything up, costly ... :( */
memcpy(data->mutator_buf, buf, buf_size);
queue_input = data->mutator_buf;
run.dynfile->data = data->mutator_buf;
queue_input_size = buf_size;
run.dynfile->size = buf_size;
*out_buf = data->mutator_buf;
/* the mutation */
mangle_mangleContent(&run, NUMBER_OF_MUTATIONS);
/* return size of mutated data */
return run.dynfile->size;
}
/**
* Deinitialize everything
*
* @param data The data ptr from afl_custom_init
*/
void afl_custom_deinit(my_mutator_t *data) {
free(data->mutator_buf);
free(data);
}

View File

@ -1,387 +0,0 @@
/*
*
* honggfuzz - core structures and macros
* -----------------------------------------
*
* Author: Robert Swiecki <swiecki@google.com>
*
* Copyright 2010-2018 by Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
*/
#ifndef _HF_HONGGFUZZ_H_
#define _HF_HONGGFUZZ_H_
#include <dirent.h>
#include <inttypes.h>
#include <limits.h>
#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/types.h>
#include <time.h>
#include "libhfcommon/util.h"
#define PROG_NAME "honggfuzz"
#define PROG_VERSION "2.4"
/* Name of the template which will be replaced with the proper name of the file */
#define _HF_FILE_PLACEHOLDER "___FILE___"
/* Default name of the report created with some architectures */
#define _HF_REPORT_FILE "HONGGFUZZ.REPORT.TXT"
/* Default stack-size of created threads. */
#define _HF_PTHREAD_STACKSIZE (1024ULL * 1024ULL * 2ULL) /* 2MB */
/* Name of envvar which indicates sequential number of fuzzer */
#define _HF_THREAD_NO_ENV "HFUZZ_THREAD_NO"
/* Name of envvar which indicates that the netDriver should be used */
#define _HF_THREAD_NETDRIVER_ENV "HFUZZ_USE_NETDRIVER"
/* Name of envvar which indicates honggfuzz's log level in use */
#define _HF_LOG_LEVEL_ENV "HFUZZ_LOG_LEVEL"
/* Number of crash verifier iterations before tag crash as stable */
#define _HF_VERIFIER_ITER 5
/* Size (in bytes) for report data to be stored in stack before written to file */
#define _HF_REPORT_SIZE 32768
/* Perf bitmap size */
#define _HF_PERF_BITMAP_SIZE_16M (1024U * 1024U * 16U)
#define _HF_PERF_BITMAP_BITSZ_MASK 0x7FFFFFFULL
/* Maximum number of PC guards (=trace-pc-guard) we support */
#define _HF_PC_GUARD_MAX (1024ULL * 1024ULL * 64ULL)
/* Maximum size of the input file in bytes (1 MiB) */
#define _HF_INPUT_MAX_SIZE (1024ULL * 1024ULL)
/* Default maximum size of produced inputs */
#define _HF_INPUT_DEFAULT_SIZE (1024ULL * 8)
/* Per-thread bitmap */
#define _HF_PERTHREAD_BITMAP_FD 1018
/* FD used to report back used int/str constants from the fuzzed process */
#define _HF_CMP_BITMAP_FD 1019
/* FD used to log inside the child process */
#define _HF_LOG_FD 1020
/* FD used to represent the input file */
#define _HF_INPUT_FD 1021
/* FD used to pass coverage feedback from the fuzzed process */
#define _HF_COV_BITMAP_FD 1022
#define _HF_BITMAP_FD _HF_COV_BITMAP_FD /* Old name for _HF_COV_BITMAP_FD */
/* FD used to pass data to a persistent process */
#define _HF_PERSISTENT_FD 1023
/* Input file as a string */
#define _HF_INPUT_FILE_PATH "/dev/fd/" HF_XSTR(_HF_INPUT_FD)
/* Maximum number of supported execve() args */
#define _HF_ARGS_MAX 2048
/* Message indicating that the fuzzed process is ready for new data */
static const uint8_t HFReadyTag = 'R';
/* Maximum number of active fuzzing threads */
#define _HF_THREAD_MAX 1024U
/* Persistent-binary signature - if found within file, it means it's a persistent mode binary */
#define _HF_PERSISTENT_SIG "\x01_LIBHFUZZ_PERSISTENT_BINARY_SIGNATURE_\x02\xFF"
/* HF NetDriver signature - if found within file, it means it's a NetDriver-based binary */
#define _HF_NETDRIVER_SIG "\x01_LIBHFUZZ_NETDRIVER_BINARY_SIGNATURE_\x02\xFF"
/* printf() nonmonetary separator. According to MacOSX's man it's supported there as well */
#define _HF_NONMON_SEP "'"
typedef enum {
_HF_DYNFILE_NONE = 0x0,
_HF_DYNFILE_INSTR_COUNT = 0x1,
_HF_DYNFILE_BRANCH_COUNT = 0x2,
_HF_DYNFILE_BTS_EDGE = 0x10,
_HF_DYNFILE_IPT_BLOCK = 0x20,
_HF_DYNFILE_SOFT = 0x40,
} dynFileMethod_t;
typedef struct {
uint64_t cpuInstrCnt;
uint64_t cpuBranchCnt;
uint64_t bbCnt;
uint64_t newBBCnt;
uint64_t softCntPc;
uint64_t softCntEdge;
uint64_t softCntCmp;
} hwcnt_t;
typedef enum {
_HF_STATE_UNSET = 0,
_HF_STATE_STATIC,
_HF_STATE_DYNAMIC_DRY_RUN,
_HF_STATE_DYNAMIC_MAIN,
_HF_STATE_DYNAMIC_MINIMIZE,
} fuzzState_t;
typedef enum {
HF_MAYBE = -1,
HF_NO = 0,
HF_YES = 1,
} tristate_t;
struct _dynfile_t {
size_t size;
uint64_t cov[4];
size_t idx;
int fd;
uint64_t timeExecUSecs;
char path[PATH_MAX];
struct _dynfile_t* src;
uint32_t refs;
uint8_t* data;
TAILQ_ENTRY(_dynfile_t) pointers;
};
typedef struct _dynfile_t dynfile_t;
struct strings_t {
size_t len;
TAILQ_ENTRY(strings_t) pointers;
char s[];
};
typedef struct {
uint8_t pcGuardMap[_HF_PC_GUARD_MAX];
uint8_t bbMapPc[_HF_PERF_BITMAP_SIZE_16M];
uint32_t bbMapCmp[_HF_PERF_BITMAP_SIZE_16M];
uint64_t pidNewPC[_HF_THREAD_MAX];
uint64_t pidNewEdge[_HF_THREAD_MAX];
uint64_t pidNewCmp[_HF_THREAD_MAX];
uint64_t guardNb;
uint64_t pidTotalPC[_HF_THREAD_MAX];
uint64_t pidTotalEdge[_HF_THREAD_MAX];
uint64_t pidTotalCmp[_HF_THREAD_MAX];
} feedback_t;
typedef struct {
uint32_t cnt;
struct {
uint8_t val[32];
uint32_t len;
} valArr[1024 * 16];
} cmpfeedback_t;
typedef struct {
struct {
size_t threadsMax;
size_t threadsFinished;
uint32_t threadsActiveCnt;
pthread_t mainThread;
pid_t mainPid;
pthread_t threads[_HF_THREAD_MAX];
} threads;
struct {
const char* inputDir;
const char* outputDir;
DIR* inputDirPtr;
size_t fileCnt;
size_t testedFileCnt;
const char* fileExtn;
size_t maxFileSz;
size_t newUnitsAdded;
char workDir[PATH_MAX];
const char* crashDir;
const char* covDirNew;
bool saveUnique;
bool saveSmaller;
size_t dynfileqMaxSz;
size_t dynfileqCnt;
dynfile_t* dynfileqCurrent;
dynfile_t* dynfileq2Current;
TAILQ_HEAD(dyns_t, _dynfile_t) dynfileq;
bool exportFeedback;
} io;
struct {
int argc;
const char* const* cmdline;
bool nullifyStdio;
bool fuzzStdin;
const char* externalCommand;
const char* postExternalCommand;
const char* feedbackMutateCommand;
bool netDriver;
bool persistent;
uint64_t asLimit;
uint64_t rssLimit;
uint64_t dataLimit;
uint64_t coreLimit;
uint64_t stackLimit;
bool clearEnv;
char* env_ptrs[128];
char env_vals[128][4096];
sigset_t waitSigSet;
} exe;
struct {
time_t timeStart;
time_t runEndTime;
time_t tmOut;
time_t lastCovUpdate;
int64_t timeOfLongestUnitUSecs;
bool tmoutVTALRM;
} timing;
struct {
struct {
uint8_t val[512];
size_t len;
} dictionary[8192];
size_t dictionaryCnt;
const char* dictionaryFile;
size_t mutationsMax;
unsigned mutationsPerRun;
size_t maxInputSz;
} mutate;
struct {
bool useScreen;
char cmdline_txt[65];
int64_t lastDisplayUSecs;
} display;
struct {
bool useVerifier;
bool exitUponCrash;
uint8_t exitCodeUponCrash;
const char* reportFile;
size_t dynFileIterExpire;
bool only_printable;
bool minimize;
bool switchingToFDM;
} cfg;
struct {
bool enable;
bool del_report;
} sanitizer;
struct {
fuzzState_t state;
feedback_t* covFeedbackMap;
int covFeedbackFd;
cmpfeedback_t* cmpFeedbackMap;
int cmpFeedbackFd;
bool cmpFeedback;
const char* blocklistFile;
uint64_t* blocklist;
size_t blocklistCnt;
bool skipFeedbackOnTimeout;
uint64_t maxCov[4];
dynFileMethod_t dynFileMethod;
hwcnt_t hwCnts;
} feedback;
struct {
size_t mutationsCnt;
size_t crashesCnt;
size_t uniqueCrashesCnt;
size_t verifiedCrashesCnt;
size_t blCrashesCnt;
size_t timeoutedCnt;
} cnts;
struct {
bool enabled;
int serverSocket;
int clientSocket;
} socketFuzzer;
struct {
pthread_rwlock_t dynfileq;
pthread_mutex_t feedback;
pthread_mutex_t report;
pthread_mutex_t state;
pthread_mutex_t input;
pthread_mutex_t timing;
} mutex;
/* For the Linux code */
struct {
int exeFd;
uint64_t dynamicCutOffAddr;
bool disableRandomization;
void* ignoreAddr;
const char* symsBlFile;
char** symsBl;
size_t symsBlCnt;
const char* symsWlFile;
char** symsWl;
size_t symsWlCnt;
uintptr_t cloneFlags;
tristate_t useNetNs;
bool kernelOnly;
bool useClone;
} arch_linux;
/* For the NetBSD code */
struct {
void* ignoreAddr;
const char* symsBlFile;
char** symsBl;
size_t symsBlCnt;
const char* symsWlFile;
char** symsWl;
size_t symsWlCnt;
} arch_netbsd;
} honggfuzz_t;
typedef enum {
_HF_RS_UNKNOWN = 0,
_HF_RS_WAITING_FOR_INITIAL_READY = 1,
_HF_RS_WAITING_FOR_READY = 2,
_HF_RS_SEND_DATA = 3,
} runState_t;
typedef struct {
honggfuzz_t* global;
pid_t pid;
int64_t timeStartedUSecs;
char crashFileName[PATH_MAX];
uint64_t pc;
uint64_t backtrace;
uint64_t access;
int exception;
char report[_HF_REPORT_SIZE];
bool mainWorker;
unsigned mutationsPerRun;
dynfile_t* dynfile;
bool staticFileTryMore;
uint32_t fuzzNo;
int persistentSock;
runState_t runState;
bool tmOutSignaled;
char* args[_HF_ARGS_MAX + 1];
int perThreadCovFeedbackFd;
unsigned triesLeft;
dynfile_t* current;
#if !defined(_HF_ARCH_DARWIN)
timer_t timerId;
#endif // !defined(_HF_ARCH_DARWIN)
hwcnt_t hwCnts;
struct {
/* For Linux code */
uint8_t* perfMmapBuf;
uint8_t* perfMmapAux;
int cpuInstrFd;
int cpuBranchFd;
int cpuIptBtsFd;
} arch_linux;
} run_t;
#endif

View File

@ -1,106 +0,0 @@
#ifndef _HG_INPUT_
#define _HG_INPUT_
#include <stdarg.h>
#ifdef __clang__
#include <stdatomic.h>
#endif
#include <stdbool.h>
#include <stdint.h>
#include <time.h>
#include "honggfuzz.h"
#include "afl-fuzz.h"
/*
* Go-style defer scoped implementation
*
* If compiled with clang, use: -fblocks -lBlocksRuntime
*
* Example of use:
*
* {
* int fd = open(fname, O_RDONLY);
* if (fd == -1) {
* error(....);
* return;
* }
* defer { close(fd); };
* ssize_t sz = read(fd, buf, sizeof(buf));
* ...
* ...
* }
*
*/
#define __STRMERGE(a, b) a##b
#define _STRMERGE(a, b) __STRMERGE(a, b)
#ifdef __clang__
#if __has_extension(blocks)
static void __attribute__((unused)) __clang_cleanup_func(void (^*dfunc)(void)) {
(*dfunc)();
}
#define defer \
void (^_STRMERGE(__defer_f_, __COUNTER__))(void) \
__attribute__((cleanup(__clang_cleanup_func))) __attribute__((unused)) = ^
#else /* __has_extension(blocks) */
#define defer UNIMPLEMENTED - NO - SUPPORT - FOR - BLOCKS - IN - YOUR - CLANG - ENABLED
#endif /* __has_extension(blocks) */
#else /* !__clang__, e.g.: gcc */
#define __block
#define _DEFER(a, count) \
auto void _STRMERGE(__defer_f_, count)(void* _defer_arg __attribute__((unused))); \
int _STRMERGE(__defer_var_, count) __attribute__((cleanup(_STRMERGE(__defer_f_, count)))) \
__attribute__((unused)); \
void _STRMERGE(__defer_f_, count)(void* _defer_arg __attribute__((unused)))
#define defer _DEFER(a, __COUNTER__)
#endif /* ifdef __clang__ */
#define HF_MIN(x, y) (x <= y ? x : y)
#define HF_MAX(x, y) (x >= y ? x : y)
#define ATOMIC_GET
#define ARRAYSIZE(x) (sizeof(x) / sizeof(*x))
#define HF_ATTR_UNUSED __attribute__((unused))
#define util_Malloc(x) malloc(x)
extern uint8_t * queue_input;
extern size_t queue_input_size;
extern afl_state_t * afl_struct;
inline void wmb() { }
inline void LOG_F(const char *format, ...) { }
static inline uint64_t util_rndGet(uint64_t min, uint64_t max) {
return min + rand_below(afl_struct, max - min + 1);
}
static inline uint64_t util_rnd64() { return rand_below(afl_struct, 1 << 30); }
static inline const uint8_t* input_getRandomInputAsBuf(run_t* run, size_t* len) {
*len = queue_input_size;
run->dynfile->data = queue_input;
run->dynfile->size = queue_input_size;
return queue_input;
}
static inline void input_setSize(run_t* run, size_t sz) {
run->dynfile->size = sz;
}
static inline void util_turnToPrintable(uint8_t* buf, size_t sz) {
for (size_t i = 0; i < sz; i++)
buf[i] = buf[i] % 95 + 32;
}
static inline void util_rndBuf(uint8_t* buf, size_t sz) {
if (sz == 0) return;
for (size_t i = 0; i < sz; i++)
buf[i] = (uint8_t)rand_below(afl_struct, 256);
}
static inline uint8_t util_rndPrintable() {
return 32 + rand_below(afl_struct, 127 - 32);
}
static inline void util_rndBufPrintable(uint8_t* buf, size_t sz) {
for (size_t i = 0; i < sz; i++)
buf[i] = util_rndPrintable();
}
#endif

View File

@ -1,3 +0,0 @@
#ifndef LOG_E
#define LOG_E LOG_F
#endif

View File

@ -1 +0,0 @@
common.h

View File

@ -1 +0,0 @@
common.h

View File

@ -1,907 +0,0 @@
/*
*
* honggfuzz - run->dynfile->datafer mangling routines
* -----------------------------------------
*
* Author:
* Robert Swiecki <swiecki@google.com>
*
* Copyright 2010-2018 by Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
*/
#include "mangle.h"
#include <ctype.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include "input.h"
#include "libhfcommon/common.h"
#include "libhfcommon/log.h"
#include "libhfcommon/util.h"
static inline size_t mangle_LenLeft(run_t* run, size_t off) {
if (off >= run->dynfile->size) {
LOG_F("Offset is too large: off:%zu >= len:%zu", off, run->dynfile->size);
}
return (run->dynfile->size - off - 1);
}
/*
* Get a random value <1:max>, but prefer smaller ones
* Based on an idea by https://twitter.com/gamozolabs
*/
static inline size_t mangle_getLen(size_t max) {
if (max > _HF_INPUT_MAX_SIZE) {
LOG_F("max (%zu) > _HF_INPUT_MAX_SIZE (%zu)", max, (size_t)_HF_INPUT_MAX_SIZE);
}
if (max == 0) {
LOG_F("max == 0");
}
if (max == 1) {
return 1;
}
/* Give 50% chance the the uniform distribution */
if (util_rnd64() & 1) {
return (size_t)util_rndGet(1, max);
}
/* effectively exprand() */
return (size_t)util_rndGet(1, util_rndGet(1, max));
}
/* Prefer smaller values here, so use mangle_getLen() */
static inline size_t mangle_getOffSet(run_t* run) {
return mangle_getLen(run->dynfile->size) - 1;
}
/* Offset which can be equal to the file size */
static inline size_t mangle_getOffSetPlus1(run_t* run) {
size_t reqlen = HF_MIN(run->dynfile->size + 1, _HF_INPUT_MAX_SIZE);
return mangle_getLen(reqlen) - 1;
}
static inline void mangle_Move(run_t* run, size_t off_from, size_t off_to, size_t len) {
if (off_from >= run->dynfile->size) {
return;
}
if (off_to >= run->dynfile->size) {
return;
}
if (off_from == off_to) {
return;
}
size_t len_from = run->dynfile->size - off_from;
len = HF_MIN(len, len_from);
size_t len_to = run->dynfile->size - off_to;
len = HF_MIN(len, len_to);
memmove(&run->dynfile->data[off_to], &run->dynfile->data[off_from], len);
}
static inline void mangle_Overwrite(
run_t* run, size_t off, const uint8_t* src, size_t len, bool printable) {
if (len == 0) {
return;
}
size_t maxToCopy = run->dynfile->size - off;
if (len > maxToCopy) {
len = maxToCopy;
}
memmove(&run->dynfile->data[off], src, len);
if (printable) {
util_turnToPrintable(&run->dynfile->data[off], len);
}
}
static inline size_t mangle_Inflate(run_t* run, size_t off, size_t len, bool printable) {
if (run->dynfile->size >= run->global->mutate.maxInputSz) {
return 0;
}
if (len > (run->global->mutate.maxInputSz - run->dynfile->size)) {
len = run->global->mutate.maxInputSz - run->dynfile->size;
}
input_setSize(run, run->dynfile->size + len);
mangle_Move(run, off, off + len, run->dynfile->size);
if (printable) {
memset(&run->dynfile->data[off], ' ', len);
}
return len;
}
static inline void mangle_Insert(
run_t* run, size_t off, const uint8_t* val, size_t len, bool printable) {
len = mangle_Inflate(run, off, len, printable);
mangle_Overwrite(run, off, val, len, printable);
}
static inline void mangle_UseValue(run_t* run, const uint8_t* val, size_t len, bool printable) {
if (util_rnd64() & 1) {
mangle_Overwrite(run, mangle_getOffSet(run), val, len, printable);
} else {
mangle_Insert(run, mangle_getOffSetPlus1(run), val, len, printable);
}
}
static inline void mangle_UseValueAt(
run_t* run, size_t off, const uint8_t* val, size_t len, bool printable) {
if (util_rnd64() & 1) {
mangle_Overwrite(run, off, val, len, printable);
} else {
mangle_Insert(run, off, val, len, printable);
}
}
static void mangle_MemSwap(run_t* run, bool printable HF_ATTR_UNUSED) {
/* No big deal if those two are overlapping */
size_t off1 = mangle_getOffSet(run);
size_t maxlen1 = run->dynfile->size - off1;
size_t off2 = mangle_getOffSet(run);
size_t maxlen2 = run->dynfile->size - off2;
size_t len = mangle_getLen(HF_MIN(maxlen1, maxlen2));
if (off1 == off2) {
return;
}
for (size_t i = 0; i < (len / 2); i++) {
/*
* First - from the head, next from the tail. Don't worry about layout of the overlapping
* part - there's no good solution to that, and it can be left somewhat scrambled,
* while still preserving the entropy
*/
const uint8_t tmp1 = run->dynfile->data[off2 + i];
run->dynfile->data[off2 + i] = run->dynfile->data[off1 + i];
run->dynfile->data[off1 + i] = tmp1;
const uint8_t tmp2 = run->dynfile->data[off2 + (len - 1) - i];
run->dynfile->data[off2 + (len - 1) - i] = run->dynfile->data[off1 + (len - 1) - i];
run->dynfile->data[off1 + (len - 1) - i] = tmp2;
}
}
static void mangle_MemCopy(run_t* run, bool printable HF_ATTR_UNUSED) {
size_t off = mangle_getOffSet(run);
size_t len = mangle_getLen(run->dynfile->size - off);
/* Use a temp buf, as Insert/Inflate can change source bytes */
uint8_t* tmpbuf = (uint8_t*)util_Malloc(len);
defer {
free(tmpbuf);
};
memmove(tmpbuf, &run->dynfile->data[off], len);
mangle_UseValue(run, tmpbuf, len, printable);
}
static void mangle_Bytes(run_t* run, bool printable) {
uint16_t buf;
if (printable) {
util_rndBufPrintable((uint8_t*)&buf, sizeof(buf));
} else {
buf = util_rnd64();
}
/* Overwrite with random 1-2-byte values */
size_t toCopy = util_rndGet(1, 2);
mangle_UseValue(run, (const uint8_t*)&buf, toCopy, printable);
}
static void mangle_ByteRepeat(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
size_t destOff = off + 1;
size_t maxSz = run->dynfile->size - destOff;
/* No space to repeat */
if (!maxSz) {
mangle_Bytes(run, printable);
return;
}
size_t len = mangle_getLen(maxSz);
if (util_rnd64() & 0x1) {
len = mangle_Inflate(run, destOff, len, printable);
}
memset(&run->dynfile->data[destOff], run->dynfile->data[off], len);
}
static void mangle_Bit(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
run->dynfile->data[off] ^= (uint8_t)(1U << util_rndGet(0, 7));
if (printable) {
util_turnToPrintable(&(run->dynfile->data[off]), 1);
}
}
static const struct {
const uint8_t val[8];
const size_t size;
} mangleMagicVals[] = {
/* 1B - No endianness */
{"\x00\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x01\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x02\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x03\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x04\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x05\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x06\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x07\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x08\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x09\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x0A\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x0B\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x0C\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x0D\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x0E\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x0F\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x10\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x20\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x40\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x7E\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x7F\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x80\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x81\x00\x00\x00\x00\x00\x00\x00", 1},
{"\xC0\x00\x00\x00\x00\x00\x00\x00", 1},
{"\xFE\x00\x00\x00\x00\x00\x00\x00", 1},
{"\xFF\x00\x00\x00\x00\x00\x00\x00", 1},
/* 2B - NE */
{"\x00\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x01\x01\x00\x00\x00\x00\x00\x00", 2},
{"\x80\x80\x00\x00\x00\x00\x00\x00", 2},
{"\xFF\xFF\x00\x00\x00\x00\x00\x00", 2},
/* 2B - BE */
{"\x00\x01\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x02\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x03\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x04\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x05\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x06\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x07\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x08\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x09\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x0A\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x0B\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x0C\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x0D\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x0E\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x0F\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x10\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x20\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x40\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x7E\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x7F\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x80\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x81\x00\x00\x00\x00\x00\x00", 2},
{"\x00\xC0\x00\x00\x00\x00\x00\x00", 2},
{"\x00\xFE\x00\x00\x00\x00\x00\x00", 2},
{"\x00\xFF\x00\x00\x00\x00\x00\x00", 2},
{"\x7E\xFF\x00\x00\x00\x00\x00\x00", 2},
{"\x7F\xFF\x00\x00\x00\x00\x00\x00", 2},
{"\x80\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x80\x01\x00\x00\x00\x00\x00\x00", 2},
{"\xFF\xFE\x00\x00\x00\x00\x00\x00", 2},
/* 2B - LE */
{"\x00\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x01\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x02\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x03\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x04\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x05\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x06\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x07\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x08\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x09\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x0A\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x0B\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x0C\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x0D\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x0E\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x0F\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x10\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x20\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x40\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x7E\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x7F\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x80\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x81\x00\x00\x00\x00\x00\x00\x00", 2},
{"\xC0\x00\x00\x00\x00\x00\x00\x00", 2},
{"\xFE\x00\x00\x00\x00\x00\x00\x00", 2},
{"\xFF\x00\x00\x00\x00\x00\x00\x00", 2},
{"\xFF\x7E\x00\x00\x00\x00\x00\x00", 2},
{"\xFF\x7F\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x80\x00\x00\x00\x00\x00\x00", 2},
{"\x01\x80\x00\x00\x00\x00\x00\x00", 2},
{"\xFE\xFF\x00\x00\x00\x00\x00\x00", 2},
/* 4B - NE */
{"\x00\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x01\x01\x01\x01\x00\x00\x00\x00", 4},
{"\x80\x80\x80\x80\x00\x00\x00\x00", 4},
{"\xFF\xFF\xFF\xFF\x00\x00\x00\x00", 4},
/* 4B - BE */
{"\x00\x00\x00\x01\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x02\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x03\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x04\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x05\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x06\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x07\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x08\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x09\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x0A\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x0B\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x0C\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x0D\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x0E\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x0F\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x10\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x20\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x40\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x7E\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x7F\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x80\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x81\x00\x00\x00\x00", 4},
{"\x00\x00\x00\xC0\x00\x00\x00\x00", 4},
{"\x00\x00\x00\xFE\x00\x00\x00\x00", 4},
{"\x00\x00\x00\xFF\x00\x00\x00\x00", 4},
{"\x7E\xFF\xFF\xFF\x00\x00\x00\x00", 4},
{"\x7F\xFF\xFF\xFF\x00\x00\x00\x00", 4},
{"\x80\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x80\x00\x00\x01\x00\x00\x00\x00", 4},
{"\xFF\xFF\xFF\xFE\x00\x00\x00\x00", 4},
/* 4B - LE */
{"\x00\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x01\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x02\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x03\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x04\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x05\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x06\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x07\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x08\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x09\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x0A\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x0B\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x0C\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x0D\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x0E\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x0F\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x10\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x20\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x40\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x7E\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x7F\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x80\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x81\x00\x00\x00\x00\x00\x00\x00", 4},
{"\xC0\x00\x00\x00\x00\x00\x00\x00", 4},
{"\xFE\x00\x00\x00\x00\x00\x00\x00", 4},
{"\xFF\x00\x00\x00\x00\x00\x00\x00", 4},
{"\xFF\xFF\xFF\x7E\x00\x00\x00\x00", 4},
{"\xFF\xFF\xFF\x7F\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x80\x00\x00\x00\x00", 4},
{"\x01\x00\x00\x80\x00\x00\x00\x00", 4},
{"\xFE\xFF\xFF\xFF\x00\x00\x00\x00", 4},
/* 8B - NE */
{"\x00\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x01\x01\x01\x01\x01\x01\x01\x01", 8},
{"\x80\x80\x80\x80\x80\x80\x80\x80", 8},
{"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8},
/* 8B - BE */
{"\x00\x00\x00\x00\x00\x00\x00\x01", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x02", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x03", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x04", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x05", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x06", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x07", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x08", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x09", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x0A", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x0B", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x0C", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x0D", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x0E", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x0F", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x10", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x20", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x40", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x7E", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x7F", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x80", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x81", 8},
{"\x00\x00\x00\x00\x00\x00\x00\xC0", 8},
{"\x00\x00\x00\x00\x00\x00\x00\xFE", 8},
{"\x00\x00\x00\x00\x00\x00\x00\xFF", 8},
{"\x7E\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8},
{"\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8},
{"\x80\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x80\x00\x00\x00\x00\x00\x00\x01", 8},
{"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE", 8},
/* 8B - LE */
{"\x00\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x01\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x02\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x03\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x04\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x05\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x06\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x07\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x08\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x09\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x0A\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x0B\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x0C\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x0D\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x0E\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x0F\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x10\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x20\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x40\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x7E\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x7F\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x80\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x81\x00\x00\x00\x00\x00\x00\x00", 8},
{"\xC0\x00\x00\x00\x00\x00\x00\x00", 8},
{"\xFE\x00\x00\x00\x00\x00\x00\x00", 8},
{"\xFF\x00\x00\x00\x00\x00\x00\x00", 8},
{"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7E", 8},
{"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x80", 8},
{"\x01\x00\x00\x00\x00\x00\x00\x80", 8},
{"\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8},
};
static void mangle_Magic(run_t* run, bool printable) {
uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleMagicVals) - 1);
mangle_UseValue(run, mangleMagicVals[choice].val, mangleMagicVals[choice].size, printable);
}
static void mangle_StaticDict(run_t* run, bool printable) {
if (run->global->mutate.dictionaryCnt == 0) {
mangle_Bytes(run, printable);
return;
}
uint64_t choice = util_rndGet(0, run->global->mutate.dictionaryCnt - 1);
mangle_UseValue(run, run->global->mutate.dictionary[choice].val,
run->global->mutate.dictionary[choice].len, printable);
}
static inline const uint8_t* mangle_FeedbackDict(run_t* run, size_t* len) {
if (!run->global->feedback.cmpFeedback) {
return NULL;
}
cmpfeedback_t* cmpf = run->global->feedback.cmpFeedbackMap;
uint32_t cnt = ATOMIC_GET(cmpf->cnt);
if (cnt == 0) {
return NULL;
}
if (cnt > ARRAYSIZE(cmpf->valArr)) {
cnt = ARRAYSIZE(cmpf->valArr);
}
uint32_t choice = util_rndGet(0, cnt - 1);
*len = (size_t)ATOMIC_GET(cmpf->valArr[choice].len);
if (*len == 0) {
return NULL;
}
return cmpf->valArr[choice].val;
}
static void mangle_ConstFeedbackDict(run_t* run, bool printable) {
size_t len;
const uint8_t* val = mangle_FeedbackDict(run, &len);
if (val == NULL) {
mangle_Bytes(run, printable);
return;
}
mangle_UseValue(run, val, len, printable);
}
static void mangle_MemSet(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
size_t len = mangle_getLen(run->dynfile->size - off);
int val = printable ? (int)util_rndPrintable() : (int)util_rndGet(0, UINT8_MAX);
if (util_rnd64() & 1) {
len = mangle_Inflate(run, off, len, printable);
}
memset(&run->dynfile->data[off], val, len);
}
static void mangle_MemClr(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
size_t len = mangle_getLen(run->dynfile->size - off);
int val = printable ? ' ' : 0;
if (util_rnd64() & 1) {
len = mangle_Inflate(run, off, len, printable);
}
memset(&run->dynfile->data[off], val, len);
}
static void mangle_RandomBuf(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
size_t len = mangle_getLen(run->dynfile->size - off);
if (util_rnd64() & 1) {
len = mangle_Inflate(run, off, len, printable);
}
if (printable) {
util_rndBufPrintable(&run->dynfile->data[off], len);
} else {
util_rndBuf(&run->dynfile->data[off], len);
}
}
static inline void mangle_AddSubWithRange(
run_t* run, size_t off, size_t varLen, uint64_t range, bool printable) {
int64_t delta = (int64_t)util_rndGet(0, range * 2) - (int64_t)range;
switch (varLen) {
case 1: {
run->dynfile->data[off] += delta;
break;
}
case 2: {
int16_t val;
memcpy(&val, &run->dynfile->data[off], sizeof(val));
if (util_rnd64() & 0x1) {
val += delta;
} else {
/* Foreign endianess */
val = __builtin_bswap16(val);
val += delta;
val = __builtin_bswap16(val);
}
mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable);
break;
}
case 4: {
int32_t val;
memcpy(&val, &run->dynfile->data[off], sizeof(val));
if (util_rnd64() & 0x1) {
val += delta;
} else {
/* Foreign endianess */
val = __builtin_bswap32(val);
val += delta;
val = __builtin_bswap32(val);
}
mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable);
break;
}
case 8: {
int64_t val;
memcpy(&val, &run->dynfile->data[off], sizeof(val));
if (util_rnd64() & 0x1) {
val += delta;
} else {
/* Foreign endianess */
val = __builtin_bswap64(val);
val += delta;
val = __builtin_bswap64(val);
}
mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable);
break;
}
default: {
LOG_F("Unknown variable length size: %zu", varLen);
}
}
}
static void mangle_AddSub(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
/* 1,2,4,8 */
size_t varLen = 1U << util_rndGet(0, 3);
if ((run->dynfile->size - off) < varLen) {
varLen = 1;
}
uint64_t range;
switch (varLen) {
case 1:
range = 16;
break;
case 2:
range = 4096;
break;
case 4:
range = 1048576;
break;
case 8:
range = 268435456;
break;
default:
LOG_F("Invalid operand size: %zu", varLen);
}
mangle_AddSubWithRange(run, off, varLen, range, printable);
}
static void mangle_IncByte(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
if (printable) {
run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 1) % 95 + 32;
} else {
run->dynfile->data[off] += (uint8_t)1UL;
}
}
static void mangle_DecByte(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
if (printable) {
run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 94) % 95 + 32;
} else {
run->dynfile->data[off] -= (uint8_t)1UL;
}
}
static void mangle_NegByte(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
if (printable) {
run->dynfile->data[off] = 94 - (run->dynfile->data[off] - 32) + 32;
} else {
run->dynfile->data[off] = ~(run->dynfile->data[off]);
}
}
static void mangle_Expand(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
size_t len;
if (util_rnd64() % 16) {
len = mangle_getLen(HF_MIN(16, run->global->mutate.maxInputSz - off));
} else {
len = mangle_getLen(run->global->mutate.maxInputSz - off);
}
mangle_Inflate(run, off, len, printable);
}
static void mangle_Shrink(run_t* run, bool printable HF_ATTR_UNUSED) {
if (run->dynfile->size <= 2U) {
return;
}
size_t off_start = mangle_getOffSet(run);
size_t len = mangle_LenLeft(run, off_start);
if (len == 0) {
return;
}
if (util_rnd64() % 16) {
len = mangle_getLen(HF_MIN(16, len));
} else {
len = mangle_getLen(len);
}
size_t off_end = off_start + len;
size_t len_to_move = run->dynfile->size - off_end;
mangle_Move(run, off_end, off_start, len_to_move);
input_setSize(run, run->dynfile->size - len);
}
static void mangle_ASCIINum(run_t* run, bool printable) {
size_t len = util_rndGet(2, 8);
char buf[20];
snprintf(buf, sizeof(buf), "%-19" PRId64, (int64_t)util_rnd64());
mangle_UseValue(run, (const uint8_t*)buf, len, printable);
}
static void mangle_ASCIINumChange(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
/* Find a digit */
for (; off < run->dynfile->size; off++) {
if (isdigit(run->dynfile->data[off])) {
break;
}
}
size_t left = run->dynfile->size - off;
if (left == 0) {
return;
}
size_t len = 0;
uint64_t val = 0;
/* 20 is maximum lenght of a string representing a 64-bit unsigned value */
for (len = 0; (len < 20) && (len < left); len++) {
char c = run->dynfile->data[off + len];
if (!isdigit(c)) {
break;
}
val *= 10;
val += (c - '0');
}
switch (util_rndGet(0, 7)) {
case 0:
val++;
break;
case 1:
val--;
break;
case 2:
val *= 2;
break;
case 3:
val /= 2;
break;
case 4:
val = util_rnd64();
break;
case 5:
val += util_rndGet(1, 256);
break;
case 6:
val -= util_rndGet(1, 256);
break;
case 7:
val = ~(val);
break;
default:
LOG_F("Invalid choice");
};
char buf[20];
snprintf(buf, sizeof(buf), "%-19" PRIu64, val);
mangle_UseValueAt(run, off, (const uint8_t*)buf, len, printable);
}
static void mangle_Splice(run_t* run, bool printable) {
if (run->global->feedback.dynFileMethod == _HF_DYNFILE_NONE) {
mangle_Bytes(run, printable);
return;
}
size_t sz = 0;
const uint8_t* buf = input_getRandomInputAsBuf(run, &sz);
if (!buf) {
LOG_E("input_getRandomInputAsBuf() returned no input");
mangle_Bytes(run, printable);
return;
}
if (!sz) {
mangle_Bytes(run, printable);
return;
}
size_t remoteOff = mangle_getLen(sz) - 1;
size_t len = mangle_getLen(sz - remoteOff);
mangle_UseValue(run, &buf[remoteOff], len, printable);
}
static void mangle_Resize(run_t* run, bool printable) {
ssize_t oldsz = run->dynfile->size;
ssize_t newsz = 0;
uint64_t choice = util_rndGet(0, 32);
switch (choice) {
case 0: /* Set new size arbitrarily */
newsz = (ssize_t)util_rndGet(1, run->global->mutate.maxInputSz);
break;
case 1 ... 4: /* Increase size by a small value */
newsz = oldsz + (ssize_t)util_rndGet(0, 8);
break;
case 5: /* Increase size by a larger value */
newsz = oldsz + (ssize_t)util_rndGet(9, 128);
break;
case 6 ... 9: /* Decrease size by a small value */
newsz = oldsz - (ssize_t)util_rndGet(0, 8);
break;
case 10: /* Decrease size by a larger value */
newsz = oldsz - (ssize_t)util_rndGet(9, 128);
break;
case 11 ... 32: /* Do nothing */
newsz = oldsz;
break;
default:
LOG_F("Illegal value from util_rndGet: %" PRIu64, choice);
break;
}
if (newsz < 1) {
newsz = 1;
}
if (newsz > (ssize_t)run->global->mutate.maxInputSz) {
newsz = run->global->mutate.maxInputSz;
}
input_setSize(run, (size_t)newsz);
if (newsz > oldsz) {
if (printable) {
memset(&run->dynfile->data[oldsz], ' ', newsz - oldsz);
}
}
}
void mangle_mangleContent(run_t* run, int speed_factor) {
static void (*const mangleFuncs[])(run_t * run, bool printable) = {
mangle_Shrink,
mangle_Expand,
mangle_Bit,
mangle_IncByte,
mangle_DecByte,
mangle_NegByte,
mangle_AddSub,
mangle_MemSet,
mangle_MemClr,
mangle_MemSwap,
mangle_MemCopy,
mangle_Bytes,
mangle_ASCIINum,
mangle_ASCIINumChange,
mangle_ByteRepeat,
mangle_Magic,
mangle_StaticDict,
mangle_ConstFeedbackDict,
mangle_RandomBuf,
mangle_Splice,
};
if (run->mutationsPerRun == 0U) {
return;
}
if (run->dynfile->size == 0U) {
mangle_Resize(run, /* printable= */ run->global->cfg.only_printable);
}
uint64_t changesCnt = run->global->mutate.mutationsPerRun;
if (speed_factor < 5) {
changesCnt = util_rndGet(1, run->global->mutate.mutationsPerRun);
} else if (speed_factor < 10) {
changesCnt = run->global->mutate.mutationsPerRun;
} else {
changesCnt = HF_MIN(speed_factor, 10);
changesCnt = HF_MAX(changesCnt, (run->global->mutate.mutationsPerRun * 5));
}
/* If last coverage acquisition was more than 5 secs ago, use splicing more frequently */
if ((time(NULL) - ATOMIC_GET(run->global->timing.lastCovUpdate)) > 5) {
if (util_rnd64() & 0x1) {
mangle_Splice(run, run->global->cfg.only_printable);
}
}
for (uint64_t x = 0; x < changesCnt; x++) {
if (run->global->feedback.cmpFeedback && (util_rnd64() & 0x1)) {
/*
* mangle_ConstFeedbackDict() is quite powerful if the dynamic feedback dictionary
* exists. If so, give it 50% chance of being used among all mangling functions.
*/
mangle_ConstFeedbackDict(run, /* printable= */ run->global->cfg.only_printable);
} else {
uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleFuncs) - 1);
mangleFuncs[choice](run, /* printable= */ run->global->cfg.only_printable);
}
}
wmb();
}

View File

@ -1,31 +0,0 @@
/*
*
* honggfuzz - buffer mangling routines
* -----------------------------------------
*
* Author: Robert Swiecki <swiecki@google.com>
*
* Copyright 2010-2018 by Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
*/
#ifndef _HF_MANGLE_H_
#define _HF_MANGLE_H_
#include "honggfuzz.h"
extern void mangle_mangleContent(run_t* run, int speed_factor);
#endif

View File

@ -1,10 +0,0 @@
# Generated by Cargo
# will have compiled files and executables
/target/
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk

View File

@ -1,14 +0,0 @@
[package]
name = "libafl_base"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libafl = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "266677bb88abe75165430f34e7de897c35560504" }
custom_mutator = { path = "../rust/custom_mutator", features = ["afl_internals"] }
serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib
[lib]
crate-type = ["cdylib"]

View File

@ -1,9 +0,0 @@
all: target/release/liblibafl_base.so
cp target/release/liblibafl_base.so libafl_base.so
target/release/liblibafl_base.so: src/lib.rs
cargo build --release
clean:
cargo clean
rm -f libafl_base.so

View File

@ -1,11 +0,0 @@
# libafl basic havoc + token mutator
This uses the [libafl](https://github.com/AFLplusplus/libafl) StdScheduledMutator with `havoc_mutations` and `token_mutations`.
Make sure to have [cargo installed](https://rustup.rs/) and just type `make` to build.
Run with:
```
AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/libafl_base/libafl_base.so AFL_CUSTOM_MUTATOR_ONLY=1 afl-fuzz ...
```

View File

@ -1,252 +0,0 @@
#![cfg(unix)]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::{
cell::{RefCell, UnsafeCell},
collections::HashMap,
ffi::CStr,
};
use custom_mutator::{afl_state, export_mutator, CustomMutator};
use libafl::{
bolts::{rands::StdRand, serdeany::SerdeAnyMap, tuples::Merge},
corpus::{Corpus, Testcase},
inputs::{BytesInput, HasBytesVec},
mutators::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens},
Mutator,
},
prelude::UsesInput,
state::{HasCorpus, HasMaxSize, HasMetadata, HasRand, State, UsesState},
Error,
};
#[allow(clippy::identity_op)]
const MAX_FILE: usize = 1 * 1024 * 1024;
static mut AFL: Option<&'static afl_state> = None;
static mut CURRENT_ENTRY: Option<usize> = None;
fn afl() -> &'static afl_state {
unsafe { AFL.unwrap() }
}
#[derive(Default, Debug)]
pub struct AFLCorpus {
entries: UnsafeCell<HashMap<usize, RefCell<Testcase<BytesInput>>>>,
}
impl Clone for AFLCorpus {
fn clone(&self) -> Self {
unsafe {
Self {
entries: UnsafeCell::new(self.entries.get().as_ref().unwrap().clone()),
}
}
}
}
impl Serialize for AFLCorpus {
fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
unimplemented!();
}
}
impl<'de> Deserialize<'de> for AFLCorpus {
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
unimplemented!();
}
}
impl UsesState for AFLCorpus {
type State = AFLState;
}
impl Corpus for AFLCorpus {
#[inline]
fn count(&self) -> usize {
afl().queued_items as usize
}
#[inline]
fn add(&mut self, _testcase: Testcase<BytesInput>) -> Result<usize, Error> {
unimplemented!();
}
#[inline]
fn replace(
&mut self,
_idx: usize,
_testcase: Testcase<BytesInput>,
) -> Result<Testcase<Self::Input>, Error> {
unimplemented!();
}
#[inline]
fn remove(&mut self, _idx: usize) -> Result<Option<Testcase<BytesInput>>, Error> {
unimplemented!();
}
#[inline]
fn get(&self, idx: usize) -> Result<&RefCell<Testcase<BytesInput>>, Error> {
unsafe {
let entries = self.entries.get().as_mut().unwrap();
entries.entry(idx).or_insert_with(|| {
let queue_buf = std::slice::from_raw_parts_mut(afl().queue_buf, self.count());
let entry = queue_buf[idx].as_mut().unwrap();
let fname = CStr::from_ptr((entry.fname.cast::<i8>()).as_ref().unwrap())
.to_str()
.unwrap()
.to_owned();
let mut testcase = Testcase::with_filename(BytesInput::new(vec![]), fname);
*testcase.input_mut() = None;
RefCell::new(testcase)
});
Ok(&self.entries.get().as_ref().unwrap()[&idx])
}
}
#[inline]
fn current(&self) -> &Option<usize> {
unsafe {
CURRENT_ENTRY = Some(afl().current_entry as usize);
&CURRENT_ENTRY
}
}
#[inline]
fn current_mut(&mut self) -> &mut Option<usize> {
unimplemented!();
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct AFLState {
rand: StdRand,
corpus: AFLCorpus,
metadata: SerdeAnyMap,
max_size: usize,
}
impl AFLState {
#[must_use]
pub fn new(seed: u32) -> Self {
Self {
rand: StdRand::with_seed(u64::from(seed)),
corpus: AFLCorpus::default(),
metadata: SerdeAnyMap::new(),
max_size: MAX_FILE,
}
}
}
impl State for AFLState {}
impl HasRand for AFLState {
type Rand = StdRand;
#[inline]
fn rand(&self) -> &Self::Rand {
&self.rand
}
#[inline]
fn rand_mut(&mut self) -> &mut Self::Rand {
&mut self.rand
}
}
impl UsesInput for AFLState {
type Input = BytesInput;
}
impl HasCorpus for AFLState {
type Corpus = AFLCorpus;
#[inline]
fn corpus(&self) -> &Self::Corpus {
&self.corpus
}
#[inline]
fn corpus_mut(&mut self) -> &mut Self::Corpus {
&mut self.corpus
}
}
impl HasMetadata for AFLState {
#[inline]
fn metadata(&self) -> &SerdeAnyMap {
&self.metadata
}
#[inline]
fn metadata_mut(&mut self) -> &mut SerdeAnyMap {
&mut self.metadata
}
}
impl HasMaxSize for AFLState {
fn max_size(&self) -> usize {
self.max_size
}
fn set_max_size(&mut self, max_size: usize) {
self.max_size = max_size;
}
}
struct LibAFLBaseCustomMutator {
state: AFLState,
input: BytesInput,
}
impl CustomMutator for LibAFLBaseCustomMutator {
type Error = libafl::Error;
fn init(afl: &'static afl_state, seed: u32) -> Result<Self, Self::Error> {
unsafe {
AFL = Some(afl);
let mut state = AFLState::new(seed);
let extras = std::slice::from_raw_parts(afl.extras, afl.extras_cnt as usize);
let mut tokens = vec![];
for extra in extras {
let data = std::slice::from_raw_parts(extra.data, extra.len as usize);
tokens.push(data.to_vec());
}
if !tokens.is_empty() {
state.add_metadata(Tokens::from(tokens));
}
Ok(Self {
state,
input: BytesInput::new(vec![]),
})
}
}
fn fuzz<'b, 's: 'b>(
&'s mut self,
buffer: &'b mut [u8],
_add_buff: Option<&[u8]>,
max_size: usize,
) -> Result<Option<&'b [u8]>, Self::Error> {
self.state.set_max_size(max_size);
// TODO avoid copy
self.input.bytes_mut().clear();
self.input.bytes_mut().extend_from_slice(buffer);
let mut mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
mutator.mutate(&mut self.state, &mut self.input, 0)?;
Ok(Some(self.input.bytes()))
}
}
export_mutator!(LibAFLBaseCustomMutator);

View File

@ -1,35 +0,0 @@
//===- FuzzerBuiltins.h - Internal header for builtins ----------*- C++ -* ===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Wrapper functions and macros around builtin functions.
//===----------------------------------------------------------------------===//
#ifndef LLVM_FUZZER_BUILTINS_H
#define LLVM_FUZZER_BUILTINS_H
#include "FuzzerPlatform.h"
#if !LIBFUZZER_MSVC
#include <cstdint>
#define GET_CALLER_PC() __builtin_return_address(0)
namespace fuzzer {
inline uint8_t Bswap(uint8_t x) { return x; }
inline uint16_t Bswap(uint16_t x) { return __builtin_bswap16(x); }
inline uint32_t Bswap(uint32_t x) { return __builtin_bswap32(x); }
inline uint64_t Bswap(uint64_t x) { return __builtin_bswap64(x); }
inline uint32_t Clzll(unsigned long long X) { return __builtin_clzll(X); }
inline uint32_t Clz(unsigned long long X) { return __builtin_clz(X); }
inline int Popcountll(unsigned long long X) { return __builtin_popcountll(X); }
} // namespace fuzzer
#endif // !LIBFUZZER_MSVC
#endif // LLVM_FUZZER_BUILTINS_H

View File

@ -1,72 +0,0 @@
//===- FuzzerBuiltinsMSVC.h - Internal header for builtins ------*- C++ -* ===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Wrapper functions and macros that use intrinsics instead of builtin functions
// which cannot be compiled by MSVC.
//===----------------------------------------------------------------------===//
#ifndef LLVM_FUZZER_BUILTINS_MSVC_H
#define LLVM_FUZZER_BUILTINS_MSVC_H
#include "FuzzerPlatform.h"
#if LIBFUZZER_MSVC
#include <intrin.h>
#include <cstdint>
#include <cstdlib>
// __builtin_return_address() cannot be compiled with MSVC. Use the equivalent
// from <intrin.h>
#define GET_CALLER_PC() _ReturnAddress()
namespace fuzzer {
inline uint8_t Bswap(uint8_t x) { return x; }
// Use alternatives to __builtin functions from <stdlib.h> and <intrin.h> on
// Windows since the builtins are not supported by MSVC.
inline uint16_t Bswap(uint16_t x) { return _byteswap_ushort(x); }
inline uint32_t Bswap(uint32_t x) { return _byteswap_ulong(x); }
inline uint64_t Bswap(uint64_t x) { return _byteswap_uint64(x); }
// The functions below were mostly copied from
// compiler-rt/lib/builtins/int_lib.h which defines the __builtin functions used
// outside of Windows.
inline uint32_t Clzll(uint64_t X) {
unsigned long LeadZeroIdx = 0;
#if !defined(_M_ARM) && !defined(_M_X64)
// Scan the high 32 bits.
if (_BitScanReverse(&LeadZeroIdx, static_cast<unsigned long>(X >> 32)))
return static_cast<int>(63 - (LeadZeroIdx + 32)); // Create a bit offset from the MSB.
// Scan the low 32 bits.
if (_BitScanReverse(&LeadZeroIdx, static_cast<unsigned long>(X)))
return static_cast<int>(63 - LeadZeroIdx);
#else
if (_BitScanReverse64(&LeadZeroIdx, X)) return 63 - LeadZeroIdx;
#endif
return 64;
}
inline uint32_t Clz(uint32_t X) {
unsigned long LeadZeroIdx = 0;
if (_BitScanReverse(&LeadZeroIdx, X)) return 31 - LeadZeroIdx;
return 32;
}
inline int Popcountll(unsigned long long X) {
#if !defined(_M_ARM) && !defined(_M_X64)
return __popcnt(X) + __popcnt(X >> 32);
#else
return __popcnt64(X);
#endif
}
} // namespace fuzzer
#endif // LIBFUZER_MSVC
#endif // LLVM_FUZZER_BUILTINS_MSVC_H

View File

@ -1,178 +0,0 @@
//===- FuzzerCommand.h - Interface representing a process -------*- C++ -* ===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// FuzzerCommand represents a command to run in a subprocess. It allows callers
// to manage command line arguments and output and error streams.
//===----------------------------------------------------------------------===//
#ifndef LLVM_FUZZER_COMMAND_H
#define LLVM_FUZZER_COMMAND_H
#include "FuzzerDefs.h"
#include "FuzzerIO.h"
#include <algorithm>
#include <sstream>
#include <string>
#include <vector>
namespace fuzzer {
class Command final {
public:
// This command line flag is used to indicate that the remaining command line
// is immutable, meaning this flag effectively marks the end of the mutable
// argument list.
static inline const char *ignoreRemainingArgs() {
return "-ignore_remaining_args=1";
}
Command() : CombinedOutAndErr(false) {}
explicit Command(const Vector<std::string> &ArgsToAdd)
: Args(ArgsToAdd), CombinedOutAndErr(false) {}
explicit Command(const Command &Other)
: Args(Other.Args), CombinedOutAndErr(Other.CombinedOutAndErr),
OutputFile(Other.OutputFile) {}
Command &operator=(const Command &Other) {
Args = Other.Args;
CombinedOutAndErr = Other.CombinedOutAndErr;
OutputFile = Other.OutputFile;
return *this;
}
~Command() {}
// Returns true if the given Arg is present in Args. Only checks up to
// "-ignore_remaining_args=1".
bool hasArgument(const std::string &Arg) const {
auto i = endMutableArgs();
return std::find(Args.begin(), i, Arg) != i;
}
// Gets all of the current command line arguments, **including** those after
// "-ignore-remaining-args=1".
const Vector<std::string> &getArguments() const { return Args; }
// Adds the given argument before "-ignore_remaining_args=1", or at the end
// if that flag isn't present.
void addArgument(const std::string &Arg) {
Args.insert(endMutableArgs(), Arg);
}
// Adds all given arguments before "-ignore_remaining_args=1", or at the end
// if that flag isn't present.
void addArguments(const Vector<std::string> &ArgsToAdd) {
Args.insert(endMutableArgs(), ArgsToAdd.begin(), ArgsToAdd.end());
}
// Removes the given argument from the command argument list. Ignores any
// occurrences after "-ignore_remaining_args=1", if present.
void removeArgument(const std::string &Arg) {
auto i = endMutableArgs();
Args.erase(std::remove(Args.begin(), i, Arg), i);
}
// Like hasArgument, but checks for "-[Flag]=...".
bool hasFlag(const std::string &Flag) const {
std::string Arg("-" + Flag + "=");
auto IsMatch = [&](const std::string &Other) {
return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
};
return std::any_of(Args.begin(), endMutableArgs(), IsMatch);
}
// Returns the value of the first instance of a given flag, or an empty string
// if the flag isn't present. Ignores any occurrences after
// "-ignore_remaining_args=1", if present.
std::string getFlagValue(const std::string &Flag) const {
std::string Arg("-" + Flag + "=");
auto IsMatch = [&](const std::string &Other) {
return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
};
auto i = endMutableArgs();
auto j = std::find_if(Args.begin(), i, IsMatch);
std::string result;
if (j != i) {
result = j->substr(Arg.length());
}
return result;
}
// Like AddArgument, but adds "-[Flag]=[Value]".
void addFlag(const std::string &Flag, const std::string &Value) {
addArgument("-" + Flag + "=" + Value);
}
// Like RemoveArgument, but removes "-[Flag]=...".
void removeFlag(const std::string &Flag) {
std::string Arg("-" + Flag + "=");
auto IsMatch = [&](const std::string &Other) {
return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
};
auto i = endMutableArgs();
Args.erase(std::remove_if(Args.begin(), i, IsMatch), i);
}
// Returns whether the command's stdout is being written to an output file.
bool hasOutputFile() const { return !OutputFile.empty(); }
// Returns the currently set output file.
const std::string &getOutputFile() const { return OutputFile; }
// Configures the command to redirect its output to the name file.
void setOutputFile(const std::string &FileName) { OutputFile = FileName; }
// Returns whether the command's stderr is redirected to stdout.
bool isOutAndErrCombined() const { return CombinedOutAndErr; }
// Sets whether to redirect the command's stderr to its stdout.
void combineOutAndErr(bool combine = true) { CombinedOutAndErr = combine; }
// Returns a string representation of the command. On many systems this will
// be the equivalent command line.
std::string toString() const {
std::stringstream SS;
for (auto arg : getArguments())
SS << arg << " ";
if (hasOutputFile())
SS << ">" << getOutputFile() << " ";
if (isOutAndErrCombined())
SS << "2>&1 ";
std::string result = SS.str();
if (!result.empty())
result = result.substr(0, result.length() - 1);
return result;
}
private:
Command(Command &&Other) = delete;
Command &operator=(Command &&Other) = delete;
Vector<std::string>::iterator endMutableArgs() {
return std::find(Args.begin(), Args.end(), ignoreRemainingArgs());
}
Vector<std::string>::const_iterator endMutableArgs() const {
return std::find(Args.begin(), Args.end(), ignoreRemainingArgs());
}
// The command arguments. Args[0] is the command name.
Vector<std::string> Args;
// True indicates stderr is redirected to stdout.
bool CombinedOutAndErr;
// If not empty, stdout is redirected to the named file.
std::string OutputFile;
};
} // namespace fuzzer
#endif // LLVM_FUZZER_COMMAND_H

View File

@ -1,581 +0,0 @@
//===- FuzzerCorpus.h - Internal header for the Fuzzer ----------*- C++ -* ===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// fuzzer::InputCorpus
//===----------------------------------------------------------------------===//
#ifndef LLVM_FUZZER_CORPUS
#define LLVM_FUZZER_CORPUS
#include "FuzzerDataFlowTrace.h"
#include "FuzzerDefs.h"
#include "FuzzerIO.h"
#include "FuzzerRandom.h"
#include "FuzzerSHA1.h"
#include "FuzzerTracePC.h"
#include <algorithm>
#include <chrono>
#include <numeric>
#include <random>
#include <unordered_set>
namespace fuzzer {
struct InputInfo {
Unit U; // The actual input data.
std::chrono::microseconds TimeOfUnit;
uint8_t Sha1[kSHA1NumBytes]; // Checksum.
// Number of features that this input has and no smaller input has.
size_t NumFeatures = 0;
size_t Tmp = 0; // Used by ValidateFeatureSet.
// Stats.
size_t NumExecutedMutations = 0;
size_t NumSuccessfullMutations = 0;
bool NeverReduce = false;
bool MayDeleteFile = false;
bool Reduced = false;
bool HasFocusFunction = false;
Vector<uint32_t> UniqFeatureSet;
Vector<uint8_t> DataFlowTraceForFocusFunction;
// Power schedule.
bool NeedsEnergyUpdate = false;
double Energy = 0.0;
size_t SumIncidence = 0;
Vector<std::pair<uint32_t, uint16_t>> FeatureFreqs;
// Delete feature Idx and its frequency from FeatureFreqs.
bool DeleteFeatureFreq(uint32_t Idx) {
if (FeatureFreqs.empty())
return false;
// Binary search over local feature frequencies sorted by index.
auto Lower = std::lower_bound(FeatureFreqs.begin(), FeatureFreqs.end(),
std::pair<uint32_t, uint16_t>(Idx, 0));
if (Lower != FeatureFreqs.end() && Lower->first == Idx) {
FeatureFreqs.erase(Lower);
return true;
}
return false;
}
// Assign more energy to a high-entropy seed, i.e., that reveals more
// information about the globally rare features in the neighborhood of the
// seed. Since we do not know the entropy of a seed that has never been
// executed we assign fresh seeds maximum entropy and let II->Energy approach
// the true entropy from above. If ScalePerExecTime is true, the computed
// entropy is scaled based on how fast this input executes compared to the
// average execution time of inputs. The faster an input executes, the more
// energy gets assigned to the input.
void UpdateEnergy(size_t GlobalNumberOfFeatures, bool ScalePerExecTime,
std::chrono::microseconds AverageUnitExecutionTime) {
Energy = 0.0;
SumIncidence = 0;
// Apply add-one smoothing to locally discovered features.
for (auto F : FeatureFreqs) {
size_t LocalIncidence = F.second + 1;
Energy -= LocalIncidence * logl(LocalIncidence);
SumIncidence += LocalIncidence;
}
// Apply add-one smoothing to locally undiscovered features.
// PreciseEnergy -= 0; // since logl(1.0) == 0)
SumIncidence += (GlobalNumberOfFeatures - FeatureFreqs.size());
// Add a single locally abundant feature apply add-one smoothing.
size_t AbdIncidence = NumExecutedMutations + 1;
Energy -= AbdIncidence * logl(AbdIncidence);
SumIncidence += AbdIncidence;
// Normalize.
if (SumIncidence != 0)
Energy = (Energy / SumIncidence) + logl(SumIncidence);
if (ScalePerExecTime) {
// Scaling to favor inputs with lower execution time.
uint32_t PerfScore = 100;
if (TimeOfUnit.count() > AverageUnitExecutionTime.count() * 10)
PerfScore = 10;
else if (TimeOfUnit.count() > AverageUnitExecutionTime.count() * 4)
PerfScore = 25;
else if (TimeOfUnit.count() > AverageUnitExecutionTime.count() * 2)
PerfScore = 50;
else if (TimeOfUnit.count() * 3 > AverageUnitExecutionTime.count() * 4)
PerfScore = 75;
else if (TimeOfUnit.count() * 4 < AverageUnitExecutionTime.count())
PerfScore = 300;
else if (TimeOfUnit.count() * 3 < AverageUnitExecutionTime.count())
PerfScore = 200;
else if (TimeOfUnit.count() * 2 < AverageUnitExecutionTime.count())
PerfScore = 150;
Energy *= PerfScore;
}
}
// Increment the frequency of the feature Idx.
void UpdateFeatureFrequency(uint32_t Idx) {
NeedsEnergyUpdate = true;
// The local feature frequencies is an ordered vector of pairs.
// If there are no local feature frequencies, push_back preserves order.
// Set the feature frequency for feature Idx32 to 1.
if (FeatureFreqs.empty()) {
FeatureFreqs.push_back(std::pair<uint32_t, uint16_t>(Idx, 1));
return;
}
// Binary search over local feature frequencies sorted by index.
auto Lower = std::lower_bound(FeatureFreqs.begin(), FeatureFreqs.end(),
std::pair<uint32_t, uint16_t>(Idx, 0));
// If feature Idx32 already exists, increment its frequency.
// Otherwise, insert a new pair right after the next lower index.
if (Lower != FeatureFreqs.end() && Lower->first == Idx) {
Lower->second++;
} else {
FeatureFreqs.insert(Lower, std::pair<uint32_t, uint16_t>(Idx, 1));
}
}
};
struct EntropicOptions {
bool Enabled;
size_t NumberOfRarestFeatures;
size_t FeatureFrequencyThreshold;
bool ScalePerExecTime;
};
class InputCorpus {
static const uint32_t kFeatureSetSize = 1 << 21;
static const uint8_t kMaxMutationFactor = 20;
static const size_t kSparseEnergyUpdates = 100;
size_t NumExecutedMutations = 0;
EntropicOptions Entropic;
public:
InputCorpus(const std::string &OutputCorpus, EntropicOptions Entropic)
: Entropic(Entropic), OutputCorpus(OutputCorpus) {
memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature));
memset(SmallestElementPerFeature, 0, sizeof(SmallestElementPerFeature));
}
~InputCorpus() {
for (auto II : Inputs)
delete II;
}
size_t size() const { return Inputs.size(); }
size_t SizeInBytes() const {
size_t Res = 0;
for (auto II : Inputs)
Res += II->U.size();
return Res;
}
size_t NumActiveUnits() const {
size_t Res = 0;
for (auto II : Inputs)
Res += !II->U.empty();
return Res;
}
size_t MaxInputSize() const {
size_t Res = 0;
for (auto II : Inputs)
Res = std::max(Res, II->U.size());
return Res;
}
void IncrementNumExecutedMutations() { NumExecutedMutations++; }
size_t NumInputsThatTouchFocusFunction() {
return std::count_if(Inputs.begin(), Inputs.end(), [](const InputInfo *II) {
return II->HasFocusFunction;
});
}
size_t NumInputsWithDataFlowTrace() {
return std::count_if(Inputs.begin(), Inputs.end(), [](const InputInfo *II) {
return !II->DataFlowTraceForFocusFunction.empty();
});
}
bool empty() const { return Inputs.empty(); }
const Unit &operator[] (size_t Idx) const { return Inputs[Idx]->U; }
InputInfo *AddToCorpus(const Unit &U, size_t NumFeatures, bool MayDeleteFile,
bool HasFocusFunction, bool NeverReduce,
std::chrono::microseconds TimeOfUnit,
const Vector<uint32_t> &FeatureSet,
const DataFlowTrace &DFT, const InputInfo *BaseII) {
assert(!U.empty());
if (FeatureDebug)
Printf("ADD_TO_CORPUS %zd NF %zd\n", Inputs.size(), NumFeatures);
Inputs.push_back(new InputInfo());
InputInfo &II = *Inputs.back();
II.U = U;
II.NumFeatures = NumFeatures;
II.NeverReduce = NeverReduce;
II.TimeOfUnit = TimeOfUnit;
II.MayDeleteFile = MayDeleteFile;
II.UniqFeatureSet = FeatureSet;
II.HasFocusFunction = HasFocusFunction;
// Assign maximal energy to the new seed.
II.Energy = RareFeatures.empty() ? 1.0 : log(RareFeatures.size());
II.SumIncidence = RareFeatures.size();
II.NeedsEnergyUpdate = false;
std::sort(II.UniqFeatureSet.begin(), II.UniqFeatureSet.end());
ComputeSHA1(U.data(), U.size(), II.Sha1);
auto Sha1Str = Sha1ToString(II.Sha1);
Hashes.insert(Sha1Str);
if (HasFocusFunction)
if (auto V = DFT.Get(Sha1Str))
II.DataFlowTraceForFocusFunction = *V;
// This is a gross heuristic.
// Ideally, when we add an element to a corpus we need to know its DFT.
// But if we don't, we'll use the DFT of its base input.
if (II.DataFlowTraceForFocusFunction.empty() && BaseII)
II.DataFlowTraceForFocusFunction = BaseII->DataFlowTraceForFocusFunction;
DistributionNeedsUpdate = true;
PrintCorpus();
// ValidateFeatureSet();
return &II;
}
// Debug-only
void PrintUnit(const Unit &U) {
if (!FeatureDebug) return;
for (uint8_t C : U) {
if (C != 'F' && C != 'U' && C != 'Z')
C = '.';
Printf("%c", C);
}
}
// Debug-only
void PrintFeatureSet(const Vector<uint32_t> &FeatureSet) {
if (!FeatureDebug) return;
Printf("{");
for (uint32_t Feature: FeatureSet)
Printf("%u,", Feature);
Printf("}");
}
// Debug-only
void PrintCorpus() {
if (!FeatureDebug) return;
Printf("======= CORPUS:\n");
int i = 0;
for (auto II : Inputs) {
if (std::find(II->U.begin(), II->U.end(), 'F') != II->U.end()) {
Printf("[%2d] ", i);
Printf("%s sz=%zd ", Sha1ToString(II->Sha1).c_str(), II->U.size());
PrintUnit(II->U);
Printf(" ");
PrintFeatureSet(II->UniqFeatureSet);
Printf("\n");
}
i++;
}
}
void Replace(InputInfo *II, const Unit &U) {
assert(II->U.size() > U.size());
Hashes.erase(Sha1ToString(II->Sha1));
DeleteFile(*II);
ComputeSHA1(U.data(), U.size(), II->Sha1);
Hashes.insert(Sha1ToString(II->Sha1));
II->U = U;
II->Reduced = true;
DistributionNeedsUpdate = true;
}
bool HasUnit(const Unit &U) { return Hashes.count(Hash(U)); }
bool HasUnit(const std::string &H) { return Hashes.count(H); }
InputInfo &ChooseUnitToMutate(Random &Rand) {
InputInfo &II = *Inputs[ChooseUnitIdxToMutate(Rand)];
assert(!II.U.empty());
return II;
}
InputInfo &ChooseUnitToCrossOverWith(Random &Rand, bool UniformDist) {
if (!UniformDist) {
return ChooseUnitToMutate(Rand);
}
InputInfo &II = *Inputs[Rand(Inputs.size())];
assert(!II.U.empty());
return II;
}
// Returns an index of random unit from the corpus to mutate.
size_t ChooseUnitIdxToMutate(Random &Rand) {
UpdateCorpusDistribution(Rand);
size_t Idx = static_cast<size_t>(CorpusDistribution(Rand));
assert(Idx < Inputs.size());
return Idx;
}
void PrintStats() {
for (size_t i = 0; i < Inputs.size(); i++) {
const auto &II = *Inputs[i];
Printf(" [% 3zd %s] sz: % 5zd runs: % 5zd succ: % 5zd focus: %d\n", i,
Sha1ToString(II.Sha1).c_str(), II.U.size(),
II.NumExecutedMutations, II.NumSuccessfullMutations, II.HasFocusFunction);
}
}
void PrintFeatureSet() {
for (size_t i = 0; i < kFeatureSetSize; i++) {
if(size_t Sz = GetFeature(i))
Printf("[%zd: id %zd sz%zd] ", i, SmallestElementPerFeature[i], Sz);
}
Printf("\n\t");
for (size_t i = 0; i < Inputs.size(); i++)
if (size_t N = Inputs[i]->NumFeatures)
Printf(" %zd=>%zd ", i, N);
Printf("\n");
}
void DeleteFile(const InputInfo &II) {
if (!OutputCorpus.empty() && II.MayDeleteFile)
RemoveFile(DirPlusFile(OutputCorpus, Sha1ToString(II.Sha1)));
}
void DeleteInput(size_t Idx) {
InputInfo &II = *Inputs[Idx];
DeleteFile(II);
Unit().swap(II.U);
II.Energy = 0.0;
II.NeedsEnergyUpdate = false;
DistributionNeedsUpdate = true;
if (FeatureDebug)
Printf("EVICTED %zd\n", Idx);
}
void AddRareFeature(uint32_t Idx) {
// Maintain *at least* TopXRarestFeatures many rare features
// and all features with a frequency below ConsideredRare.
// Remove all other features.
while (RareFeatures.size() > Entropic.NumberOfRarestFeatures &&
FreqOfMostAbundantRareFeature > Entropic.FeatureFrequencyThreshold) {
// Find most and second most abbundant feature.
uint32_t MostAbundantRareFeatureIndices[2] = {RareFeatures[0],
RareFeatures[0]};
size_t Delete = 0;
for (size_t i = 0; i < RareFeatures.size(); i++) {
uint32_t Idx2 = RareFeatures[i];
if (GlobalFeatureFreqs[Idx2] >=
GlobalFeatureFreqs[MostAbundantRareFeatureIndices[0]]) {
MostAbundantRareFeatureIndices[1] = MostAbundantRareFeatureIndices[0];
MostAbundantRareFeatureIndices[0] = Idx2;
Delete = i;
}
}
// Remove most abundant rare feature.
RareFeatures[Delete] = RareFeatures.back();
RareFeatures.pop_back();
for (auto II : Inputs) {
if (II->DeleteFeatureFreq(MostAbundantRareFeatureIndices[0]))
II->NeedsEnergyUpdate = true;
}
// Set 2nd most abundant as the new most abundant feature count.
FreqOfMostAbundantRareFeature =
GlobalFeatureFreqs[MostAbundantRareFeatureIndices[1]];
}
// Add rare feature, handle collisions, and update energy.
RareFeatures.push_back(Idx);
GlobalFeatureFreqs[Idx] = 0;
for (auto II : Inputs) {
II->DeleteFeatureFreq(Idx);
// Apply add-one smoothing to this locally undiscovered feature.
// Zero energy seeds will never be fuzzed and remain zero energy.
if (II->Energy > 0.0) {
II->SumIncidence += 1;
II->Energy += logl(II->SumIncidence) / II->SumIncidence;
}
}
DistributionNeedsUpdate = true;
}
bool AddFeature(size_t Idx, uint32_t NewSize, bool Shrink) {
assert(NewSize);
Idx = Idx % kFeatureSetSize;
uint32_t OldSize = GetFeature(Idx);
if (OldSize == 0 || (Shrink && OldSize > NewSize)) {
if (OldSize > 0) {
size_t OldIdx = SmallestElementPerFeature[Idx];
InputInfo &II = *Inputs[OldIdx];
assert(II.NumFeatures > 0);
II.NumFeatures--;
if (II.NumFeatures == 0)
DeleteInput(OldIdx);
} else {
NumAddedFeatures++;
if (Entropic.Enabled)
AddRareFeature((uint32_t)Idx);
}
NumUpdatedFeatures++;
if (FeatureDebug)
Printf("ADD FEATURE %zd sz %d\n", Idx, NewSize);
SmallestElementPerFeature[Idx] = Inputs.size();
InputSizesPerFeature[Idx] = NewSize;
return true;
}
return false;
}
// Increment frequency of feature Idx globally and locally.
void UpdateFeatureFrequency(InputInfo *II, size_t Idx) {
uint32_t Idx32 = Idx % kFeatureSetSize;
// Saturated increment.
if (GlobalFeatureFreqs[Idx32] == 0xFFFF)
return;
uint16_t Freq = GlobalFeatureFreqs[Idx32]++;
// Skip if abundant.
if (Freq > FreqOfMostAbundantRareFeature ||
std::find(RareFeatures.begin(), RareFeatures.end(), Idx32) ==
RareFeatures.end())
return;
// Update global frequencies.
if (Freq == FreqOfMostAbundantRareFeature)
FreqOfMostAbundantRareFeature++;
// Update local frequencies.
if (II)
II->UpdateFeatureFrequency(Idx32);
}
size_t NumFeatures() const { return NumAddedFeatures; }
size_t NumFeatureUpdates() const { return NumUpdatedFeatures; }
private:
static const bool FeatureDebug = false;
size_t GetFeature(size_t Idx) const { return InputSizesPerFeature[Idx]; }
void ValidateFeatureSet() {
if (FeatureDebug)
PrintFeatureSet();
for (size_t Idx = 0; Idx < kFeatureSetSize; Idx++)
if (GetFeature(Idx))
Inputs[SmallestElementPerFeature[Idx]]->Tmp++;
for (auto II: Inputs) {
if (II->Tmp != II->NumFeatures)
Printf("ZZZ %zd %zd\n", II->Tmp, II->NumFeatures);
assert(II->Tmp == II->NumFeatures);
II->Tmp = 0;
}
}
// Updates the probability distribution for the units in the corpus.
// Must be called whenever the corpus or unit weights are changed.
//
// Hypothesis: inputs that maximize information about globally rare features
// are interesting.
void UpdateCorpusDistribution(Random &Rand) {
// Skip update if no seeds or rare features were added/deleted.
// Sparse updates for local change of feature frequencies,
// i.e., randomly do not skip.
if (!DistributionNeedsUpdate &&
(!Entropic.Enabled || Rand(kSparseEnergyUpdates)))
return;
DistributionNeedsUpdate = false;
size_t N = Inputs.size();
assert(N);
Intervals.resize(N + 1);
Weights.resize(N);
std::iota(Intervals.begin(), Intervals.end(), 0);
std::chrono::microseconds AverageUnitExecutionTime(0);
for (auto II : Inputs) {
AverageUnitExecutionTime += II->TimeOfUnit;
}
AverageUnitExecutionTime /= N;
bool VanillaSchedule = true;
if (Entropic.Enabled) {
for (auto II : Inputs) {
if (II->NeedsEnergyUpdate && II->Energy != 0.0) {
II->NeedsEnergyUpdate = false;
II->UpdateEnergy(RareFeatures.size(), Entropic.ScalePerExecTime,
AverageUnitExecutionTime);
}
}
for (size_t i = 0; i < N; i++) {
if (Inputs[i]->NumFeatures == 0) {
// If the seed doesn't represent any features, assign zero energy.
Weights[i] = 0.;
} else if (Inputs[i]->NumExecutedMutations / kMaxMutationFactor >
NumExecutedMutations / Inputs.size()) {
// If the seed was fuzzed a lot more than average, assign zero energy.
Weights[i] = 0.;
} else {
// Otherwise, simply assign the computed energy.
Weights[i] = Inputs[i]->Energy;
}
// If energy for all seeds is zero, fall back to vanilla schedule.
if (Weights[i] > 0.0)
VanillaSchedule = false;
}
}
if (VanillaSchedule) {
for (size_t i = 0; i < N; i++)
Weights[i] = Inputs[i]->NumFeatures
? (i + 1) * (Inputs[i]->HasFocusFunction ? 1000 : 1)
: 0.;
}
if (FeatureDebug) {
for (size_t i = 0; i < N; i++)
Printf("%zd ", Inputs[i]->NumFeatures);
Printf("SCORE\n");
for (size_t i = 0; i < N; i++)
Printf("%f ", Weights[i]);
Printf("Weights\n");
}
CorpusDistribution = std::piecewise_constant_distribution<double>(
Intervals.begin(), Intervals.end(), Weights.begin());
}
std::piecewise_constant_distribution<double> CorpusDistribution;
Vector<double> Intervals;
Vector<double> Weights;
std::unordered_set<std::string> Hashes;
Vector<InputInfo*> Inputs;
size_t NumAddedFeatures = 0;
size_t NumUpdatedFeatures = 0;
uint32_t InputSizesPerFeature[kFeatureSetSize];
uint32_t SmallestElementPerFeature[kFeatureSetSize];
bool DistributionNeedsUpdate = true;
uint16_t FreqOfMostAbundantRareFeature = 0;
uint16_t GlobalFeatureFreqs[kFeatureSetSize] = {};
Vector<uint32_t> RareFeatures;
std::string OutputCorpus;
};
} // namespace fuzzer
#endif // LLVM_FUZZER_CORPUS

View File

@ -1,60 +0,0 @@
//===- FuzzerCrossOver.cpp - Cross over two test inputs -------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Cross over test inputs.
//===----------------------------------------------------------------------===//
#include "FuzzerDefs.h"
#include "FuzzerMutate.h"
#include "FuzzerRandom.h"
#include <cstring>
namespace fuzzer {
// Cross Data1 and Data2, store the result (up to MaxOutSize bytes) in Out.
size_t MutationDispatcher::CrossOver(const uint8_t *Data1, size_t Size1,
const uint8_t *Data2, size_t Size2,
uint8_t *Out, size_t MaxOutSize) {
assert(Size1 || Size2);
MaxOutSize = Rand(MaxOutSize) + 1;
size_t OutPos = 0;
size_t Pos1 = 0;
size_t Pos2 = 0;
size_t * InPos = &Pos1;
size_t InSize = Size1;
const uint8_t *Data = Data1;
bool CurrentlyUsingFirstData = true;
while (OutPos < MaxOutSize && (Pos1 < Size1 || Pos2 < Size2)) {
// Merge a part of Data into Out.
size_t OutSizeLeft = MaxOutSize - OutPos;
if (*InPos < InSize) {
size_t InSizeLeft = InSize - *InPos;
size_t MaxExtraSize = std::min(OutSizeLeft, InSizeLeft);
size_t ExtraSize = Rand(MaxExtraSize) + 1;
memcpy(Out + OutPos, Data + *InPos, ExtraSize);
OutPos += ExtraSize;
(*InPos) += ExtraSize;
}
// Use the other input data on the next iteration.
InPos = CurrentlyUsingFirstData ? &Pos2 : &Pos1;
InSize = CurrentlyUsingFirstData ? Size2 : Size1;
Data = CurrentlyUsingFirstData ? Data2 : Data1;
CurrentlyUsingFirstData = !CurrentlyUsingFirstData;
}
return OutPos;
}
} // namespace fuzzer

View File

@ -1,344 +0,0 @@
//===- FuzzerDataFlowTrace.cpp - DataFlowTrace ---*- C++ -* ===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// fuzzer::DataFlowTrace
//===----------------------------------------------------------------------===//
#include "FuzzerDataFlowTrace.h"
#include "FuzzerCommand.h"
#include "FuzzerIO.h"
#include "FuzzerRandom.h"
#include "FuzzerSHA1.h"
#include "FuzzerUtil.h"
#include <cstdlib>
#include <fstream>
#include <numeric>
#include <queue>
#include <sstream>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
namespace fuzzer {
static const char *kFunctionsTxt = "functions.txt";
bool BlockCoverage::AppendCoverage(const std::string &S) {
std::stringstream SS(S);
return AppendCoverage(SS);
}
// Coverage lines have this form:
// CN X Y Z T
// where N is the number of the function, T is the total number of instrumented
// BBs, and X,Y,Z, if present, are the indecies of covered BB.
// BB #0, which is the entry block, is not explicitly listed.
bool BlockCoverage::AppendCoverage(std::istream &IN) {
std::string L;
while (std::getline(IN, L, '\n')) {
if (L.empty()) continue;
std::stringstream SS(L.c_str() + 1);
size_t FunctionId = 0;
SS >> FunctionId;
if (L[0] == 'F') {
FunctionsWithDFT.insert(FunctionId);
continue;
}
if (L[0] != 'C') continue;
Vector<uint32_t> CoveredBlocks;
while (true) {
uint32_t BB = 0;
SS >> BB;
if (!SS) break;
CoveredBlocks.push_back(BB);
}
if (CoveredBlocks.empty()) return false;
uint32_t NumBlocks = CoveredBlocks.back();
CoveredBlocks.pop_back();
for (auto BB : CoveredBlocks)
if (BB >= NumBlocks) return false;
auto It = Functions.find(FunctionId);
auto &Counters =
It == Functions.end()
? Functions.insert({FunctionId, Vector<uint32_t>(NumBlocks)})
.first->second
: It->second;
if (Counters.size() != NumBlocks) return false; // wrong number of blocks.
Counters[0]++;
for (auto BB : CoveredBlocks)
Counters[BB]++;
}
return true;
}
// Assign weights to each function.
// General principles:
// * any uncovered function gets weight 0.
// * a function with lots of uncovered blocks gets bigger weight.
// * a function with a less frequently executed code gets bigger weight.
Vector<double> BlockCoverage::FunctionWeights(size_t NumFunctions) const {
Vector<double> Res(NumFunctions);
for (auto It : Functions) {
auto FunctionID = It.first;
auto Counters = It.second;
assert(FunctionID < NumFunctions);
auto &Weight = Res[FunctionID];
// Give higher weight if the function has a DFT.
Weight = FunctionsWithDFT.count(FunctionID) ? 1000. : 1;
// Give higher weight to functions with less frequently seen basic blocks.
Weight /= SmallestNonZeroCounter(Counters);
// Give higher weight to functions with the most uncovered basic blocks.
Weight *= NumberOfUncoveredBlocks(Counters) + 1;
}
return Res;
}
void DataFlowTrace::ReadCoverage(const std::string &DirPath) {
Vector<SizedFile> Files;
GetSizedFilesFromDir(DirPath, &Files);
for (auto &SF : Files) {
auto Name = Basename(SF.File);
if (Name == kFunctionsTxt) continue;
if (!CorporaHashes.count(Name)) continue;
std::ifstream IF(SF.File);
Coverage.AppendCoverage(IF);
}
}
static void DFTStringAppendToVector(Vector<uint8_t> * DFT,
const std::string &DFTString) {
assert(DFT->size() == DFTString.size());
for (size_t I = 0, Len = DFT->size(); I < Len; I++)
(*DFT)[I] = DFTString[I] == '1';
}
// converts a string of '0' and '1' into a Vector<uint8_t>
static Vector<uint8_t> DFTStringToVector(const std::string &DFTString) {
Vector<uint8_t> DFT(DFTString.size());
DFTStringAppendToVector(&DFT, DFTString);
return DFT;
}
static bool ParseError(const char *Err, const std::string &Line) {
Printf("DataFlowTrace: parse error: %s: Line: %s\n", Err, Line.c_str());
return false;
}
// TODO(metzman): replace std::string with std::string_view for
// better performance. Need to figure our how to use string_view on Windows.
static bool ParseDFTLine(const std::string &Line, size_t *FunctionNum,
std::string *DFTString) {
if (!Line.empty() && Line[0] != 'F') return false; // Ignore coverage.
size_t SpacePos = Line.find(' ');
if (SpacePos == std::string::npos)
return ParseError("no space in the trace line", Line);
if (Line.empty() || Line[0] != 'F')
return ParseError("the trace line doesn't start with 'F'", Line);
*FunctionNum = std::atol(Line.c_str() + 1);
const char *Beg = Line.c_str() + SpacePos + 1;
const char *End = Line.c_str() + Line.size();
assert(Beg < End);
size_t Len = End - Beg;
for (size_t I = 0; I < Len; I++) {
if (Beg[I] != '0' && Beg[I] != '1')
return ParseError("the trace should contain only 0 or 1", Line);
}
*DFTString = Beg;
return true;
}
bool DataFlowTrace::Init(const std::string &DirPath, std::string *FocusFunction,
Vector<SizedFile> &CorporaFiles, Random &Rand) {
if (DirPath.empty()) return false;
Printf("INFO: DataFlowTrace: reading from '%s'\n", DirPath.c_str());
Vector<SizedFile> Files;
GetSizedFilesFromDir(DirPath, &Files);
std::string L;
size_t FocusFuncIdx = SIZE_MAX;
Vector<std::string> FunctionNames;
// Collect the hashes of the corpus files.
for (auto &SF : CorporaFiles)
CorporaHashes.insert(Hash(FileToVector(SF.File)));
// Read functions.txt
std::ifstream IF(DirPlusFile(DirPath, kFunctionsTxt));
size_t NumFunctions = 0;
while (std::getline(IF, L, '\n')) {
FunctionNames.push_back(L);
NumFunctions++;
if (*FocusFunction == L) FocusFuncIdx = NumFunctions - 1;
}
if (!NumFunctions) return false;
if (*FocusFunction == "auto") {
// AUTOFOCUS works like this:
// * reads the coverage data from the DFT files.
// * assigns weights to functions based on coverage.
// * chooses a random function according to the weights.
ReadCoverage(DirPath);
auto Weights = Coverage.FunctionWeights(NumFunctions);
Vector<double> Intervals(NumFunctions + 1);
std::iota(Intervals.begin(), Intervals.end(), 0);
auto Distribution = std::piecewise_constant_distribution<double>(
Intervals.begin(), Intervals.end(), Weights.begin());
FocusFuncIdx = static_cast<size_t>(Distribution(Rand));
*FocusFunction = FunctionNames[FocusFuncIdx];
assert(FocusFuncIdx < NumFunctions);
Printf("INFO: AUTOFOCUS: %zd %s\n", FocusFuncIdx,
FunctionNames[FocusFuncIdx].c_str());
for (size_t i = 0; i < NumFunctions; i++) {
if (!Weights[i]) continue;
Printf(" [%zd] W %g\tBB-tot %u\tBB-cov %u\tEntryFreq %u:\t%s\n", i,
Weights[i], Coverage.GetNumberOfBlocks(i),
Coverage.GetNumberOfCoveredBlocks(i), Coverage.GetCounter(i, 0),
FunctionNames[i].c_str());
}
}
if (FocusFuncIdx == SIZE_MAX || Files.size() <= 1)
return false;
// Read traces.
size_t NumTraceFiles = 0;
size_t NumTracesWithFocusFunction = 0;
for (auto &SF : Files) {
auto Name = Basename(SF.File);
if (Name == kFunctionsTxt) continue;
if (!CorporaHashes.count(Name)) continue; // not in the corpus.
NumTraceFiles++;
// Printf("=== %s\n", Name.c_str());
std::ifstream IF2(SF.File);
while (std::getline(IF2, L, '\n')) {
size_t FunctionNum = 0;
std::string DFTString;
if (ParseDFTLine(L, &FunctionNum, &DFTString) &&
FunctionNum == FocusFuncIdx) {
NumTracesWithFocusFunction++;
if (FunctionNum >= NumFunctions)
return ParseError("N is greater than the number of functions", L);
Traces[Name] = DFTStringToVector(DFTString);
// Print just a few small traces.
if (NumTracesWithFocusFunction <= 3 && DFTString.size() <= 16)
Printf("%s => |%s|\n", Name.c_str(), std::string(DFTString).c_str());
break; // No need to parse the following lines.
}
}
}
Printf(
"INFO: DataFlowTrace: %zd trace files, %zd functions, "
"%zd traces with focus function\n",
NumTraceFiles, NumFunctions, NumTracesWithFocusFunction);
return NumTraceFiles > 0;
}
int CollectDataFlow(const std::string &DFTBinary, const std::string &DirPath,
const Vector<SizedFile> &CorporaFiles) {
Printf("INFO: collecting data flow: bin: %s dir: %s files: %zd\n",
DFTBinary.c_str(), DirPath.c_str(), CorporaFiles.size());
if (CorporaFiles.empty()) {
Printf("ERROR: can't collect data flow without corpus provided.");
return 1;
}
static char DFSanEnv[] = "DFSAN_OPTIONS=warn_unimplemented=0";
putenv(DFSanEnv);
MkDir(DirPath);
for (auto &F : CorporaFiles) {
// For every input F we need to collect the data flow and the coverage.
// Data flow collection may fail if we request too many DFSan tags at once.
// So, we start from requesting all tags in range [0,Size) and if that fails
// we then request tags in [0,Size/2) and [Size/2, Size), and so on.
// Function number => DFT.
auto OutPath = DirPlusFile(DirPath, Hash(FileToVector(F.File)));
// std::unordered_map<size_t, Vector<uint8_t>> DFTMap;
// std::unordered_set<std::string> Cov;
Command Cmd;
Cmd.addArgument(DFTBinary);
Cmd.addArgument(F.File);
Cmd.addArgument(OutPath);
Printf("CMD: %s\n", Cmd.toString().c_str());
ExecuteCommand(Cmd);
}
// Write functions.txt if it's currently empty or doesn't exist.
auto FunctionsTxtPath = DirPlusFile(DirPath, kFunctionsTxt);
if (FileToString(FunctionsTxtPath).empty()) {
Command Cmd;
Cmd.addArgument(DFTBinary);
Cmd.setOutputFile(FunctionsTxtPath);
ExecuteCommand(Cmd);
}
return 0;
}
} // namespace fuzzer

View File

@ -1,135 +0,0 @@
//===- FuzzerDataFlowTrace.h - Internal header for the Fuzzer ---*- C++ -* ===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// fuzzer::DataFlowTrace; reads and handles a data-flow trace.
//
// A data flow trace is generated by e.g. dataflow/DataFlow.cpp
// and is stored on disk in a separate directory.
//
// The trace dir contains a file 'functions.txt' which lists function names,
// oner per line, e.g.
// ==> functions.txt <==
// Func2
// LLVMFuzzerTestOneInput
// Func1
//
// All other files in the dir are the traces, see dataflow/DataFlow.cpp.
// The name of the file is sha1 of the input used to generate the trace.
//
// Current status:
// the data is parsed and the summary is printed, but the data is not yet
// used in any other way.
//===----------------------------------------------------------------------===//
#ifndef LLVM_FUZZER_DATA_FLOW_TRACE
#define LLVM_FUZZER_DATA_FLOW_TRACE
#include "FuzzerDefs.h"
#include "FuzzerIO.h"
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <string>
namespace fuzzer {
int CollectDataFlow(const std::string &DFTBinary, const std::string &DirPath,
const Vector<SizedFile> &CorporaFiles);
class BlockCoverage {
public:
bool AppendCoverage(std::istream &IN);
bool AppendCoverage(const std::string &S);
size_t NumCoveredFunctions() const { return Functions.size(); }
uint32_t GetCounter(size_t FunctionId, size_t BasicBlockId) {
auto It = Functions.find(FunctionId);
if (It == Functions.end()) return 0;
const auto &Counters = It->second;
if (BasicBlockId < Counters.size())
return Counters[BasicBlockId];
return 0;
}
uint32_t GetNumberOfBlocks(size_t FunctionId) {
auto It = Functions.find(FunctionId);
if (It == Functions.end()) return 0;
const auto &Counters = It->second;
return Counters.size();
}
uint32_t GetNumberOfCoveredBlocks(size_t FunctionId) {
auto It = Functions.find(FunctionId);
if (It == Functions.end()) return 0;
const auto &Counters = It->second;
uint32_t Result = 0;
for (auto Cnt: Counters)
if (Cnt)
Result++;
return Result;
}
Vector<double> FunctionWeights(size_t NumFunctions) const;
void clear() { Functions.clear(); }
private:
typedef Vector<uint32_t> CoverageVector;
uint32_t NumberOfCoveredBlocks(const CoverageVector &Counters) const {
uint32_t Res = 0;
for (auto Cnt : Counters)
if (Cnt)
Res++;
return Res;
}
uint32_t NumberOfUncoveredBlocks(const CoverageVector &Counters) const {
return Counters.size() - NumberOfCoveredBlocks(Counters);
}
uint32_t SmallestNonZeroCounter(const CoverageVector &Counters) const {
assert(!Counters.empty());
uint32_t Res = Counters[0];
for (auto Cnt : Counters)
if (Cnt)
Res = Min(Res, Cnt);
assert(Res);
return Res;
}
// Function ID => vector of counters.
// Each counter represents how many input files trigger the given basic block.
std::unordered_map<size_t, CoverageVector> Functions;
// Functions that have DFT entry.
std::unordered_set<size_t> FunctionsWithDFT;
};
class DataFlowTrace {
public:
void ReadCoverage(const std::string &DirPath);
bool Init(const std::string &DirPath, std::string *FocusFunction,
Vector<SizedFile> &CorporaFiles, Random &Rand);
void Clear() { Traces.clear(); }
const Vector<uint8_t> *Get(const std::string &InputSha1) const {
auto It = Traces.find(InputSha1);
if (It != Traces.end())
return &It->second;
return nullptr;
}
private:
// Input's sha1 => DFT for the FocusFunction.
std::unordered_map<std::string, Vector<uint8_t> > Traces;
BlockCoverage Coverage;
std::unordered_set<std::string> CorporaHashes;
};
} // namespace fuzzer
#endif // LLVM_FUZZER_DATA_FLOW_TRACE

View File

@ -1,75 +0,0 @@
//===- FuzzerDefs.h - Internal header for the Fuzzer ------------*- C++ -* ===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Basic definitions.
//===----------------------------------------------------------------------===//
#ifndef LLVM_FUZZER_DEFS_H
#define LLVM_FUZZER_DEFS_H
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <memory>
#include <set>
#include <string>
#include <vector>
namespace fuzzer {
template <class T> T Min(T a, T b) { return a < b ? a : b; }
template <class T> T Max(T a, T b) { return a > b ? a : b; }
class Random;
class Dictionary;
class DictionaryEntry;
class MutationDispatcher;
struct FuzzingOptions;
class InputCorpus;
struct InputInfo;
struct ExternalFunctions;
// Global interface to functions that may or may not be available.
extern ExternalFunctions *EF;
// We are using a custom allocator to give a different symbol name to STL
// containers in order to avoid ODR violations.
template<typename T>
class fuzzer_allocator: public std::allocator<T> {
public:
fuzzer_allocator() = default;
template<class U>
explicit fuzzer_allocator(const fuzzer_allocator<U>&) {}
template<class Other>
struct rebind { typedef fuzzer_allocator<Other> other; };
};
template<typename T>
using Vector = std::vector<T, fuzzer_allocator<T>>;
template<typename T>
using Set = std::set<T, std::less<T>, fuzzer_allocator<T>>;
typedef Vector<uint8_t> Unit;
typedef Vector<Unit> UnitVector;
typedef int (*UserCallback)(const uint8_t *Data, size_t Size);
int FuzzerDriver(int *argc, char ***argv, UserCallback Callback);
uint8_t *ExtraCountersBegin();
uint8_t *ExtraCountersEnd();
void ClearExtraCounters();
extern bool RunningUserCallback;
} // namespace fuzzer
#endif // LLVM_FUZZER_DEFS_H

View File

@ -1,118 +0,0 @@
//===- FuzzerDictionary.h - Internal header for the Fuzzer ------*- C++ -* ===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// fuzzer::Dictionary
//===----------------------------------------------------------------------===//
#ifndef LLVM_FUZZER_DICTIONARY_H
#define LLVM_FUZZER_DICTIONARY_H
#include "FuzzerDefs.h"
#include "FuzzerIO.h"
#include "FuzzerUtil.h"
#include <algorithm>
#include <limits>
namespace fuzzer {
// A simple POD sized array of bytes.
template <size_t kMaxSizeT> class FixedWord {
public:
static const size_t kMaxSize = kMaxSizeT;
FixedWord() {}
FixedWord(const uint8_t *B, uint8_t S) { Set(B, S); }
void Set(const uint8_t *B, uint8_t S) {
assert(S <= kMaxSize);
memcpy(Data, B, S);
Size = S;
}
bool operator==(const FixedWord<kMaxSize> &w) const {
return Size == w.Size && 0 == memcmp(Data, w.Data, Size);
}
static size_t GetMaxSize() { return kMaxSize; }
const uint8_t *data() const { return Data; }
uint8_t size() const { return Size; }
private:
uint8_t Size = 0;
uint8_t Data[kMaxSize];
};
typedef FixedWord<64> Word;
class DictionaryEntry {
public:
DictionaryEntry() {}
explicit DictionaryEntry(Word W) : W(W) {}
DictionaryEntry(Word W, size_t PositionHint) : W(W), PositionHint(PositionHint) {}
const Word &GetW() const { return W; }
bool HasPositionHint() const { return PositionHint != std::numeric_limits<size_t>::max(); }
size_t GetPositionHint() const {
assert(HasPositionHint());
return PositionHint;
}
void IncUseCount() { UseCount++; }
void IncSuccessCount() { SuccessCount++; }
size_t GetUseCount() const { return UseCount; }
size_t GetSuccessCount() const {return SuccessCount; }
void Print(const char *PrintAfter = "\n") {
PrintASCII(W.data(), W.size());
if (HasPositionHint())
Printf("@%zd", GetPositionHint());
Printf("%s", PrintAfter);
}
private:
Word W;
size_t PositionHint = std::numeric_limits<size_t>::max();
size_t UseCount = 0;
size_t SuccessCount = 0;
};
class Dictionary {
public:
static const size_t kMaxDictSize = 1 << 14;
bool ContainsWord(const Word &W) const {
return std::any_of(begin(), end(), [&](const DictionaryEntry &DE) {
return DE.GetW() == W;
});
}
const DictionaryEntry *begin() const { return &DE[0]; }
const DictionaryEntry *end() const { return begin() + Size; }
DictionaryEntry & operator[] (size_t Idx) {
assert(Idx < Size);
return DE[Idx];
}
void push_back(const DictionaryEntry &DE) {
if (Size < kMaxDictSize)
this->DE[Size++] = DE;
}
void clear() { Size = 0; }
bool empty() const { return Size == 0; }
size_t size() const { return Size; }
private:
DictionaryEntry DE[kMaxDictSize];
size_t Size = 0;
};
// Parses one dictionary entry.
// If successful, write the enty to Unit and returns true,
// otherwise returns false.
bool ParseOneDictionaryEntry(const std::string &Str, Unit *U);
// Parses the dictionary file, fills Units, returns true iff all lines
// were parsed successfully.
bool ParseDictionaryFile(const std::string &Text, Vector<Unit> *Units);
} // namespace fuzzer
#endif // LLVM_FUZZER_DICTIONARY_H

File diff suppressed because it is too large Load Diff

View File

@ -1,50 +0,0 @@
//===- FuzzerExtFunctions.def - External functions --------------*- C++ -* ===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// This defines the external function pointers that
// ``fuzzer::ExternalFunctions`` should contain and try to initialize. The
// EXT_FUNC macro must be defined at the point of inclusion. The signature of
// the macro is:
//
// EXT_FUNC(<name>, <return_type>, <function_signature>, <warn_if_missing>)
//===----------------------------------------------------------------------===//
// Optional user functions
EXT_FUNC(LLVMFuzzerInitialize, int, (int *argc, char ***argv), false);
EXT_FUNC(LLVMFuzzerCustomMutator, size_t,
(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed),
false);
EXT_FUNC(LLVMFuzzerCustomCrossOver, size_t,
(const uint8_t *Data1, size_t Size1,
const uint8_t *Data2, size_t Size2,
uint8_t *Out, size_t MaxOutSize, unsigned int Seed),
false);
// Sanitizer functions
EXT_FUNC(__lsan_enable, void, (), false);
EXT_FUNC(__lsan_disable, void, (), false);
EXT_FUNC(__lsan_do_recoverable_leak_check, int, (), false);
EXT_FUNC(__sanitizer_acquire_crash_state, int, (), true);
EXT_FUNC(__sanitizer_install_malloc_and_free_hooks, int,
(void (*malloc_hook)(const volatile void *, size_t),
void (*free_hook)(const volatile void *)),
false);
EXT_FUNC(__sanitizer_log_write, void, (const char *buf, size_t len), false);
EXT_FUNC(__sanitizer_purge_allocator, void, (), false);
EXT_FUNC(__sanitizer_print_memory_profile, void, (size_t, size_t), false);
EXT_FUNC(__sanitizer_print_stack_trace, void, (), true);
EXT_FUNC(__sanitizer_symbolize_pc, void,
(void *, const char *fmt, char *out_buf, size_t out_buf_size), false);
EXT_FUNC(__sanitizer_get_module_and_offset_for_pc, int,
(void *pc, char *module_path,
size_t module_path_len,void **pc_offset), false);
EXT_FUNC(__sanitizer_set_death_callback, void, (void (*)(void)), true);
EXT_FUNC(__sanitizer_set_report_fd, void, (void*), false);
EXT_FUNC(__msan_scoped_disable_interceptor_checks, void, (), false);
EXT_FUNC(__msan_scoped_enable_interceptor_checks, void, (), false);
EXT_FUNC(__msan_unpoison, void, (const volatile void *, size_t size), false);
EXT_FUNC(__msan_unpoison_param, void, (size_t n), false);

View File

@ -1,34 +0,0 @@
//===- FuzzerExtFunctions.h - Interface to external functions ---*- C++ -* ===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Defines an interface to (possibly optional) functions.
//===----------------------------------------------------------------------===//
#ifndef LLVM_FUZZER_EXT_FUNCTIONS_H
#define LLVM_FUZZER_EXT_FUNCTIONS_H
#include <stddef.h>
#include <stdint.h>
namespace fuzzer {
struct ExternalFunctions {
// Initialize function pointers. Functions that are not available will be set
// to nullptr. Do not call this constructor before ``main()`` has been
// entered.
ExternalFunctions();
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
RETURN_TYPE(*NAME) FUNC_SIG = nullptr
#include "FuzzerExtFunctions.def"
#undef EXT_FUNC
};
} // namespace fuzzer
#endif

View File

@ -1,60 +0,0 @@
//===- FuzzerExtFunctionsDlsym.cpp - Interface to external functions ------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Implementation for operating systems that support dlsym(). We only use it on
// Apple platforms for now. We don't use this approach on Linux because it
// requires that clients of LibFuzzer pass ``--export-dynamic`` to the linker.
// That is a complication we don't wish to expose to clients right now.
//===----------------------------------------------------------------------===//
#include "FuzzerPlatform.h"
#if LIBFUZZER_APPLE
#include "FuzzerExtFunctions.h"
#include "FuzzerIO.h"
#include <dlfcn.h>
using namespace fuzzer;
template <typename T>
static T GetFnPtr(const char *FnName, bool WarnIfMissing) {
dlerror(); // Clear any previous errors.
void *Fn = dlsym(RTLD_DEFAULT, FnName);
if (Fn == nullptr) {
if (WarnIfMissing) {
const char *ErrorMsg = dlerror();
Printf("WARNING: Failed to find function \"%s\".", FnName);
if (ErrorMsg) Printf(" Reason %s.", ErrorMsg);
Printf("\n");
}
}
return reinterpret_cast<T>(Fn);
}
namespace fuzzer {
ExternalFunctions::ExternalFunctions() {
\
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
this->NAME = GetFnPtr<decltype(ExternalFunctions::NAME)>(#NAME, WARN)
#include "FuzzerExtFunctions.def"
#undef EXT_FUNC
}
} // namespace fuzzer
#endif // LIBFUZZER_APPLE

View File

@ -1,63 +0,0 @@
//===- FuzzerExtFunctionsWeak.cpp - Interface to external functions -------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Implementation for Linux. This relies on the linker's support for weak
// symbols. We don't use this approach on Apple platforms because it requires
// clients of LibFuzzer to pass ``-U _<symbol_name>`` to the linker to allow
// weak symbols to be undefined. That is a complication we don't want to expose
// to clients right now.
//===----------------------------------------------------------------------===//
#include "FuzzerPlatform.h"
#if LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FUCHSIA || \
LIBFUZZER_FREEBSD || LIBFUZZER_OPENBSD || LIBFUZZER_EMSCRIPTEN
#include "FuzzerExtFunctions.h"
#include "FuzzerIO.h"
extern "C" {
// Declare these symbols as weak to allow them to be optionally defined.
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
__attribute__((weak, visibility("default"))) RETURN_TYPE NAME FUNC_SIG
#include "FuzzerExtFunctions.def"
#undef EXT_FUNC
}
using namespace fuzzer;
static void CheckFnPtr(void *FnPtr, const char *FnName, bool WarnIfMissing) {
if (FnPtr == nullptr && WarnIfMissing) {
Printf("WARNING: Failed to find function \"%s\".\n", FnName);
}
}
namespace fuzzer {
ExternalFunctions::ExternalFunctions() {
\
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
this->NAME = ::NAME; \
CheckFnPtr(reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(::NAME)), \
#NAME, WARN);
#include "FuzzerExtFunctions.def"
#undef EXT_FUNC
}
} // namespace fuzzer
#endif

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