mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-24 22:53:24 +00:00
Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
2f6106879f | |||
4567a836e5 | |||
4b63eb2cf3 | |||
d33020db57 | |||
103884de2a | |||
96b5159eed | |||
a961039b19 | |||
ecc1ddaec6 | |||
05cc21e9d6 | |||
954f50fa00 | |||
27d08ee0b2 | |||
05c8dd90ca |
74
.github/workflows/ci.yml
vendored
74
.github/workflows/ci.yml
vendored
@ -9,79 +9,7 @@ on:
|
||||
branches:
|
||||
- dev # No need for stable-pull-request, as that equals dev-push
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
check-compiler-passes-old:
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
matrix:
|
||||
version: [14, 15]
|
||||
env:
|
||||
AFL_SKIP_CPUFREQ: 1
|
||||
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: update
|
||||
run: sudo apt-get update && sudo apt-get upgrade -y
|
||||
- name: debug
|
||||
run: apt-cache search plugin-dev | grep gcc-; echo; apt-cache search clang-format- | grep clang-format-
|
||||
- name: install packages
|
||||
run: sudo apt-get install -y -m -f build-essential git libtool libtool-bin automake flex bison libglib2.0-0 libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build python3-pip gcc-12-plugin-dev
|
||||
- name: install llvm-tools
|
||||
run: sudo apt install -y clang-${{ matrix.version }} llvm-${{ matrix.version }}
|
||||
- name: install clang-rt (for llvm 15)
|
||||
# because ubuntu-22.04 already has this package
|
||||
if: matrix.version != '15'
|
||||
run: sudo apt install -y libclang-${{ matrix.version }}-dev
|
||||
- name: compiler installed
|
||||
run: gcc -v; echo; clang -v
|
||||
- name: build afl++
|
||||
run: export NO_NYX=1; export ASAN_BUILD=1; export LLVM_CONFIG=llvm-config-${{ matrix.version }}; make ASAN_BUILD=1 NO_NYX=1 LLVM_CONFIG=llvm-config-${{ matrix.version }} all
|
||||
- name: Check llvm passes
|
||||
run: make ASAN_BUILD=1 NO_NYX=1 LLVM_CONFIG=llvm-config-${{ matrix.version }} llvm-build-test || exit 1
|
||||
- name: run tests
|
||||
run: sudo -E ./afl-system-config; make tests
|
||||
check-compiler-passes-new:
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
matrix:
|
||||
version: [16, 17, 18, 19, 20]
|
||||
env:
|
||||
AFL_SKIP_CPUFREQ: 1
|
||||
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: update
|
||||
run: sudo apt-get update && sudo apt-get upgrade -y
|
||||
- name: debug
|
||||
run: apt-cache search plugin-dev | grep gcc-; echo; apt-cache search clang-format- | grep clang-format-
|
||||
- name: install packages
|
||||
run: sudo apt-get install -y -m -f build-essential git libtool libtool-bin automake flex bison libglib2.0-0 libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build python3-pip gcc-12-plugin-dev
|
||||
- name: install llvm-tools (20)
|
||||
if: matrix.version == '20'
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh ${{ matrix.version }}
|
||||
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${{ matrix.version }} 200
|
||||
- name: install llvm-tools
|
||||
if: matrix.version != '20'
|
||||
run: sudo apt install -y clang-${{ matrix.version }} llvm-${{ matrix.version }}
|
||||
- name: install clang-rt
|
||||
if: matrix.version != '20'
|
||||
run: sudo apt install -y libclang-${{ matrix.version }}-dev
|
||||
- name: compiler installed
|
||||
run: gcc -v; echo; clang -v
|
||||
- name: build afl++
|
||||
run: export NO_NYX=1; export ASAN_BUILD=1; export LLVM_CONFIG=llvm-config-${{ matrix.version }}; make ASAN_BUILD=1 NO_NYX=1 LLVM_CONFIG=llvm-config-${{ matrix.version }} all
|
||||
- name: Check llvm passes
|
||||
run: make ASAN_BUILD=1 NO_NYX=1 LLVM_CONFIG=llvm-config-${{ matrix.version }} llvm-build-test || exit 1
|
||||
- name: run tests
|
||||
run: sudo -E ./afl-system-config; make tests
|
||||
|
||||
linux:
|
||||
runs-on: "${{ matrix.os }}"
|
||||
strategy:
|
||||
@ -103,7 +31,7 @@ jobs:
|
||||
- name: install gcc plugin
|
||||
run: sudo apt-get install -y -m -f --install-suggests $(readlink /usr/bin/gcc)-plugin-dev
|
||||
- name: build afl++
|
||||
run: export NO_NYX=1; export ASAN_BUILD=1; export LLVM_CONFIG=llvm-config-15; make ASAN_BUILD=1 NO_NYX=1 LLVM_CONFIG=llvm-config-15 distrib
|
||||
run: export NO_NYX=1; export ASAN_BUILD=1; export LLVM_CONFIG=llvm-config-12; make ASAN_BUILD=1 NO_NYX=1 LLVM_CONFIG=llvm-config-12 distrib
|
||||
- name: run tests
|
||||
run: sudo -E ./afl-system-config; make tests
|
||||
macos:
|
||||
|
4
.github/workflows/code-format.yml
vendored
4
.github/workflows/code-format.yml
vendored
@ -9,10 +9,6 @@ on:
|
||||
branches:
|
||||
- dev # No need for stable-pull-request, as that equals dev-push
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
code-format-check:
|
||||
name: Check code format
|
||||
|
4
.github/workflows/codeql-analysis.yml
vendored
4
.github/workflows/codeql-analysis.yml
vendored
@ -9,10 +9,6 @@ on:
|
||||
branches:
|
||||
- dev # No need for stable-pull-request, as that equals dev-push
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
|
4
.github/workflows/container.yml
vendored
4
.github/workflows/container.yml
vendored
@ -10,10 +10,6 @@ on:
|
||||
branches:
|
||||
- dev # No need for stable-pull-request, as that equals dev-push
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-and-test-amd64:
|
||||
name: Test amd64 image
|
||||
|
4
.github/workflows/rust_custom_mutator.yml
vendored
4
.github/workflows/rust_custom_mutator.yml
vendored
@ -9,10 +9,6 @@ on:
|
||||
branches:
|
||||
- dev # No need for stable-pull-request, as that equals dev-push
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Test Rust Custom Mutator Support
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -108,8 +108,6 @@ utils/persistent_mode/persistent_demo
|
||||
utils/persistent_mode/persistent_demo_new
|
||||
utils/persistent_mode/persistent_demo_new_compat
|
||||
utils/persistent_mode/test-instr
|
||||
utils/qemu_persistent_hook/mipsel_test
|
||||
utils/qemu_persistent_hook/test
|
||||
utils/replay_record/persistent_demo_replay
|
||||
utils/replay_record/persistent_demo_replay_compat
|
||||
utils/replay_record/persistent_demo_replay_argparse
|
||||
|
12
Dockerfile
12
Dockerfile
@ -5,7 +5,7 @@
|
||||
# GCC 11 is used instead of 12 because genhtml for afl-cov doesn't like it.
|
||||
#
|
||||
|
||||
FROM ubuntu:24.04 AS aflplusplus
|
||||
FROM ubuntu:22.04 AS aflplusplus
|
||||
LABEL "maintainer"="AFL++ team <afl@aflplus.plus>"
|
||||
LABEL "about"="AFLplusplus container image"
|
||||
|
||||
@ -17,7 +17,7 @@ ENV NO_NYX=1
|
||||
|
||||
### Only change these if you know what you are doing:
|
||||
# Current recommended LLVM version is 16
|
||||
ENV LLVM_VERSION=19
|
||||
ENV LLVM_VERSION=16
|
||||
# GCC 12 is producing compile errors for some targets so we stay at GCC 11
|
||||
ENV GCC_VERSION=11
|
||||
|
||||
@ -32,8 +32,8 @@ RUN apt-get update && apt-get full-upgrade -y && \
|
||||
apt-get install -y --no-install-recommends wget ca-certificates apt-utils && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
#RUN echo "deb [signed-by=/etc/apt/keyrings/llvm-snapshot.gpg.key] http://apt.llvm.org/jammy/ llvm-toolchain-jammy-${LLVM_VERSION} main" > /etc/apt/sources.list.d/llvm.list && \
|
||||
# wget -qO /etc/apt/keyrings/llvm-snapshot.gpg.key https://apt.llvm.org/llvm-snapshot.gpg.key
|
||||
RUN echo "deb [signed-by=/etc/apt/keyrings/llvm-snapshot.gpg.key] http://apt.llvm.org/jammy/ llvm-toolchain-jammy-${LLVM_VERSION} main" > /etc/apt/sources.list.d/llvm.list && \
|
||||
wget -qO /etc/apt/keyrings/llvm-snapshot.gpg.key https://apt.llvm.org/llvm-snapshot.gpg.key
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get -y install --no-install-recommends \
|
||||
@ -65,8 +65,8 @@ RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${GCC_VERSION} 0
|
||||
update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${LLVM_VERSION} 0 && \
|
||||
update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-${LLVM_VERSION} 0
|
||||
|
||||
#RUN wget -qO- https://sh.rustup.rs | CARGO_HOME=/etc/cargo sh -s -- -y -q --no-modify-path
|
||||
#ENV PATH=$PATH:/etc/cargo/bin
|
||||
RUN wget -qO- https://sh.rustup.rs | CARGO_HOME=/etc/cargo sh -s -- -y -q --no-modify-path
|
||||
ENV PATH=$PATH:/etc/cargo/bin
|
||||
|
||||
RUN apt clean -y
|
||||
|
||||
|
34
GNUmakefile
34
GNUmakefile
@ -31,7 +31,7 @@ PROGNAME = afl
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
|
||||
PROGS = afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
|
||||
SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-cmin.py afl-whatsup afl-addseeds afl-system-config afl-persistent-config afl-cc
|
||||
SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-addseeds afl-system-config afl-persistent-config afl-cc
|
||||
HEADERS = include/afl-fuzz.h include/afl-mutations.h include/afl-persistent-replay.h include/afl-prealloc.h include/afl-record-compat.h include/alloc-inl.h include/android-ashmem.h include/cmplog.h include/common.h include/config.h include/coverage-32.h include/coverage-64.h include/debug.h include/envs.h include/forkserver.h include/hash.h include/list.h include/sharedmem.h include/snapshot-inl.h include/t1ha.h include/t1ha0_ia32aes_b.h include/t1ha_bits.h include/t1ha_selfcheck.h include/types.h include/xxhash.h
|
||||
MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8)
|
||||
ASAN_OPTIONS=detect_leaks=0
|
||||
@ -76,16 +76,14 @@ ifdef IS_IOS
|
||||
endif
|
||||
|
||||
ifeq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
ifndef ASAN_BUILD
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto=full
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto=thin
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@ -255,6 +253,17 @@ ifeq "$(PYTHON_INCLUDE)" ""
|
||||
endif
|
||||
endif
|
||||
|
||||
# Old Ubuntu and others dont have python/python2-config so we hardcode 2.7
|
||||
ifeq "$(PYTHON_INCLUDE)" ""
|
||||
ifneq "$(shell command -v python2.7 2>/dev/null)" ""
|
||||
ifneq "$(shell command -v python2.7-config 2>/dev/null)" ""
|
||||
PYTHON_INCLUDE := $(shell python2.7-config --includes)
|
||||
PYTHON_LIB := $(shell python2.7-config --ldflags)
|
||||
PYTHON_VERSION := $(strip $(shell python2.7 --version 2>&1))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef SOURCE_DATE_EPOCH
|
||||
BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u "+%Y-%m-%d")
|
||||
else
|
||||
@ -304,8 +313,8 @@ ifeq "$(shell command -v svn >/dev/null && svn proplist . 2>/dev/null && echo 1
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo 'int main() { return 0;}' | $(CC) $(CFLAGS) -fsanitize=address -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -DASAN_BUILD -fno-lto
|
||||
ASAN_LDFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -fno-lto
|
||||
ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -DASAN_BUILD
|
||||
ASAN_LDFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
@ -345,11 +354,6 @@ llvm:
|
||||
-$(MAKE) -j$(nproc) -f GNUmakefile.llvm
|
||||
@test -e afl-cc || { echo "[-] Compiling afl-cc failed. You seem not to have a working compiler." ; exit 1; }
|
||||
|
||||
llvm-build-test:
|
||||
$(MAKE) -j$(nproc) -f GNUmakefile.llvm
|
||||
@test -e afl-cc || { echo "[-] Compiling afl-cc failed. You seem not to have a working compiler." ; exit 1; }
|
||||
|
||||
|
||||
.PHONY: gcc_plugin
|
||||
gcc_plugin:
|
||||
ifneq "$(SYS)" "Darwin"
|
||||
|
@ -148,7 +148,7 @@ afl-common.o: ./src/afl-common.c
|
||||
$(PASSES): instrumentation/afl-gcc-common.h
|
||||
|
||||
./afl-gcc-pass.so: instrumentation/afl-gcc-pass.so.cc | test_deps
|
||||
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@ $(LDFLAGS)
|
||||
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
|
||||
ln -sf afl-cc afl-gcc-fast
|
||||
ln -sf afl-cc afl-g++-fast
|
||||
ln -sf afl-cc.8 afl-gcc-fast.8
|
||||
|
@ -32,8 +32,8 @@ VERSION = $(shell grep '^ *$(HASH)define VERSION ' ./config.h | cut -d '"' -
|
||||
|
||||
SYS = $(shell uname -s)
|
||||
|
||||
override LLVM_TOO_NEW_DEFAULT := 21
|
||||
override LLVM_TOO_OLD_DEFAULT := 14
|
||||
override LLVM_TOO_NEW_DEFAULT := 19
|
||||
override LLVM_TOO_OLD_DEFAULT := 13
|
||||
|
||||
ifeq "$(SYS)" "OpenBSD"
|
||||
LLVM_CONFIG ?= $(BIN_PATH)/llvm-config
|
||||
@ -69,7 +69,7 @@ endif
|
||||
|
||||
LLVM_STDCXX := gnu++11
|
||||
LLVM_LTO := 0
|
||||
LLVM_UNSUPPORTED := $(shell echo "$(LLVMVER)" | grep -E -q '^[0-2]\.|^3\.[0-7]\.|^2[2-9]\.' && echo 1 || echo 0)
|
||||
LLVM_UNSUPPORTED := $(shell echo "$(LLVMVER)" | grep -E -q '^[0-2]\.|^3\.[0-7]\.|^2[1-9]\.' && echo 1 || echo 0)
|
||||
# Uncomment to see the values assigned above
|
||||
# $(foreach var,_CLANG_VERSIONS_TO_TEST LLVM_CONFIG LLVMVER LLVM_MAJOR LLVM_MINOR LLVM_TOO_NEW LLVM_TOO_OLD LLVM_TOO_NEW_DEFAULT LLVM_TOO_OLD_DEFAULT LLVM_NEW_API LLVM_NEWER_API LLVM_13_OK LLVM_HAVE_LTO LLVM_BINDIR LLVM_LIBDIR LLVM_STDCXX LLVM_APPLE_XCODE LLVM_LTO LLVM_UNSUPPORTED,$(warning $(var) = $($(var))))
|
||||
|
||||
@ -470,7 +470,7 @@ endif
|
||||
|
||||
./afl-ld-lto: src/afl-ld-lto.c
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ $(LDFLAGS)
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
Release version: [4.32c](https://github.com/AFLplusplus/AFLplusplus/releases)
|
||||
|
||||
GitHub version: 4.33a
|
||||
GitHub version: 4.32c
|
||||
|
||||
Repository:
|
||||
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
||||
@ -230,7 +230,7 @@ Thank you! (For people sending pull requests - please add yourself to this list
|
||||
fuzzah @intrigus-lgtm
|
||||
Yaakov Saxon Sergej Schumilo
|
||||
Ziqiao Kong Ryan Berger
|
||||
Sangjun Park Scott Guest
|
||||
Sangjun Park
|
||||
```
|
||||
|
||||
</details>
|
||||
@ -259,5 +259,3 @@ presented at WOOT'20:
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
[](https://deepwiki.com/AFLplusplus/AFLplusplus)
|
||||
|
9
afl-cmin
9
afl-cmin
@ -1,19 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
THISPATH=`dirname ${0}`
|
||||
|
||||
# call afl-cmin.py if it can be executed successfully.
|
||||
if $THISPATH/afl-cmin.py --help > /dev/null 2>&1; then
|
||||
exec $THISPATH/afl-cmin.py "$@"
|
||||
fi
|
||||
|
||||
SYS=$(uname -s)
|
||||
test "$SYS" = "Darwin" && {
|
||||
echo Error: afl-cmin does not work on Apple currently. please use afl-cmin.bash instead.
|
||||
exit 1
|
||||
}
|
||||
|
||||
export AFL_QUIET=1
|
||||
export ASAN_OPTIONS=detect_leaks=0
|
||||
THISPATH=`dirname ${0}`
|
||||
export PATH="${THISPATH}:$PATH"
|
||||
awk -f - -- ${@+"$@"} <<'EOF'
|
||||
#!/usr/bin/awk -f
|
||||
|
760
afl-cmin.py
760
afl-cmin.py
@ -1,760 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright 2016-2025 Google Inc.
|
||||
# Copyright 2025 AFLplusplus Project. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
import argparse
|
||||
import array
|
||||
import base64
|
||||
import collections
|
||||
import glob
|
||||
import hashlib
|
||||
import itertools
|
||||
import logging
|
||||
import multiprocessing
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
# https://more-itertools.readthedocs.io/en/stable/_modules/more_itertools/recipes.html#batched
|
||||
from sys import hexversion
|
||||
|
||||
def _batched(iterable, n, *, strict=False):
|
||||
"""Batch data into tuples of length *n*. If the number of items in
|
||||
*iterable* is not divisible by *n*:
|
||||
* The last batch will be shorter if *strict* is ``False``.
|
||||
* :exc:`ValueError` will be raised if *strict* is ``True``.
|
||||
|
||||
>>> list(batched('ABCDEFG', 3))
|
||||
[('A', 'B', 'C'), ('D', 'E', 'F'), ('G',)]
|
||||
|
||||
On Python 3.13 and above, this is an alias for :func:`itertools.batched`.
|
||||
"""
|
||||
if n < 1:
|
||||
raise ValueError('n must be at least one')
|
||||
iterator = iter(iterable)
|
||||
while batch := tuple(itertools.islice(iterator, n)):
|
||||
if strict and len(batch) != n:
|
||||
raise ValueError('batched(): incomplete batch')
|
||||
yield batch
|
||||
|
||||
|
||||
if hexversion >= 0x30D00A2: # pragma: no cover
|
||||
from itertools import batched as itertools_batched
|
||||
def batched(iterable, n, *, strict=False):
|
||||
return itertools_batched(iterable, n, strict=strict)
|
||||
else:
|
||||
batched = _batched
|
||||
|
||||
batched.__doc__ = _batched.__doc__
|
||||
|
||||
try:
|
||||
from tqdm import tqdm
|
||||
except ImportError:
|
||||
print('Hint: install python module "tqdm" to show progress bar')
|
||||
|
||||
class tqdm:
|
||||
|
||||
def __init__(self, data=None, *args, **argd):
|
||||
self.data = data
|
||||
|
||||
def __iter__(self):
|
||||
yield from self.data
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
pass
|
||||
|
||||
def update(self, *args):
|
||||
pass
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
cpu_count = multiprocessing.cpu_count()
|
||||
group = parser.add_argument_group("Required parameters")
|
||||
group.add_argument(
|
||||
"-i",
|
||||
dest="input",
|
||||
action="append",
|
||||
metavar="dir",
|
||||
required=True,
|
||||
help="input directory with the starting corpus",
|
||||
)
|
||||
group.add_argument(
|
||||
"-o",
|
||||
dest="output",
|
||||
metavar="dir",
|
||||
required=True,
|
||||
help="output directory for minimized files",
|
||||
)
|
||||
|
||||
group = parser.add_argument_group("Execution control settings")
|
||||
group.add_argument(
|
||||
"-f",
|
||||
dest="stdin_file",
|
||||
metavar="file",
|
||||
help="location read by the fuzzed program (stdin)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-m",
|
||||
dest="memory_limit",
|
||||
default="none",
|
||||
metavar="megs",
|
||||
type=lambda x: x if x == "none" else int(x),
|
||||
help="memory limit for child process (default: %(default)s)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-t",
|
||||
dest="time_limit",
|
||||
default=5000,
|
||||
metavar="msec",
|
||||
type=lambda x: x if x == "none" else int(x),
|
||||
help="timeout for each run (default: %(default)s)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-O",
|
||||
dest="frida_mode",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="use binary-only instrumentation (FRIDA mode)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-Q",
|
||||
dest="qemu_mode",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="use binary-only instrumentation (QEMU mode)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-U",
|
||||
dest="unicorn_mode",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="use unicorn-based instrumentation (Unicorn mode)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-X", dest="nyx_mode", action="store_true", default=False, help="use Nyx mode"
|
||||
)
|
||||
|
||||
group = parser.add_argument_group("Minimization settings")
|
||||
group.add_argument(
|
||||
"--crash-dir",
|
||||
dest="crash_dir",
|
||||
metavar="dir",
|
||||
default=None,
|
||||
help="move crashes to a separate dir, always deduplicated",
|
||||
)
|
||||
group.add_argument(
|
||||
"-A",
|
||||
dest="allow_any",
|
||||
action="store_true",
|
||||
help="allow crashes and timeouts (not recommended)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-C",
|
||||
dest="crash_only",
|
||||
action="store_true",
|
||||
help="keep crashing inputs, reject everything else",
|
||||
)
|
||||
group.add_argument(
|
||||
"-e",
|
||||
dest="edge_mode",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="solve for edge coverage only, ignore hit counts",
|
||||
)
|
||||
|
||||
group = parser.add_argument_group("Misc")
|
||||
group.add_argument(
|
||||
"-T",
|
||||
dest="workers",
|
||||
type=lambda x: cpu_count if x == "all" else int(x),
|
||||
default=1,
|
||||
help="number of concurrent worker (default: %(default)d)",
|
||||
)
|
||||
group.add_argument(
|
||||
"--as_queue",
|
||||
action="store_true",
|
||||
help='output file name like "id:000000,hash:value"',
|
||||
)
|
||||
group.add_argument(
|
||||
"--no-dedup", action="store_true", help="skip deduplication step for corpus files"
|
||||
)
|
||||
group.add_argument("--debug", action="store_true")
|
||||
|
||||
parser.add_argument("exe", metavar="/path/to/target_app")
|
||||
parser.add_argument("args", nargs="*")
|
||||
|
||||
args = parser.parse_args()
|
||||
logger = None
|
||||
afl_showmap_bin = None
|
||||
tuple_index_type_code = "I"
|
||||
file_index_type_code = None
|
||||
|
||||
|
||||
def init():
|
||||
global logger
|
||||
log_level = logging.DEBUG if args.debug else logging.INFO
|
||||
logging.basicConfig(
|
||||
level=log_level, format="%(asctime)s - %(levelname)s - %(message)s"
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
if args.stdin_file and args.workers > 1:
|
||||
logger.error("-f is only supported with one worker (-T 1)")
|
||||
sys.exit(1)
|
||||
|
||||
if args.memory_limit != "none" and args.memory_limit < 5:
|
||||
logger.error("dangerously low memory limit")
|
||||
sys.exit(1)
|
||||
|
||||
if args.time_limit != "none" and args.time_limit < 10:
|
||||
logger.error("dangerously low timeout")
|
||||
sys.exit(1)
|
||||
|
||||
if not os.path.isfile(args.exe):
|
||||
logger.error('binary "%s" not found or not regular file', args.exe)
|
||||
sys.exit(1)
|
||||
|
||||
if not os.environ.get("AFL_SKIP_BIN_CHECK") and not any(
|
||||
[args.qemu_mode, args.frida_mode, args.unicorn_mode, args.nyx_mode]
|
||||
):
|
||||
if b"__AFL_SHM_ID" not in open(args.exe, "rb").read():
|
||||
logger.error("binary '%s' doesn't appear to be instrumented", args.exe)
|
||||
sys.exit(1)
|
||||
|
||||
for dn in args.input:
|
||||
if not os.path.isdir(dn) and not glob.glob(dn):
|
||||
logger.error('directory "%s" not found', dn)
|
||||
sys.exit(1)
|
||||
|
||||
global afl_showmap_bin
|
||||
searches = [
|
||||
None,
|
||||
os.path.dirname(__file__),
|
||||
os.getcwd(),
|
||||
]
|
||||
if os.environ.get("AFL_PATH"):
|
||||
searches.append(os.environ["AFL_PATH"])
|
||||
|
||||
for search in searches:
|
||||
afl_showmap_bin = shutil.which("afl-showmap", path=search)
|
||||
if afl_showmap_bin:
|
||||
break
|
||||
if not afl_showmap_bin:
|
||||
logger.fatal("cannot find afl-showmap, please set AFL_PATH")
|
||||
sys.exit(1)
|
||||
|
||||
trace_dir = os.path.join(args.output, ".traces")
|
||||
shutil.rmtree(trace_dir, ignore_errors=True)
|
||||
try:
|
||||
os.rmdir(args.output)
|
||||
except OSError:
|
||||
pass
|
||||
if os.path.exists(args.output):
|
||||
logger.error(
|
||||
'directory "%s" exists and is not empty - delete it first', args.output
|
||||
)
|
||||
sys.exit(1)
|
||||
if args.crash_dir and not os.path.exists(args.crash_dir):
|
||||
os.makedirs(args.crash_dir)
|
||||
os.makedirs(trace_dir)
|
||||
|
||||
logger.info("use %d workers (-T)", args.workers)
|
||||
|
||||
|
||||
def detect_type_code(size):
|
||||
for type_code in ["B", "H", "I", "L", "Q"]:
|
||||
if 256 ** array.array(type_code).itemsize > size:
|
||||
return type_code
|
||||
|
||||
|
||||
def afl_showmap(input_path=None, batch=None, afl_map_size=None, first=False):
|
||||
assert input_path or batch
|
||||
# yapf: disable
|
||||
cmd = [
|
||||
afl_showmap_bin,
|
||||
'-m', str(args.memory_limit),
|
||||
'-t', str(args.time_limit),
|
||||
'-Z', # cmin mode
|
||||
]
|
||||
# yapf: enable
|
||||
found_atat = False
|
||||
for arg in args.args:
|
||||
if "@@" in arg:
|
||||
found_atat = True
|
||||
|
||||
if args.stdin_file:
|
||||
assert args.workers == 1
|
||||
input_from_file = True
|
||||
stdin_file = args.stdin_file
|
||||
cmd += ["-H", stdin_file]
|
||||
elif found_atat:
|
||||
input_from_file = True
|
||||
stdin_file = os.path.join(args.output, f".input.{os.getpid()}")
|
||||
cmd += ["-H", stdin_file]
|
||||
else:
|
||||
input_from_file = False
|
||||
|
||||
if batch:
|
||||
input_from_file = True
|
||||
filelist = os.path.join(args.output, f".filelist.{os.getpid()}")
|
||||
with open(filelist, "w") as f:
|
||||
for _, path in batch:
|
||||
f.write(path + "\n")
|
||||
cmd += ["-I", filelist]
|
||||
output_path = os.path.join(args.output, f".showmap.{os.getpid()}")
|
||||
cmd += ["-o", output_path]
|
||||
else:
|
||||
if input_from_file:
|
||||
shutil.copy(input_path, stdin_file)
|
||||
cmd += ["-o", "-"]
|
||||
|
||||
if args.frida_mode:
|
||||
cmd += ["-O"]
|
||||
if args.qemu_mode:
|
||||
cmd += ["-Q"]
|
||||
if args.unicorn_mode:
|
||||
cmd += ["-U"]
|
||||
if args.nyx_mode:
|
||||
cmd += ["-X"]
|
||||
if args.edge_mode:
|
||||
cmd += ["-e"]
|
||||
cmd += ["--", args.exe] + args.args
|
||||
|
||||
env = os.environ.copy()
|
||||
env["AFL_QUIET"] = "1"
|
||||
env["ASAN_OPTIONS"] = "detect_leaks=0"
|
||||
if first:
|
||||
logger.debug("run command line: %s", subprocess.list2cmdline(cmd))
|
||||
env["AFL_CMIN_ALLOW_ANY"] = "1"
|
||||
if afl_map_size:
|
||||
env["AFL_MAP_SIZE"] = str(afl_map_size)
|
||||
if args.crash_only:
|
||||
env["AFL_CMIN_CRASHES_ONLY"] = "1"
|
||||
if args.allow_any:
|
||||
env["AFL_CMIN_ALLOW_ANY"] = "1"
|
||||
|
||||
if input_from_file:
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=env, bufsize=1048576)
|
||||
else:
|
||||
p = subprocess.Popen(
|
||||
cmd,
|
||||
stdin=open(input_path, "rb"),
|
||||
stdout=subprocess.PIPE,
|
||||
env=env,
|
||||
bufsize=1048576,
|
||||
)
|
||||
out = p.stdout.read()
|
||||
p.wait()
|
||||
|
||||
if batch:
|
||||
result = []
|
||||
for idx, input_path in batch:
|
||||
basename = os.path.basename(input_path)
|
||||
values = []
|
||||
try:
|
||||
trace_file = os.path.join(output_path, basename)
|
||||
with open(trace_file, "r") as f:
|
||||
values = list(map(int, f))
|
||||
crashed = len(values) == 0
|
||||
os.unlink(trace_file)
|
||||
except FileNotFoundError:
|
||||
a = None
|
||||
crashed = True
|
||||
values = [(t // 1000) * 9 + t % 1000 for t in values]
|
||||
a = array.array(tuple_index_type_code, values)
|
||||
result.append((idx, a, crashed))
|
||||
os.unlink(filelist)
|
||||
os.rmdir(output_path)
|
||||
return result
|
||||
else:
|
||||
values = []
|
||||
for line in out.split():
|
||||
if not line.isdigit():
|
||||
continue
|
||||
values.append(int(line))
|
||||
values = [(t // 1000) * 9 + t % 1000 for t in values]
|
||||
a = array.array(tuple_index_type_code, values)
|
||||
crashed = p.returncode in [2, 3]
|
||||
if input_from_file and stdin_file != args.stdin_file:
|
||||
os.unlink(stdin_file)
|
||||
return a, crashed
|
||||
|
||||
|
||||
class JobDispatcher(multiprocessing.Process):
|
||||
|
||||
def __init__(self, job_queue, jobs):
|
||||
super().__init__()
|
||||
self.job_queue = job_queue
|
||||
self.jobs = jobs
|
||||
|
||||
def run(self):
|
||||
for job in self.jobs:
|
||||
self.job_queue.put(job)
|
||||
self.job_queue.close()
|
||||
|
||||
|
||||
class Worker(multiprocessing.Process):
|
||||
|
||||
def __init__(self, idx, afl_map_size, q_in, p_out, r_out):
|
||||
super().__init__()
|
||||
self.idx = idx
|
||||
self.afl_map_size = afl_map_size
|
||||
self.q_in = q_in
|
||||
self.p_out = p_out
|
||||
self.r_out = r_out
|
||||
|
||||
def run(self):
|
||||
map_size = self.afl_map_size or 65536
|
||||
max_tuple = map_size * 9
|
||||
max_file_index = 256 ** array.array(file_index_type_code).itemsize - 1
|
||||
m = array.array(file_index_type_code, [max_file_index] * max_tuple)
|
||||
counter = collections.Counter()
|
||||
crashes = []
|
||||
|
||||
pack_name = os.path.join(args.output, ".traces", f"{self.idx}.pack")
|
||||
pack_pos = 0
|
||||
with open(pack_name, "wb") as trace_pack:
|
||||
while True:
|
||||
batch = self.q_in.get()
|
||||
if batch is None:
|
||||
break
|
||||
|
||||
for idx, r, crash in afl_showmap(
|
||||
batch=batch, afl_map_size=self.afl_map_size
|
||||
):
|
||||
counter.update(r)
|
||||
|
||||
used = False
|
||||
|
||||
if crash:
|
||||
crashes.append(idx)
|
||||
|
||||
# If we aren't saving crashes to a separate dir, handle them
|
||||
# the same as other inputs. However, unless AFL_CMIN_ALLOW_ANY=1,
|
||||
# afl_showmap will not return any coverage for crashes so they will
|
||||
# never be retained.
|
||||
if not crash or not args.crash_dir:
|
||||
for t in r:
|
||||
if idx < m[t]:
|
||||
m[t] = idx
|
||||
used = True
|
||||
|
||||
if used:
|
||||
tuple_count = len(r)
|
||||
r.tofile(trace_pack)
|
||||
self.p_out.put((idx, self.idx, pack_pos, tuple_count))
|
||||
pack_pos += tuple_count * r.itemsize
|
||||
else:
|
||||
self.p_out.put(None)
|
||||
|
||||
self.r_out.put((self.idx, m, counter, crashes))
|
||||
|
||||
|
||||
class CombineTraceWorker(multiprocessing.Process):
|
||||
|
||||
def __init__(self, pack_name, jobs, r_out):
|
||||
super().__init__()
|
||||
self.pack_name = pack_name
|
||||
self.jobs = jobs
|
||||
self.r_out = r_out
|
||||
|
||||
def run(self):
|
||||
already_have = set()
|
||||
with open(self.pack_name, "rb") as f:
|
||||
for pos, tuple_count in self.jobs:
|
||||
f.seek(pos)
|
||||
result = array.array(tuple_index_type_code)
|
||||
result.fromfile(f, tuple_count)
|
||||
already_have.update(result)
|
||||
self.r_out.put(already_have)
|
||||
|
||||
|
||||
def hash_file(path):
|
||||
m = hashlib.sha1()
|
||||
with open(path, "rb") as f:
|
||||
m.update(f.read())
|
||||
return m.digest()
|
||||
|
||||
|
||||
def dedup(files):
|
||||
with multiprocessing.Pool(args.workers) as pool:
|
||||
seen_hash = set()
|
||||
result = []
|
||||
hash_list = []
|
||||
# use large chunksize to reduce multiprocessing overhead
|
||||
chunksize = max(1, min(256, len(files) // args.workers))
|
||||
for i, h in enumerate(
|
||||
tqdm(
|
||||
pool.imap(hash_file, files, chunksize),
|
||||
desc="dedup",
|
||||
total=len(files),
|
||||
ncols=0,
|
||||
leave=(len(files) > 100000),
|
||||
)
|
||||
):
|
||||
if h in seen_hash:
|
||||
continue
|
||||
seen_hash.add(h)
|
||||
result.append(files[i])
|
||||
hash_list.append(h)
|
||||
return result, hash_list
|
||||
|
||||
|
||||
def is_afl_dir(dirnames, filenames):
|
||||
return (
|
||||
"queue" in dirnames
|
||||
and "hangs" in dirnames
|
||||
and "crashes" in dirnames
|
||||
and "fuzzer_setup" in filenames
|
||||
)
|
||||
|
||||
|
||||
def collect_files(input_paths):
|
||||
paths = []
|
||||
for s in input_paths:
|
||||
paths += glob.glob(s)
|
||||
|
||||
files = []
|
||||
with tqdm(desc="search", unit=" files", ncols=0) as pbar:
|
||||
for path in paths:
|
||||
for root, dirnames, filenames in os.walk(path, followlinks=True):
|
||||
for dirname in dirnames:
|
||||
if dirname.startswith("."):
|
||||
dirnames.remove(dirname)
|
||||
|
||||
if not args.crash_only and is_afl_dir(dirnames, filenames):
|
||||
continue
|
||||
|
||||
for filename in filenames:
|
||||
if filename.startswith("."):
|
||||
continue
|
||||
pbar.update(1)
|
||||
files.append(os.path.join(root, filename))
|
||||
return files
|
||||
|
||||
|
||||
def main():
|
||||
init()
|
||||
|
||||
files = collect_files(args.input)
|
||||
if len(files) == 0:
|
||||
logger.error("no inputs in the target directory - nothing to be done")
|
||||
sys.exit(1)
|
||||
logger.info("Found %d input files in %d directories", len(files), len(args.input))
|
||||
|
||||
if not args.no_dedup:
|
||||
files, hash_list = dedup(files)
|
||||
logger.info("Remain %d files after dedup", len(files))
|
||||
else:
|
||||
logger.info("Skipping file deduplication.")
|
||||
|
||||
global file_index_type_code
|
||||
file_index_type_code = detect_type_code(len(files))
|
||||
|
||||
logger.info("Sorting files.")
|
||||
with multiprocessing.Pool(args.workers) as pool:
|
||||
chunksize = max(1, min(512, len(files) // args.workers))
|
||||
size_list = list(pool.map(os.path.getsize, files, chunksize))
|
||||
idxes = sorted(range(len(files)), key=lambda x: size_list[x])
|
||||
files = [files[idx] for idx in idxes]
|
||||
hash_list = [hash_list[idx] for idx in idxes]
|
||||
|
||||
afl_map_size = None
|
||||
if b"AFL_DUMP_MAP_SIZE" in open(args.exe, "rb").read():
|
||||
output = subprocess.run(
|
||||
[args.exe], capture_output=True, env={"AFL_DUMP_MAP_SIZE": "1", "ASAN_OPTIONS": "detect_leaks=0"}
|
||||
).stdout
|
||||
afl_map_size = int(output)
|
||||
logger.info("Setting AFL_MAP_SIZE=%d", afl_map_size)
|
||||
|
||||
global tuple_index_type_code
|
||||
tuple_index_type_code = detect_type_code(afl_map_size * 9)
|
||||
|
||||
logger.info("Testing the target binary")
|
||||
tuples, _ = afl_showmap(files[0], afl_map_size=afl_map_size, first=True)
|
||||
if tuples:
|
||||
logger.info("ok, %d tuples recorded", len(tuples))
|
||||
else:
|
||||
logger.error("no instrumentation output detected")
|
||||
sys.exit(1)
|
||||
|
||||
job_queue = multiprocessing.Queue()
|
||||
progress_queue = multiprocessing.Queue()
|
||||
result_queue = multiprocessing.Queue()
|
||||
|
||||
workers = []
|
||||
for i in range(args.workers):
|
||||
p = Worker(i, afl_map_size, job_queue, progress_queue, result_queue)
|
||||
p.start()
|
||||
workers.append(p)
|
||||
|
||||
chunk = max(1, min(128, len(files) // args.workers))
|
||||
jobs = list(batched(enumerate(files), chunk))
|
||||
jobs += [None] * args.workers # sentinel
|
||||
|
||||
dispatcher = JobDispatcher(job_queue, jobs)
|
||||
dispatcher.start()
|
||||
|
||||
logger.info("Processing traces")
|
||||
effective = 0
|
||||
trace_info = {}
|
||||
for _ in tqdm(files, ncols=0, smoothing=0.01):
|
||||
r = progress_queue.get()
|
||||
if r is not None:
|
||||
idx, worker_idx, pos, tuple_count = r
|
||||
trace_info[idx] = worker_idx, pos, tuple_count
|
||||
effective += 1
|
||||
dispatcher.join()
|
||||
|
||||
logger.info("Obtaining trace results")
|
||||
ms = []
|
||||
crashes = []
|
||||
counter = collections.Counter()
|
||||
for _ in tqdm(range(args.workers), ncols=0):
|
||||
idx, m, c, crs = result_queue.get()
|
||||
ms.append(m)
|
||||
counter.update(c)
|
||||
crashes.extend(crs)
|
||||
workers[idx].join()
|
||||
best_idxes = list(map(min, zip(*ms)))
|
||||
|
||||
if not args.crash_dir:
|
||||
logger.info(
|
||||
"Found %d unique tuples across %d files (%d effective)",
|
||||
len(counter),
|
||||
len(files),
|
||||
effective,
|
||||
)
|
||||
else:
|
||||
logger.info(
|
||||
"Found %d unique tuples across %d files (%d effective, %d crashes)",
|
||||
len(counter),
|
||||
len(files),
|
||||
effective,
|
||||
len(crashes),
|
||||
)
|
||||
all_unique = counter.most_common()
|
||||
|
||||
logger.info("Processing candidates and writing output")
|
||||
already_have = set()
|
||||
count = 0
|
||||
|
||||
def save_file(idx):
|
||||
input_path = files[idx]
|
||||
fn = (
|
||||
base64.b16encode(hash_list[idx]).decode("utf8").lower()
|
||||
if not args.no_dedup
|
||||
else os.path.basename(input_path)
|
||||
)
|
||||
if args.as_queue:
|
||||
if args.no_dedup:
|
||||
fn = "id:%06d,orig:%s" % (count, fn)
|
||||
else:
|
||||
fn = "id:%06d,hash:%s" % (count, fn)
|
||||
output_path = os.path.join(args.output, fn)
|
||||
try:
|
||||
os.link(input_path, output_path)
|
||||
except OSError:
|
||||
shutil.copy(input_path, output_path)
|
||||
|
||||
jobs = [[] for i in range(args.workers)]
|
||||
saved = set()
|
||||
for t, c in all_unique:
|
||||
if c != 1:
|
||||
continue
|
||||
idx = best_idxes[t]
|
||||
if idx in saved:
|
||||
continue
|
||||
save_file(idx)
|
||||
saved.add(idx)
|
||||
count += 1
|
||||
|
||||
worker_idx, pos, tuple_count = trace_info[idx]
|
||||
job = (pos, tuple_count)
|
||||
jobs[worker_idx].append(job)
|
||||
|
||||
trace_packs = []
|
||||
workers = []
|
||||
for i in range(args.workers):
|
||||
pack_name = os.path.join(args.output, ".traces", f"{i}.pack")
|
||||
trace_f = open(pack_name, "rb")
|
||||
trace_packs.append(trace_f)
|
||||
|
||||
p = CombineTraceWorker(pack_name, jobs[i], result_queue)
|
||||
p.start()
|
||||
workers.append(p)
|
||||
|
||||
for _ in range(args.workers):
|
||||
result = result_queue.get()
|
||||
already_have.update(result)
|
||||
|
||||
for t, c in tqdm(list(reversed(all_unique)), ncols=0):
|
||||
if t in already_have:
|
||||
continue
|
||||
|
||||
idx = best_idxes[t]
|
||||
save_file(idx)
|
||||
count += 1
|
||||
|
||||
worker_idx, pos, tuple_count = trace_info[idx]
|
||||
trace_pack = trace_packs[worker_idx]
|
||||
trace_pack.seek(pos)
|
||||
result = array.array(tuple_index_type_code)
|
||||
result.fromfile(trace_pack, tuple_count)
|
||||
|
||||
already_have.update(result)
|
||||
|
||||
for f in trace_packs:
|
||||
f.close()
|
||||
|
||||
if args.crash_dir:
|
||||
logger.info("Saving crashes to %s", args.crash_dir)
|
||||
crash_files = [files[c] for c in crashes]
|
||||
|
||||
if args.no_dedup:
|
||||
# Unless we deduped previously, we have to dedup the crash files
|
||||
# now.
|
||||
crash_files, hash_list = dedup(crash_files)
|
||||
|
||||
for idx, crash_path in enumerate(crash_files):
|
||||
fn = base64.b16encode(hash_list[idx]).decode("utf8").lower()
|
||||
output_path = os.path.join(args.crash_dir, fn)
|
||||
try:
|
||||
os.link(crash_path, output_path)
|
||||
except OSError:
|
||||
try:
|
||||
shutil.copy(crash_path, output_path)
|
||||
except shutil.Error:
|
||||
# This error happens when src and dest are hardlinks of the
|
||||
# same file. We have nothing to do in this case, but handle
|
||||
# it gracefully.
|
||||
pass
|
||||
|
||||
if count == 1:
|
||||
logger.warning("all test cases had the same traces, check syntax!")
|
||||
logger.info('narrowed down to %s files, saved in "%s"', count, args.output)
|
||||
if not os.environ.get("AFL_KEEP_TRACES"):
|
||||
logger.info("Deleting trace files")
|
||||
trace_dir = os.path.join(args.output, ".traces")
|
||||
shutil.rmtree(trace_dir, ignore_errors=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -4,7 +4,7 @@ CFLAGS = -O3 -funroll-loops -fPIC
|
||||
all: aflpp-standalone
|
||||
|
||||
aflpp-standalone: aflpp-standalone.c
|
||||
$(CC) $(CFLAGS) -w -DBIN_PATH=\"foo\" -I../../../include -I. -o aflpp-standalone aflpp-standalone.c ../../../src/afl-performance.c ../../../src/afl-fuzz-extras.c ../../../src/afl-common.c
|
||||
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -o aflpp-standalone aflpp-standalone.c ../../../src/afl-performance.c ../../../src/afl-fuzz-extras.c ../../../src/afl-common.c
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ aflpp-standalone core
|
||||
|
@ -1,20 +1,19 @@
|
||||
|
||||
CFLAGS = -g -O3 -funroll-loops -fPIC -D_STANDALONE_MODULE=1 -Wno-pointer-sign
|
||||
CFLAGS = -g -O3 -funroll-loops -fPIC -D_STANDALONE_MODULE=1 -Wno-implicit-function-declaration
|
||||
CXXFLAGS= -g -O3 -funroll-loops -fPIC -D_STANDALONE_MODULE=1
|
||||
|
||||
all: autotokens-standalone
|
||||
|
||||
autotokens.o: ../autotokens.cpp
|
||||
$(CXX) $(CXXFLAGS) -g -I../../../include -I. -I../.. -c ../autotokens.cpp
|
||||
$(CXX) $(CXXFLAGS) -I../../../include -I. -I../.. -c ../autotokens.cpp
|
||||
|
||||
autotokens-standalone: autotokens-standalone.c autotokens.o
|
||||
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c autotokens-standalone.c
|
||||
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-performance.c
|
||||
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-fuzz-extras.c
|
||||
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-fuzz-queue.c
|
||||
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-common.c
|
||||
$(CXX) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -o autotokens-standalone *.o
|
||||
@rm -f ../../../src/afl-common.o ../../../src/afl-fuzz-queue.o ../../../src/afl-fuzz-extras.o ../../../src/afl-performance.o
|
||||
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c autotokens-standalone.c
|
||||
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-performance.c
|
||||
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-fuzz-extras.c
|
||||
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-fuzz-queue.c
|
||||
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-common.c
|
||||
$(CXX) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -o autotokens-standalone *.o
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ autotokens-standalone core
|
||||
|
@ -1,28 +1,15 @@
|
||||
#include "afl-fuzz.h"
|
||||
#include "afl-mutations.h"
|
||||
#include "forkserver.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
|
||||
static int max_havoc = 16, verbose;
|
||||
static char _mh[4] = "16";
|
||||
static char *dict, *mh = _mh;
|
||||
static unsigned char *dict, *mh = "16";
|
||||
|
||||
extern int module_disabled;
|
||||
|
||||
void *afl_custom_init(afl_state_t *, unsigned int);
|
||||
u8 afl_custom_queue_get(void *data, const u8 *filename);
|
||||
size_t afl_custom_fuzz(void *data, u8 *buf, size_t buf_size, u8 **out_buf,
|
||||
u8 *add_buf, size_t add_buf_size, size_t max_size);
|
||||
|
||||
u32 write_to_testcase(afl_state_t *afl, void **mem, u32 a, u32 b) {
|
||||
return 0;
|
||||
}
|
||||
fsrv_run_result_t fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv,
|
||||
u32 i) {
|
||||
return FSRV_RUN_OK;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
@ -157,7 +144,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
if (dict) {
|
||||
|
||||
load_extras(afl, (u8*)dict);
|
||||
load_extras(afl, dict);
|
||||
if (verbose)
|
||||
fprintf(stderr, "Loaded dictionary: %s (%u entries)\n", dict,
|
||||
afl->extras_cnt);
|
||||
|
@ -3,7 +3,8 @@
|
||||
These are example and helper files for the custom mutator feature.
|
||||
See [docs/custom_mutators.md](../../docs/custom_mutators.md) for more information
|
||||
|
||||
Note that if you compile with python3.7 you must use python3 scripts.
|
||||
Note that if you compile with python3.7 you must use python3 scripts, and if
|
||||
you use python2.7 to compile python2 scripts!
|
||||
|
||||
simple_example.c - most simplest example. generates a random sized buffer
|
||||
filled with 'A'
|
||||
|
@ -56,7 +56,7 @@ if [ ! -f "../../src/afl-performance.o" ]; then
|
||||
|
||||
fi
|
||||
|
||||
PYTHONBIN=`command -v python3 || command -v python || echo python3`
|
||||
PYTHONBIN=`command -v python3 || command -v python || command -v python2 || echo python3`
|
||||
MAKECMD=make
|
||||
TARCMD=tar
|
||||
|
||||
|
@ -52,7 +52,7 @@ if [ ! -f "../../config.h" ]; then
|
||||
|
||||
fi
|
||||
|
||||
PYTHONBIN=`command -v python3 || command -v python || echo python3`
|
||||
PYTHONBIN=`command -v python3 || command -v python || command -v python2 || echo python3`
|
||||
MAKECMD=make
|
||||
TARCMD=tar
|
||||
|
||||
|
@ -3,36 +3,6 @@
|
||||
This is the list of all noteworthy changes made in every public
|
||||
release of the tool. See README.md for the general instruction manual.
|
||||
|
||||
|
||||
### Version ++4.33a (dev)
|
||||
- afl-fuzz:
|
||||
- Use `AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT` if you use AFL_PRELOAD
|
||||
to disable fork, see docs (thanks to @alexandredoyen29)
|
||||
- Fix for FAST power schedules (introduced in 4.32c) (thanks to @kcwu)
|
||||
- Colors for NO_UI output (thanks to @smoelius)
|
||||
- Fix potential sync issues when resuming sessions and when instances in a
|
||||
campaign are restarted and skip entries that were synced from itself
|
||||
(thanks to @kcwu for raising the issues and providing support!)
|
||||
- more 64 bit archicture support by @maribu
|
||||
- afl-cc:
|
||||
- Added instrumenting hidden edges (approx 5% edges were not instrumented,
|
||||
LLVM sancov overall misses 8% of edges compared to our implementation)
|
||||
Note that is is currently only implemented for our PCGUARD plugin, not
|
||||
LTO, CLASSIC, etc.!
|
||||
- Fix to make AFL_SAN_NO_INST work with gcc_plugin
|
||||
- MacOS aflpp driver compilation fix (-fsanitize=fuzzer implementation)
|
||||
- Make AFL_DUMP_MAP_SIZE work even if the target has sanitizer issues
|
||||
- qemuafl:
|
||||
- Better MIPS persistent mode support
|
||||
- `AFL_EXITPOINT` support added
|
||||
- `AFL_QEMU_BLOCK_COV` block coverage support added
|
||||
- afl-cmin:
|
||||
- New afl-cmin.py which is much faster, will be executed by default via
|
||||
afl-cmin if it executes successfully (thanks to @kcwu!)
|
||||
- New desocketing library: utils/libaflppdesock
|
||||
- Likely works when all other desocketing options fail
|
||||
|
||||
|
||||
### Version ++4.32c (release)
|
||||
- Fixed a bug where after a fast restart of a full fuzzed corpus afl-fuzz
|
||||
terminates with "need at least one valid input seed that does not crash"
|
||||
@ -52,6 +22,7 @@
|
||||
- frida_mode:
|
||||
- fixes for new MacOS + M4 hardware
|
||||
|
||||
|
||||
### Version ++4.31c (release)
|
||||
- SAND mode added (docs/SAND.md) for more effecient fuzzing with sanitizers
|
||||
(thanks to @wtdcode !)
|
||||
|
12
docs/FAQ.md
12
docs/FAQ.md
@ -11,7 +11,7 @@ If you find an interesting or important question missing, submit it via
|
||||
AFL++ is a superior fork to Google's AFL - more speed, more and better
|
||||
mutations, more and better instrumentation, custom module support, etc.
|
||||
|
||||
American Fuzzy Lop (AFL) was developed by Michal "lcamtuf" Zalewski starting
|
||||
American Fuzzy Lop (AFL) was developed by Michał "lcamtuf" Zalewski starting
|
||||
in 2013/2014, and when he left Google end of 2017 he stopped developing it.
|
||||
|
||||
At the end of 2019, the Google fuzzing team took over maintenance of AFL,
|
||||
@ -284,14 +284,14 @@ If you find an interesting or important question missing, submit it via
|
||||
afl-cc/afl-clang-fast/afl-clang-lto:
|
||||
|
||||
```
|
||||
/prg/tmp/llvm-project/build/bin/clang-18: symbol lookup error: /usr/local/bin/../lib/afl//cmplog-instructions-pass.so: undefined symbol: _ZNK4llvm8TypeSizecvmEv
|
||||
clang-18: error: unable to execute command: No such file or directory
|
||||
clang-18: error: clang frontend command failed due to signal (use -v to see invocation)
|
||||
clang version 18.0.0 (https://github.com/llvm/llvm-project 1d7cf550721c51030144f3cd295c5789d51c4aad)
|
||||
/prg/tmp/llvm-project/build/bin/clang-13: symbol lookup error: /usr/local/bin/../lib/afl//cmplog-instructions-pass.so: undefined symbol: _ZNK4llvm8TypeSizecvmEv
|
||||
clang-13: error: unable to execute command: No such file or directory
|
||||
clang-13: error: clang frontend command failed due to signal (use -v to see invocation)
|
||||
clang version 13.0.0 (https://github.com/llvm/llvm-project 1d7cf550721c51030144f3cd295c5789d51c4aad)
|
||||
Target: x86_64-unknown-linux-gnu
|
||||
Thread model: posix
|
||||
InstalledDir: /prg/tmp/llvm-project/build/bin
|
||||
clang-18: note: diagnostic msg:
|
||||
clang-13: note: diagnostic msg:
|
||||
********************
|
||||
```
|
||||
|
||||
|
@ -21,7 +21,7 @@ If you want to build AFL++ yourself, you have many options. The easiest choice
|
||||
is to build and install everything:
|
||||
|
||||
NOTE: depending on your Debian/Ubuntu/Kali/... release, replace `-14` with
|
||||
whatever llvm version is available. We recommend llvm 14 or newer.
|
||||
whatever llvm version is available. We recommend llvm 13 or newer.
|
||||
|
||||
```shell
|
||||
sudo apt-get update
|
||||
|
@ -21,7 +21,7 @@ For a normal fuzzing workflow, we have:
|
||||
For SAND fuzzing workflow, this is slightly different:
|
||||
|
||||
1. Build target project _without_ any sanitizers to get `target_native`, which we will define as a "native binary". It is usually done by using `afl-clang-fast/lto(++)` to compile your project _without_ `AFL_USE_ASAN/UBSAN/MSAN`.
|
||||
2. Build target project with AFL_USE_ASAN=1 AFL_LLVM_ONLY_FSRV=1 to get `target_asan`. Do note this step can be repeated for multiple sanitizers, like MSAN, UBSAN etc. It is also possible to have ASAN and UBSAN to build together.
|
||||
2. Build target project with AFL_USE_ASAN=1 AFL_SAN_NO_INST=1 to get `target_asan`. Do note this step can be repeated for multiple sanitizers, like MSAN, UBSAN etc. It is also possible to have ASAN and UBSAN to build together.
|
||||
3. Fuzz the target with `afl-fuzz -i seeds -o out -w ./target_asan -- ./target_native`. Note `-w` can be specified multiple times.
|
||||
|
||||
Then you get:
|
||||
@ -44,11 +44,11 @@ Just like the normal building process, except using `afl-clang-fast`
|
||||
2. Build the sanitizers-enabled binaries.
|
||||
|
||||
```bash
|
||||
AFL_LLVM_ONLY_FSRV=1 AFL_USE_UBSAN=1 AFL_USE_ASAN=1 afl-clang-fast test-instr.c -o ./asanubsan
|
||||
AFL_LLVM_ONLY_FSRV=1 AFL_USE_MSAN=1 afl-clang-fast test-instr.c -o ./msan
|
||||
AFL_SAN_NO_INST=1 AFL_USE_UBSAN=1 AFL_USE_ASAN=1 afl-clang-fast test-instr.c -o ./asanubsan
|
||||
AFL_SAN_NO_INST=1 AFL_USE_MSAN=1 afl-clang-fast test-instr.c -o ./msan
|
||||
```
|
||||
|
||||
Do note `AFL_LLVM_ONLY_FSRV=1` is crucial, this enables forkservers but disables pc instrumentation. You are allowed to reuse sanitizers-enabled binaries, i.e. binaries built _without_ `AFL_LLVM_ONLY_FSRV=1`, at a cost of reduced speed.
|
||||
Do note `AFL_SAN_NO_INST=1` is crucial, this enables forkservers but disables pc instrumentation. Do not reuse sanitizers-enabled binaries built _without_ `AFL_SAN_NO_INST=1`. This will mess up SAND execution pattern.
|
||||
|
||||
3. Start fuzzing
|
||||
|
||||
|
@ -111,10 +111,6 @@ fairly broad use of environment variables instead:
|
||||
|
||||
- Note: both `AFL_CFISAN_VERBOSE=1` and `AFL_UBSAN_VERBOSE=1` are disabled by default as verbose output can significantly slow down fuzzing performance. Use these options only during debugging or when additional crash diagnostics are required
|
||||
|
||||
- `AFL_LLVM_ONLY_FSRV`/`AFL_GCC_ONLY_FSRV` will inject forkserver but not pc instrumentation. Please note this is different compared to `AFL_LLVM_DISABLE_INSTRUMENTATION`, which will totally disable forkserver implementation. This env is pretty useful in two cases:
|
||||
- [SAND](./SAND.md). In this case, the binaries built in this way will serve as extra oracles. Check the corresponding documents for details.
|
||||
- Compatible with LibAFL ForkserverExecutor implementation and thus faster to repeatedly run, compared to simple CommandExecutor.
|
||||
|
||||
- `TMPDIR` is used by afl-as for temporary files; if this variable is not set,
|
||||
the tool defaults to /tmp.
|
||||
|
||||
@ -668,41 +664,6 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
Note that will not be exact and with slow targets it can take seconds
|
||||
until there is a slice for the time test.
|
||||
|
||||
- When using `AFL_PRELOAD` with a preload that disable `fork()` calls in
|
||||
the target, the forkserver becomes unable to fork.
|
||||
To overcome this issue, the `AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT`
|
||||
permits to be able to check in the preloaded library if the environment
|
||||
variable `AFL_FORKSERVER_PARENT` is set, to be able to use vanilla
|
||||
`fork()` in the forkserver, and the placeholder in the target.
|
||||
Here is a POC :
|
||||
```C
|
||||
// AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT=1 afl-fuzz ...
|
||||
pid_t fork(void)
|
||||
{
|
||||
if (getenv("AFL_FORKSERVER_PARENT") == NULL)
|
||||
return 0; // We are in the target
|
||||
else
|
||||
return real_fork(); // We are in the forkserver
|
||||
}
|
||||
```
|
||||
|
||||
- `AFL_FORKSRV_UID` allows you to specify the UID that should be used when
|
||||
running the fork server. When setting this variable, user should ensure
|
||||
afl-fuzz binary has enough privileges to modify the UID (e.g. CAP\_SETUID
|
||||
capability in Linux system).
|
||||
|
||||
- `AFL_FORKSRV_GID` allows you to specify the GID and the supplementary group
|
||||
IDs that should be used when running the fork server. When setting this
|
||||
variable, user should ensure afl-fuzz binary has enough privileges to
|
||||
modify the GIDs (e.g. CAP\_SETGID capability in Linux system).
|
||||
|
||||
- When both `AFL_FORKSRV_UID` and `AFL_FORKSRV_GID` are set, afl-fuzz binary
|
||||
and the fork server no longer share any IDs. Thus, afl-fuzz binary changes
|
||||
the group owner of the created files to ensure that the fork server can
|
||||
still access them. In such case, user should ensure afl-fuzz binary has
|
||||
enough privileges to modify the ownership of entities (e.g. CAP\_CHOWN
|
||||
capability in Linux system).
|
||||
|
||||
## 6) Settings for afl-qemu-trace
|
||||
|
||||
The QEMU wrapper used to instrument binary-only code supports several settings:
|
||||
@ -741,10 +702,6 @@ The QEMU wrapper used to instrument binary-only code supports several settings:
|
||||
of the basic blocks, which can be useful when dealing with very complex
|
||||
binaries.
|
||||
|
||||
- You can switch to block coverage that has less chances of colliding (but
|
||||
on the other hand coverage is on blocks, not edges) with
|
||||
`AFL_QEMU_BLOCK_COV`.
|
||||
|
||||
- Setting `AFL_QEMU_COMPCOV` enables the CompareCoverage tracing of all cmp
|
||||
and sub in x86 and x86_64. This is an alias of `AFL_COMPCOV_LEVEL=1` when
|
||||
`AFL_COMPCOV_LEVEL` is not specified.
|
||||
|
@ -45,7 +45,7 @@ E. CmpLog is our enhanced
|
||||
implementation, see
|
||||
[instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md)
|
||||
|
||||
F. Similar and compatible to clang 14+ sancov sanitize-coverage-allow/deny but
|
||||
F. Similar and compatible to clang 13+ sancov sanitize-coverage-allow/deny but
|
||||
for all llvm versions and all our compile modes, only instrument what should
|
||||
be instrumented, for more speed, directed fuzzing and less instability; see
|
||||
[instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md)
|
||||
|
@ -16,8 +16,7 @@ FRIDA mode and QEMU mode in persistent mode are the fastest - if persistent mode
|
||||
is possible and the stability is high enough.
|
||||
|
||||
Otherwise, try Zafl, RetroWrite, Dyninst, and if these fail, too, then try
|
||||
standard FRIDA/QEMU mode with `AFL_ENTRYPOINT` + `AFL_EXITPOINT` to where you
|
||||
need it.
|
||||
standard FRIDA/QEMU mode with `AFL_ENTRYPOINT` to where you need it.
|
||||
|
||||
If your target is non-linux, then use unicorn_mode.
|
||||
|
||||
|
@ -132,15 +132,11 @@ options are available:
|
||||
locations. This technique is very fast and good - if the target does not
|
||||
transform input data before comparison. Therefore, this technique is called
|
||||
`input to state` or `redqueen`. If you want to use this technique, then you
|
||||
have to compile the target with `AFL_LLVM_CMPLOG=1`.
|
||||
You could use the resulting binary for both normal fuzzing and `-c` CMPLOG
|
||||
mode (with `-c 0`), however this will result in a performance loss of about
|
||||
20%.
|
||||
It is therefore better to compile a specific CMPLOG target with
|
||||
`AFL_LLVM_ONLY_FSRV=1 AFL_LLVM_CMPLOG=1` and pass this binary name via
|
||||
`-c cmplog-fuzzing-target` and compile target again normally with `afl-cc`
|
||||
and use this is the fuzzing target as usual.
|
||||
You can read more about this in
|
||||
have to compile the target twice, once specifically with/for this mode by
|
||||
setting `AFL_LLVM_CMPLOG=1`, and pass this binary to afl-fuzz via the `-c`
|
||||
parameter. Note that you can compile also just a cmplog binary and use that
|
||||
for both, however, there will be a performance penalty. You can read more
|
||||
about this in
|
||||
[instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md).
|
||||
|
||||
If you use LTO, LLVM, or GCC_PLUGIN mode
|
||||
@ -869,13 +865,10 @@ Here are some of the most important caveats for AFL++:
|
||||
|
||||
- There is no direct support for fuzzing network services, background daemons,
|
||||
or interactive apps that require UI interaction to work. You may need to make
|
||||
simple code changes to make them behave in a more traditional way. Preeny,
|
||||
libdesock or desockmulti may offer a relatively simple option, too - see:
|
||||
simple code changes to make them behave in a more traditional way. Preeny or
|
||||
libdesock may offer a relatively simple option, too - see:
|
||||
[https://github.com/zardus/preeny](https://github.com/zardus/preeny) or
|
||||
[https://github.com/fkie-cad/libdesock](https://github.com/fkie-cad/libdesock)
|
||||
[https://github.com/zyingp/desockmulti](https://github.com/zyingp/desockmulti)
|
||||
If these fail then try our own which might be a bit slower but is more
|
||||
reliable: [utils/libaflppdesock](../utils/libaflppdesock)
|
||||
|
||||
Some useful tips for modifying network-based services can be also found at:
|
||||
[https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop](https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop)
|
||||
|
@ -15,7 +15,6 @@ JS_OBJ:=$(BUILD_DIR)api.o
|
||||
SOURCES:=$(wildcard $(SRC_DIR)**/*.c) $(wildcard $(SRC_DIR)*.c)
|
||||
OBJS:=$(foreach src,$(SOURCES),$(OBJ_DIR)$(notdir $(patsubst %.c, %.o, $(src))))
|
||||
|
||||
XTOOLS_HOST?=x86_64-linux-gnu
|
||||
TARGET_CC?=$(CC)
|
||||
TARGET_CXX?=$(CXX)
|
||||
HOST_CC?=$(CC)
|
||||
@ -187,13 +186,39 @@ ifndef OS
|
||||
$(error "Operating system unsupported")
|
||||
endif
|
||||
|
||||
GUM_DEVKIT_VERSION=17.0.7
|
||||
GUM_DEVKIT_VERSION=16.1.11
|
||||
GUM_DEVKIT_FILENAME=frida-gumjs-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar.xz
|
||||
GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(GUM_DEVKIT_VERSION)/$(GUM_DEVKIT_FILENAME)"
|
||||
|
||||
ifeq ($(OS),macos)
|
||||
# Extract the major version
|
||||
GUM_VERSION_MAJOR := $(shell echo "$(GUM_DEVKIT_VERSION)" | sed -E 's/\..*//')
|
||||
# Extract the minor version (assumes format "MAJOR.MINOR[.PATCH...]")
|
||||
GUM_VERSION_MINOR := $(shell echo "$(GUM_DEVKIT_VERSION)" | sed -E 's/^[^.]*\.//; s/\..*//')
|
||||
|
||||
# Evaluate the version condition in a separate shell call
|
||||
IS_GUM_16_6_PLUS := $(shell \
|
||||
if (( $(GUM_VERSION_MAJOR) > 16 || ( $(GUM_VERSION_MAJOR) == 16 && $(GUM_VERSION_MINOR) >= 6 ) )); then \
|
||||
echo 1; \
|
||||
fi)
|
||||
else
|
||||
IS_GUM_16_6_PLUS := $(shell VERSION="$(GUM_DEVKIT_VERSION)"; \
|
||||
MAJOR=$${VERSION%%.*}; \
|
||||
MINOR=$${VERSION#*.}; MINOR=$${MINOR%%.*}; \
|
||||
if [ $$MAJOR -gt 16 ] || { [ $$MAJOR -eq 16 ] && [ $$MINOR -ge 6 ]; }; then \
|
||||
echo 1; \
|
||||
fi)
|
||||
endif
|
||||
|
||||
CFLAGS += $(if $(IS_GUM_16_6_PLUS),-DGUM_16_6_PLUS)
|
||||
|
||||
GUM_DEVKIT_TARBALL:=$(FRIDA_BUILD_DIR)$(GUM_DEVKIT_FILENAME)
|
||||
GUM_DEVIT_HEADER=$(FRIDA_BUILD_DIR)frida-gumjs.h
|
||||
ifdef FRIDA_SOURCE
|
||||
GUM_DEVIT_LIBRARY=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gumjs-1.0.a
|
||||
else
|
||||
GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gumjs.a
|
||||
endif
|
||||
GUM_DEVIT_HEADER=$(FRIDA_BUILD_DIR)frida-gumjs.h
|
||||
|
||||
FRIDA_DIR:=$(PWD)build/frida-source/
|
||||
FRIDA_MAKEFILE:=$(FRIDA_DIR)Makefile
|
||||
@ -227,13 +252,13 @@ BIN2C_SRC:=$(PWD)util/bin2c.c
|
||||
all: $(FRIDA_TRACE) $(FRIDA_TRACE_LIB) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_QEMU_DRIVER_HOOK_OBJ) $(ADDR_BIN)
|
||||
|
||||
32:
|
||||
XTOOLS_HOST=i686-linux-gnu CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
|
||||
CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
|
||||
|
||||
arm:
|
||||
XTOOLS_HOST=arm-linux-gnueabihf CFLAGS="-marm" LDFLAGS="-marm" ARCH="armhf" TARGET_CC=arm-linux-gnueabihf-gcc TARGET_CXX=arm-linux-gnueabihf-g++ make all
|
||||
CFLAGS="-marm" LDFLAGS="-marm" ARCH="armhf" TARGET_CC=arm-linux-gnueabihf-gcc TARGET_CXX=arm-linux-gnueabihf-g++ make all
|
||||
|
||||
arm64:
|
||||
XTOOLS_HOST=aarch64-linux-gnu ARCH="arm64" TARGET_CC=aarch64-linux-gnu-gcc TARGET_CXX=aarch64-linux-gnu-g++ make all
|
||||
ARCH="arm64" TARGET_CC=aarch64-linux-gnu-gcc TARGET_CXX=aarch64-linux-gnu-g++ make all
|
||||
|
||||
$(BUILD_DIR):
|
||||
mkdir -p $(BUILD_DIR)
|
||||
@ -246,29 +271,114 @@ $(OBJ_DIR): | $(BUILD_DIR)
|
||||
$(FRIDA_BUILD_DIR): | $(BUILD_DIR)
|
||||
mkdir -p $@
|
||||
|
||||
#TODO Set architecture
|
||||
ifdef FRIDA_SOURCE
|
||||
$(FRIDA_MAKEFILE): | $(BUILD_DIR)
|
||||
git clone https://github.com/frida/frida-gum.git $(FRIDA_DIR)
|
||||
cd $(FRIDA_DIR) && \
|
||||
./configure \
|
||||
--host=$(XTOOLS_HOST) \
|
||||
--enable-tests \
|
||||
--enable-gumpp \
|
||||
--enable-gumjs \
|
||||
--with-devkits=gum,gumjs
|
||||
git clone --recursive https://github.com/frida/frida.git $(FRIDA_DIR)
|
||||
|
||||
.PHONY: $(GUM_DEVIT_LIBRARY)
|
||||
|
||||
$(GUM_DEVIT_LIBRARY): $(FRIDA_MAKEFILE) | $(FRIDA_BUILD_DIR)
|
||||
echo $(GUM_DEVIT_LIBRARY) $(FRIDA_MAKEFILE) $(FRIDA_BUILD_DIR)
|
||||
cd $(FRIDA_DIR) && make FRIDA_V8=disabled
|
||||
cp $(FRIDA_DIR)build/bindings/gumjs/devkit/frida-gumjs.h $(GUM_DEVIT_HEADER)
|
||||
cp $(FRIDA_DIR)build/bindings/gumjs/devkit/libfrida-gumjs.a $(GUM_DEVIT_LIBRARY)
|
||||
$(GUM_DEVIT_LIBRARY): $(FRIDA_MAKEFILE)
|
||||
cd $(FRIDA_DIR) && make gum-$(OS)$(GUM_ARCH) FRIDA_V8=disabled
|
||||
|
||||
$(GUM_DEVIT_HEADER): $(FRIDA_MAKEFILE) | $(FRIDA_BUILD_DIR)
|
||||
echo "#include <stdio.h>" > $@
|
||||
echo "#include <unistd.h>" >> $@
|
||||
echo "#include <gum/gumreturnaddress.h>" >> $@
|
||||
echo "#include <gum/gumbacktracer.h>" >> $@
|
||||
echo "#include <gum/gumsymbolutil.h>" >> $@
|
||||
echo "#include <gum/gumstalker.h>" >> $@
|
||||
echo "#include <gum/gumlibc.h>" >> $@
|
||||
echo "#include <gumjs/gumscriptbackend.h>" >> $@
|
||||
|
||||
ifeq "$(OS)" "macos"
|
||||
|
||||
CFLAGS+=-I $(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/include/frida-1.0 \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
|
||||
|
||||
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libiconv.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libv8-8.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgmodule-2.0.a \
|
||||
|
||||
else ifeq "$(ARCH)" "arm64"
|
||||
|
||||
CFLAGS+=-I $(FRIDA_DIR)build/$(OS)-$(ARCH)/include/frida-1.0 \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
|
||||
|
||||
ifeq "$(OS)" "android"
|
||||
CFLAGS += -static-libstdc++
|
||||
endif
|
||||
else
|
||||
CFLAGS+=-I $(FRIDA_DIR)build/$(OS)-$(ARCH)/include/frida-1.0 \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
|
||||
|
||||
endif
|
||||
|
||||
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libunwind.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libdwarf.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libelf.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
|
||||
|
||||
CFLAGS+=-I $(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/include/frida-1.0 \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/
|
||||
|
||||
ifeq "$(OS)" "android"
|
||||
CFLAGS += -static-libstdc++
|
||||
endif
|
||||
|
||||
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libunwind.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libdwarf.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libelf.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
|
||||
|
||||
|
||||
else
|
||||
$(GUM_DEVKIT_TARBALL): | $(FRIDA_BUILD_DIR)
|
||||
|
@ -27,6 +27,7 @@ void asan_init(void) {
|
||||
|
||||
}
|
||||
|
||||
#ifdef GUM_16_6_PLUS
|
||||
static gboolean asan_exclude_module(GumModule *module, gpointer user_data) {
|
||||
|
||||
gchar *symbol_name = (gchar *)user_data;
|
||||
@ -46,6 +47,32 @@ static gboolean asan_exclude_module(GumModule *module, gpointer user_data) {
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
static gboolean asan_exclude_module(const GumModuleDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
gchar *symbol_name = (gchar *)user_data;
|
||||
GumAddress address;
|
||||
|
||||
address = gum_module_find_export_by_name(details->name, symbol_name);
|
||||
if (address == 0) { return TRUE; }
|
||||
|
||||
/* If the reported address of the symbol is outside of the range of the module
|
||||
* then ignore it */
|
||||
if (address < details->range->base_address) { return TRUE; }
|
||||
if (address > (details->range->base_address + details->range->size)) {
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
ranges_add_exclude((GumMemoryRange *)details->range);
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void asan_exclude_module_by_symbol(gchar *symbol_name) {
|
||||
|
||||
gum_process_enumerate_modules(asan_exclude_module, symbol_name);
|
||||
|
@ -382,5 +382,5 @@ Afl.jsApiSetTraceable = Afl.jsApiGetFunction("js_api_set_traceable", "void", [])
|
||||
Afl.jsApiSetVerbose = Afl.jsApiGetFunction("js_api_set_verbose", "void", []);
|
||||
Afl.jsApiWrite = new NativeFunction(
|
||||
/* tslint:disable-next-line:no-null-keyword */
|
||||
Module.getGlobalExportByName("write"), "int", ["int", "pointer", "int"]);
|
||||
Module.getExportByName(null, "write"), "int", ["int", "pointer", "int"]);
|
||||
Afl.jsApiIjonSet = Afl.jsApiGetFunction("js_api_ijon_set", "void", ["uint32"]);
|
||||
|
@ -39,6 +39,7 @@ typedef struct {
|
||||
static guint64 text_base = 0;
|
||||
static guint64 text_limit = 0;
|
||||
|
||||
#ifdef GUM_16_6_PLUS
|
||||
static gboolean lib_find_exe(GumModule *module, gpointer user_data) {
|
||||
|
||||
lib_details_t *lib_details = (lib_details_t *)user_data;
|
||||
@ -56,6 +57,24 @@ static gboolean lib_find_exe(GumModule *module, gpointer user_data) {
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
static gboolean lib_find_exe(const GumModuleDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
lib_details_t *lib_details = (lib_details_t *)user_data;
|
||||
|
||||
strncpy(lib_details->name, details->name, PATH_MAX);
|
||||
strncpy(lib_details->path, details->path, PATH_MAX);
|
||||
lib_details->name[PATH_MAX] = '\0';
|
||||
lib_details->path[PATH_MAX] = '\0';
|
||||
lib_details->base_address = details->range->base_address;
|
||||
lib_details->size = details->range->size;
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void lib_validate_hdr(Elf_Ehdr *hdr) {
|
||||
|
||||
if (hdr->e_ident[0] != ELFMAG0) FFATAL("Invalid e_ident[0]");
|
||||
|
@ -12,6 +12,7 @@ extern void gum_darwin_enumerate_modules(mach_port_t task,
|
||||
static guint64 text_base = 0;
|
||||
static guint64 text_limit = 0;
|
||||
|
||||
#ifdef GUM_16_6_PLUS
|
||||
static gboolean lib_get_main_module(GumModule *module, gpointer user_data) {
|
||||
|
||||
GumDarwinModule **ret = (GumDarwinModule **)user_data;
|
||||
@ -29,6 +30,25 @@ static gboolean lib_get_main_module(GumModule *module, gpointer user_data) {
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
static gboolean lib_get_main_module(const GumModuleDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
GumDarwinModule **ret = (GumDarwinModule **)user_data;
|
||||
GumDarwinModule *module = gum_darwin_module_new_from_memory(
|
||||
details->path, mach_task_self(), details->range->base_address,
|
||||
GUM_DARWIN_MODULE_FLAGS_NONE, NULL);
|
||||
|
||||
FVERBOSE("Found main module: %s", module->name);
|
||||
|
||||
*ret = module;
|
||||
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
gboolean lib_get_text_section(const GumDarwinSectionDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
|
@ -46,7 +46,6 @@ gboolean found_range(const GumRangeDetails *details, gpointer user_data) {
|
||||
static int on_dlclose(void *handle) {
|
||||
|
||||
GArray *ranges = NULL;
|
||||
GumModule *module = NULL;
|
||||
struct link_map *lm = NULL;
|
||||
gum_range_t *range = NULL;
|
||||
GumAddress base;
|
||||
@ -62,12 +61,8 @@ static int on_dlclose(void *handle) {
|
||||
FVERBOSE("on_dlclose: %s", lm->l_name);
|
||||
|
||||
ranges = g_array_new(FALSE, TRUE, sizeof(gum_range_t));
|
||||
|
||||
module = gum_process_find_module_by_name(lm->l_name);
|
||||
|
||||
if (module == NULL) { FATAL("Failed to find module: %s", lm->l_name); }
|
||||
|
||||
gum_module_enumerate_ranges(module, GUM_PAGE_EXECUTE, found_range, ranges);
|
||||
gum_module_enumerate_ranges(lm->l_name, GUM_PAGE_EXECUTE, found_range,
|
||||
ranges);
|
||||
|
||||
int ret = dlclose(handle);
|
||||
if (ret != 0) {
|
||||
|
@ -263,8 +263,13 @@ static int prefetch_on_fork(void) {
|
||||
|
||||
static void prefetch_hook_fork(void) {
|
||||
|
||||
#ifdef GUM_16_6_PLUS
|
||||
void *fork_addr =
|
||||
GSIZE_TO_POINTER(gum_module_find_global_export_by_name("fork"));
|
||||
#else
|
||||
void *fork_addr =
|
||||
GSIZE_TO_POINTER(gum_module_find_export_by_name(NULL, "fork"));
|
||||
#endif
|
||||
intercept_hook(fork_addr, prefetch_on_fork, NULL);
|
||||
|
||||
}
|
||||
|
@ -116,6 +116,7 @@ static void convert_address_token(gchar *token, GumMemoryRange *range) {
|
||||
|
||||
}
|
||||
|
||||
#ifdef GUM_16_6_PLUS
|
||||
static gboolean convert_name_token_for_module(GumModule *module,
|
||||
gpointer user_data) {
|
||||
|
||||
@ -137,6 +138,28 @@ static gboolean convert_name_token_for_module(GumModule *module,
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
static gboolean convert_name_token_for_module(const GumModuleDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
convert_name_ctx_t *ctx = (convert_name_ctx_t *)user_data;
|
||||
if (details->path == NULL) { return true; };
|
||||
|
||||
if (!g_str_has_suffix(details->path, ctx->suffix)) { return true; };
|
||||
|
||||
FVERBOSE("Found module - prefix: %s, 0x%016" G_GINT64_MODIFIER
|
||||
"x-0x%016" G_GINT64_MODIFIER "x %s",
|
||||
ctx->suffix, details->range->base_address,
|
||||
details->range->base_address + details->range->size, details->path);
|
||||
|
||||
*ctx->range = *details->range;
|
||||
ctx->done = true;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void convert_name_token(gchar *token, GumMemoryRange *range) {
|
||||
|
||||
gchar *suffix = g_strconcat("/", token, NULL);
|
||||
|
@ -462,10 +462,7 @@ typedef struct afl_env_vars {
|
||||
afl_no_startup_calibration, afl_no_warn_instability,
|
||||
afl_post_process_keep_original, afl_crashing_seeds_as_new_crash,
|
||||
afl_final_sync, afl_ignore_seed_problems, afl_disable_redundant,
|
||||
afl_sha1_filenames, afl_no_sync, afl_no_fastresume, afl_forksrv_uid_set,
|
||||
afl_forksrv_gid_set;
|
||||
|
||||
u16 afl_forksrv_nb_supl_gids;
|
||||
afl_sha1_filenames, afl_no_sync, afl_no_fastresume;
|
||||
|
||||
u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path,
|
||||
*afl_hang_tmout, *afl_forksrv_init_tmout, *afl_preload,
|
||||
@ -476,12 +473,6 @@ typedef struct afl_env_vars {
|
||||
|
||||
s32 afl_pizza_mode;
|
||||
|
||||
uid_t afl_forksrv_uid;
|
||||
|
||||
gid_t afl_forksrv_gid;
|
||||
|
||||
gid_t *afl_forksrv_supl_gids;
|
||||
|
||||
} afl_env_vars_t;
|
||||
|
||||
struct afl_pass_stat {
|
||||
@ -564,10 +555,6 @@ typedef struct afl_state {
|
||||
*orig_cmdline, /* Original command line */
|
||||
*infoexec; /* Command to execute on a new crash */
|
||||
|
||||
mode_t perm, /* File permission when creating files */
|
||||
dir_perm; /* File permission when creating directories */
|
||||
u8 chown_needed; /* Group owner of files needs to be modified */
|
||||
|
||||
u32 hang_tmout, /* Timeout used for hang det (ms) */
|
||||
stats_update_freq; /* Stats update frequency (execs) */
|
||||
|
||||
@ -783,7 +770,6 @@ typedef struct afl_state {
|
||||
#define FOREIGN_SYNCS_MAX 32U
|
||||
u8 foreign_sync_cnt;
|
||||
struct foreign_sync foreign_syncs[FOREIGN_SYNCS_MAX];
|
||||
char *foreign_file;
|
||||
|
||||
#ifdef _AFL_DOCUMENT_MUTATIONS
|
||||
u8 do_document;
|
||||
@ -1153,7 +1139,6 @@ struct custom_mutator {
|
||||
|
||||
void afl_state_init(afl_state_t *, uint32_t map_size);
|
||||
void afl_state_deinit(afl_state_t *);
|
||||
void afl_resize_map_buffers(afl_state_t *, u32 old_size, u32 new_size);
|
||||
|
||||
/* Set stop_soon flag on all children, kill all children */
|
||||
void afl_states_stop(void);
|
||||
@ -1195,7 +1180,7 @@ u8 havoc_mutation_probability_py(void *);
|
||||
u8 queue_get_py(void *, const u8 *);
|
||||
const char *introspection_py(void *);
|
||||
u8 queue_new_entry_py(void *, const u8 *, const u8 *);
|
||||
void splice_optout_py(void *);
|
||||
void splice_optout(void *);
|
||||
void deinit_py(void *);
|
||||
|
||||
#endif
|
||||
@ -1230,6 +1215,7 @@ u8 *describe_op(afl_state_t *, u8, size_t);
|
||||
#endif
|
||||
u8 save_if_interesting(afl_state_t *, void *, u32, u8);
|
||||
u8 has_new_bits(afl_state_t *, u8 *);
|
||||
u8 has_new_bits_unclassified(afl_state_t *, u8 *);
|
||||
#ifndef AFL_SHOWMAP
|
||||
void classify_counts(afl_forkserver_t *);
|
||||
#endif
|
||||
@ -1272,7 +1258,6 @@ int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen);
|
||||
|
||||
/* Run */
|
||||
|
||||
void check_sync_fuzzers(afl_state_t *);
|
||||
void sync_fuzzers(afl_state_t *);
|
||||
u32 write_to_testcase(afl_state_t *, void **, u32, u32);
|
||||
u8 calibrate_case(afl_state_t *, struct queue_entry *, u8 *, u32, u8);
|
||||
@ -1293,6 +1278,7 @@ u8 fuzz_one(afl_state_t *);
|
||||
#ifdef HAVE_AFFINITY
|
||||
void bind_to_free_cpu(afl_state_t *);
|
||||
#endif
|
||||
void setup_post(afl_state_t *);
|
||||
void read_testcases(afl_state_t *, u8 *);
|
||||
void perform_dry_run(afl_state_t *);
|
||||
void pivot_inputs(afl_state_t *);
|
||||
@ -1456,7 +1442,7 @@ char *sha1_hex_for_file(const char *fname, u32 len);
|
||||
* enabled. */
|
||||
static inline int permissive_create(afl_state_t *afl, const char *fn) {
|
||||
|
||||
int fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, afl->perm);
|
||||
int fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
if (unlikely(fd < 0)) {
|
||||
|
||||
if (!(afl->afl_env.afl_sha1_filenames && errno == EEXIST)) {
|
||||
@ -1467,12 +1453,6 @@ static inline int permissive_create(afl_state_t *afl, const char *fn) {
|
||||
|
||||
}
|
||||
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
|
||||
|
||||
}
|
||||
|
||||
return fd;
|
||||
|
||||
}
|
||||
|
@ -144,10 +144,10 @@ u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms);
|
||||
u32 get_map_size(void);
|
||||
|
||||
/* create a stream file */
|
||||
FILE *create_ffile(u8 *fn, mode_t perm);
|
||||
FILE *create_ffile(u8 *fn);
|
||||
|
||||
/* create a file */
|
||||
s32 create_file(u8 *fn, mode_t perm);
|
||||
s32 create_file(u8 *fn);
|
||||
|
||||
/* memmem implementation as not all platforms support this */
|
||||
void *afl_memmem(const void *haystack, size_t haystacklen, const void *needle,
|
||||
|
@ -26,7 +26,7 @@
|
||||
/* Version string: */
|
||||
|
||||
// c = release, a = volatile github dev, e = experimental branch
|
||||
#define VERSION "++4.33a"
|
||||
#define VERSION "++4.32c"
|
||||
|
||||
/******************************************************
|
||||
* *
|
||||
@ -49,9 +49,6 @@
|
||||
Default: 300 (seconds) */
|
||||
#define STRATEGY_SWITCH_TIME 1000
|
||||
|
||||
/* Default file permission umode when creating directories */
|
||||
#define DEFAULT_DIRS_PERMISSION 0700
|
||||
|
||||
/* Default file permission umode when creating files (default: 0600) */
|
||||
#define DEFAULT_PERMISSION 0600
|
||||
|
||||
@ -174,9 +171,8 @@
|
||||
#define EXEC_TM_ROUND 20U
|
||||
|
||||
/* 64bit arch MACRO */
|
||||
#if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__) || \
|
||||
(defined(__riscv) && __riscv_xlen == 64) || defined(__powerpc64le__) || \
|
||||
defined(__s390x__) || defined(__loongarch64))
|
||||
#if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__) || \
|
||||
(defined(__riscv) && __riscv_xlen == 64))
|
||||
#define WORD_SIZE_64 1
|
||||
#endif
|
||||
|
||||
@ -342,10 +338,6 @@
|
||||
|
||||
#define AVG_SMOOTHING 16
|
||||
|
||||
/* Max length of sync id (the id after -M and -S) */
|
||||
|
||||
#define SYNC_ID_MAX_LEN 50
|
||||
|
||||
/* Sync interval (every n havoc cycles): */
|
||||
|
||||
#define SYNC_INTERVAL 8
|
||||
@ -431,15 +423,9 @@
|
||||
|
||||
#define SHM_ENV_VAR "__AFL_SHM_ID"
|
||||
|
||||
/* Environment variable used to pass shared memory fuzz map id
|
||||
and the mapping size to the called program. */
|
||||
/* Environment variable used to pass SHM FUZZ ID to the called program. */
|
||||
|
||||
#define SHM_FUZZ_ENV_VAR "__AFL_SHM_FUZZ_ID"
|
||||
#define SHM_FUZZ_MAP_SIZE_ENV_VAR "__AFL_SHM_FUZZ_MAP_SIZE"
|
||||
|
||||
/* Default size of the shared memory fuzz map.
|
||||
We add 4 byte for one u32 length field. */
|
||||
#define SHM_FUZZ_MAP_SIZE_DEFAULT (MAX_FILE + 4)
|
||||
|
||||
/* Other less interesting, internal-only variables. */
|
||||
|
||||
|
@ -10,7 +10,6 @@ static char *afl_environment_deprecated[] = {
|
||||
"AFL_DEFER_FORKSRV",
|
||||
"AFL_POST_LIBRARY",
|
||||
"AFL_PERSISTENT",
|
||||
"AFL_SAN_NO_INST",
|
||||
NULL
|
||||
|
||||
};
|
||||
@ -34,19 +33,18 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_DISABLE_TRIM", "AFL_NO_TRIM", "AFL_DISABLE_LLVM_INSTRUMENTATION",
|
||||
"AFL_DONT_OPTIMIZE", "AFL_DRIVER_STDERR_DUPLICATE_FILENAME",
|
||||
"AFL_DUMB_FORKSRV", "AFL_EARLY_FORKSERVER", "AFL_ENTRYPOINT",
|
||||
"AFL_EXITPOINT", "AFL_EXIT_WHEN_DONE", "AFL_EXIT_ON_TIME",
|
||||
"AFL_EXIT_ON_SEED_ISSUES", "AFL_FAST_CAL", "AFL_FINAL_SYNC", "AFL_FORCE_UI",
|
||||
"AFL_FRIDA_DEBUG_MAPS", "AFL_FRIDA_DRIVER_NO_HOOK",
|
||||
"AFL_FRIDA_EXCLUDE_RANGES", "AFL_FRIDA_INST_CACHE_SIZE",
|
||||
"AFL_FRIDA_INST_COVERAGE_ABSOLUTE", "AFL_FRIDA_INST_COVERAGE_FILE",
|
||||
"AFL_FRIDA_INST_DEBUG_FILE", "AFL_FRIDA_INST_INSN", "AFL_FRIDA_INST_JIT",
|
||||
"AFL_FRIDA_INST_NO_CACHE", "AFL_FRIDA_INST_NO_DYNAMIC_LOAD",
|
||||
"AFL_FRIDA_INST_NO_OPTIMIZE", "AFL_FRIDA_INST_NO_PREFETCH",
|
||||
"AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH", "AFL_FRIDA_INST_NO_SUPPRESS",
|
||||
"AFL_FRIDA_INST_RANGES", "AFL_FRIDA_INST_REGS_FILE", "AFL_FRIDA_INST_SEED",
|
||||
"AFL_FRIDA_INST_TRACE", "AFL_FRIDA_INST_TRACE_UNIQUE",
|
||||
"AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE", "AFL_FRIDA_JS_SCRIPT",
|
||||
"AFL_FRIDA_OUTPUT_STDOUT", "AFL_FRIDA_OUTPUT_STDERR",
|
||||
"AFL_EXIT_WHEN_DONE", "AFL_EXIT_ON_TIME", "AFL_EXIT_ON_SEED_ISSUES",
|
||||
"AFL_FAST_CAL", "AFL_FINAL_SYNC", "AFL_FORCE_UI", "AFL_FRIDA_DEBUG_MAPS",
|
||||
"AFL_FRIDA_DRIVER_NO_HOOK", "AFL_FRIDA_EXCLUDE_RANGES",
|
||||
"AFL_FRIDA_INST_CACHE_SIZE", "AFL_FRIDA_INST_COVERAGE_ABSOLUTE",
|
||||
"AFL_FRIDA_INST_COVERAGE_FILE", "AFL_FRIDA_INST_DEBUG_FILE",
|
||||
"AFL_FRIDA_INST_INSN", "AFL_FRIDA_INST_JIT", "AFL_FRIDA_INST_NO_CACHE",
|
||||
"AFL_FRIDA_INST_NO_DYNAMIC_LOAD", "AFL_FRIDA_INST_NO_OPTIMIZE",
|
||||
"AFL_FRIDA_INST_NO_PREFETCH", "AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH",
|
||||
"AFL_FRIDA_INST_NO_SUPPRESS", "AFL_FRIDA_INST_RANGES",
|
||||
"AFL_FRIDA_INST_REGS_FILE", "AFL_FRIDA_INST_SEED", "AFL_FRIDA_INST_TRACE",
|
||||
"AFL_FRIDA_INST_TRACE_UNIQUE", "AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE",
|
||||
"AFL_FRIDA_JS_SCRIPT", "AFL_FRIDA_OUTPUT_STDOUT", "AFL_FRIDA_OUTPUT_STDERR",
|
||||
"AFL_FRIDA_PERSISTENT_ADDR", "AFL_FRIDA_PERSISTENT_CNT",
|
||||
"AFL_FRIDA_PERSISTENT_DEBUG", "AFL_FRIDA_PERSISTENT_HOOK",
|
||||
"AFL_FRIDA_PERSISTENT_RET", "AFL_FRIDA_STALKER_ADJACENT_BLOCKS",
|
||||
@ -103,8 +101,8 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_PERSISTENT_RECORD", "AFL_POST_PROCESS_KEEP_ORIGINAL", "AFL_PRELOAD",
|
||||
"AFL_TARGET_ENV", "AFL_PYTHON_MODULE", "AFL_QEMU_CUSTOM_BIN",
|
||||
"AFL_QEMU_COMPCOV", "AFL_QEMU_COMPCOV_DEBUG", "AFL_QEMU_DEBUG_MAPS",
|
||||
"AFL_QEMU_BLOCK_COV", "AFL_QEMU_DISABLE_CACHE", "AFL_QEMU_DRIVER_NO_HOOK",
|
||||
"AFL_QEMU_FORCE_DFL", "AFL_QEMU_PERSISTENT_ADDR", "AFL_QEMU_PERSISTENT_CNT",
|
||||
"AFL_QEMU_DISABLE_CACHE", "AFL_QEMU_DRIVER_NO_HOOK", "AFL_QEMU_FORCE_DFL",
|
||||
"AFL_QEMU_PERSISTENT_ADDR", "AFL_QEMU_PERSISTENT_CNT",
|
||||
"AFL_QEMU_PERSISTENT_GPR", "AFL_QEMU_PERSISTENT_HOOK",
|
||||
"AFL_QEMU_PERSISTENT_MEM", "AFL_QEMU_PERSISTENT_RET",
|
||||
"AFL_QEMU_PERSISTENT_RETADDR_OFFSET", "AFL_QEMU_PERSISTENT_EXITS",
|
||||
@ -120,9 +118,7 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_CFISAN_VERBOSE", "AFL_USE_LSAN", "AFL_WINE_PATH", "AFL_NO_SNAPSHOT",
|
||||
"AFL_EXPAND_HAVOC_NOW", "AFL_USE_FASAN", "AFL_USE_QASAN",
|
||||
"AFL_PRINT_FILENAMES", "AFL_PIZZA_MODE", "AFL_NO_FASTRESUME",
|
||||
"AFL_SAN_ABSTRACTION", "AFL_LLVM_ONLY_FSRV", "AFL_GCC_ONLY_FRSV",
|
||||
"AFL_SAN_RECOVER", "AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT",
|
||||
"AFL_FORKSRV_UID", "AFL_FORKSRV_GID", NULL};
|
||||
"AFL_SAN_ABSTRACTION", "AFL_SAN_NO_INST", "AFL_SAN_RECOVER", NULL};
|
||||
|
||||
extern char *afl_environment_variables[];
|
||||
|
||||
|
@ -159,8 +159,6 @@ typedef struct afl_forkserver {
|
||||
|
||||
u8 uses_asan; /* Target uses ASAN/LSAN/MSAN? (bit 0/1/2 respectively) */
|
||||
|
||||
bool setenv; /* setenv() to discriminate the forkserver? */
|
||||
|
||||
bool debug; /* debug mode? */
|
||||
|
||||
u8 san_but_not_instrumented; /* Is it sanitizer enabled but not instrumented?
|
||||
@ -187,16 +185,6 @@ typedef struct afl_forkserver {
|
||||
s32 persistent_record_pid;
|
||||
#endif
|
||||
|
||||
u8 uid_set;
|
||||
uid_t uid;
|
||||
u8 gid_set;
|
||||
pid_t gid;
|
||||
u16 nb_supl_gids;
|
||||
pid_t *supl_gids;
|
||||
|
||||
mode_t perm;
|
||||
u8 chown_needed;
|
||||
|
||||
/* Function to kick off the forkserver child */
|
||||
void (*init_child_func)(struct afl_forkserver *fsrv, char **argv);
|
||||
|
||||
@ -252,7 +240,6 @@ typedef enum fsrv_run_result {
|
||||
|
||||
void afl_fsrv_init(afl_forkserver_t *fsrv);
|
||||
void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from);
|
||||
void afl_fsrv_setup_preload(afl_forkserver_t *fsrv, char *argv0);
|
||||
void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
volatile u8 *stop_soon_p, u8 debug_child_output);
|
||||
u32 afl_fsrv_get_mapsize(afl_forkserver_t *fsrv, char **argv,
|
||||
|
@ -2,6 +2,18 @@
|
||||
american fuzzy lop++ - hashing function
|
||||
---------------------------------------
|
||||
|
||||
The hash32() function is a variant of MurmurHash3, a good
|
||||
non-cryptosafe hashing function developed by Austin Appleby.
|
||||
|
||||
For simplicity, this variant does *NOT* accept buffer lengths
|
||||
that are not divisible by 8 bytes. The 32-bit version is otherwise
|
||||
similar to the original; the 64-bit one is a custom hack with
|
||||
mostly-unproven properties.
|
||||
|
||||
Austin's original code is public domain.
|
||||
|
||||
Other code written by Michal Zalewski
|
||||
|
||||
Copyright 2016 Google Inc. All rights reserved.
|
||||
Copyright 2019-2024 AFLplusplus Project. All rights reserved.
|
||||
|
||||
@ -21,5 +33,82 @@
|
||||
u32 hash32(u8 *key, u32 len, u32 seed);
|
||||
u64 hash64(u8 *key, u32 len, u64 seed);
|
||||
|
||||
#if 0
|
||||
|
||||
The following code is disabled because xxh3 is 30% faster
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
#define ROL64(_x, _r) ((((u64)(_x)) << (_r)) | (((u64)(_x)) >> (64 - (_r))))
|
||||
|
||||
static inline u32 hash32(u8 *key, u32 len, u32 seed) {
|
||||
|
||||
const u64 *data = (u64 *)key;
|
||||
u64 h1 = seed ^ len;
|
||||
|
||||
len >>= 3;
|
||||
|
||||
while (len--) {
|
||||
|
||||
u64 k1 = *data++;
|
||||
|
||||
k1 *= 0x87c37b91114253d5ULL;
|
||||
k1 = ROL64(k1, 31);
|
||||
k1 *= 0x4cf5ad432745937fULL;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = ROL64(h1, 27);
|
||||
h1 = h1 * 5 + 0x52dce729;
|
||||
|
||||
}
|
||||
|
||||
h1 ^= h1 >> 33;
|
||||
h1 *= 0xff51afd7ed558ccdULL;
|
||||
h1 ^= h1 >> 33;
|
||||
h1 *= 0xc4ceb9fe1a85ec53ULL;
|
||||
h1 ^= h1 >> 33;
|
||||
|
||||
return h1;
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define ROL32(_x, _r) ((((u32)(_x)) << (_r)) | (((u32)(_x)) >> (32 - (_r))))
|
||||
|
||||
static inline u32 hash32(const void *key, u32 len, u32 seed) {
|
||||
|
||||
const u32 *data = (u32 *)key;
|
||||
u32 h1 = seed ^ len;
|
||||
|
||||
len >>= 2;
|
||||
|
||||
while (len--) {
|
||||
|
||||
u32 k1 = *data++;
|
||||
|
||||
k1 *= 0xcc9e2d51;
|
||||
k1 = ROL32(k1, 15);
|
||||
k1 *= 0x1b873593;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = ROL32(h1, 13);
|
||||
h1 = h1 * 5 + 0xe6546b64;
|
||||
|
||||
}
|
||||
|
||||
h1 ^= h1 >> 16;
|
||||
h1 *= 0x85ebca6b;
|
||||
h1 ^= h1 >> 13;
|
||||
h1 *= 0xc2b2ae35;
|
||||
h1 ^= h1 >> 16;
|
||||
|
||||
return h1;
|
||||
|
||||
}
|
||||
|
||||
#endif /* ^__x86_64__ */
|
||||
#endif
|
||||
|
||||
#endif /* !_HAVE_HASH_H */
|
||||
|
||||
|
@ -57,8 +57,7 @@ typedef struct sharedmem {
|
||||
|
||||
} sharedmem_t;
|
||||
|
||||
u8 *afl_shm_init(sharedmem_t *, size_t, unsigned char non_instrumented_mode,
|
||||
mode_t mode, int gid);
|
||||
u8 *afl_shm_init(sharedmem_t *, size_t, unsigned char non_instrumented_mode);
|
||||
void afl_shm_deinit(sharedmem_t *);
|
||||
|
||||
#endif
|
||||
|
@ -327,13 +327,13 @@ class ModuleSanitizerCoverageLTOLegacyPass : public ModulePass {
|
||||
|
||||
};
|
||||
|
||||
if (!getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
if (!getenv("AFL_SAN_NO_INST")) {
|
||||
|
||||
return ModuleSancov.instrumentModule(M, DTCallback, PDTCallback);
|
||||
|
||||
} else {
|
||||
|
||||
if (getenv("AFL_DEBUG")) { DEBUGF("Instrumentation disabled\n"); }
|
||||
if (getenv("AFL_DEBUG")) { DEBUGF("Instrument disabled\n"); }
|
||||
return false;
|
||||
|
||||
}
|
||||
@ -389,14 +389,14 @@ PreservedAnalyses ModuleSanitizerCoverageLTO::run(Module &M,
|
||||
|
||||
};
|
||||
|
||||
if (!getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
if (!getenv("AFL_SAN_NO_INST")) {
|
||||
|
||||
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
|
||||
return PreservedAnalyses::none();
|
||||
|
||||
} else {
|
||||
|
||||
if (debug) { DEBUGF("Instrumentation disabled\n"); }
|
||||
if (debug) { DEBUGF("Instrument disabled\n"); }
|
||||
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
// #include "llvm/IR/Verifier.h"
|
||||
#if LLVM_VERSION_MAJOR >= 15
|
||||
#if LLVM_VERSION_MAJOR < 17
|
||||
#include "llvm/ADT/Triple.h"
|
||||
@ -77,9 +76,9 @@
|
||||
#else
|
||||
#include "llvm/Transforms/Utils/Instrumentation.h"
|
||||
#endif
|
||||
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Transforms/Utils/ModuleUtils.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
@ -207,8 +206,7 @@ class ModuleSanitizerCoverageAFL
|
||||
|
||||
SanitizerCoverageOptions Options;
|
||||
|
||||
uint32_t instr = 0, selects = 0, hidden = 0, unhandled = 0, skippedbb = 0,
|
||||
dump_cc = 0;
|
||||
uint32_t instr = 0, selects = 0, unhandled = 0, dump_cc = 0;
|
||||
GlobalVariable *AFLMapPtr = NULL;
|
||||
ConstantInt *One = NULL;
|
||||
ConstantInt *Zero = NULL;
|
||||
@ -224,6 +222,9 @@ llvmGetPassPluginInfo() {
|
||||
/* lambda to insert our pass into the pass pipeline. */
|
||||
[](PassBuilder &PB) {
|
||||
|
||||
#if LLVM_VERSION_MAJOR == 13
|
||||
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
|
||||
#endif
|
||||
#if LLVM_VERSION_MAJOR >= 16
|
||||
PB.registerOptimizerEarlyEPCallback([](ModulePassManager &MPM,
|
||||
OptimizationLevel OL
|
||||
@ -271,14 +272,14 @@ PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M,
|
||||
// TODO: Support LTO or llvm classic?
|
||||
// Note we still need afl-compiler-rt so we just disable the instrumentation
|
||||
// here.
|
||||
if (!getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
if (!getenv("AFL_SAN_NO_INST")) {
|
||||
|
||||
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
|
||||
return PreservedAnalyses::none();
|
||||
|
||||
} else {
|
||||
|
||||
if (getenv("AFL_DEBUG")) { DEBUGF("Instrumentation disabled\n"); }
|
||||
if (getenv("AFL_DEBUG")) { DEBUGF("Instrument disabled\n"); }
|
||||
|
||||
}
|
||||
|
||||
@ -504,16 +505,9 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
|
||||
getenv("AFL_USE_TSAN") ? ", TSAN" : "",
|
||||
getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
|
||||
getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
|
||||
char buf[32] = "";
|
||||
if (skippedbb) {
|
||||
|
||||
snprintf(buf, sizeof(buf), " %u instrumentations saved.", skippedbb);
|
||||
|
||||
}
|
||||
|
||||
OKF("Instrumented %u locations with no collisions (%s mode) of which are "
|
||||
"%u handled and %u unhandled special instructions.%s",
|
||||
instr, modeline, selects + hidden, unhandled, buf);
|
||||
"%u handled and %u unhandled selects.",
|
||||
instr, modeline, selects, unhandled);
|
||||
|
||||
}
|
||||
|
||||
@ -787,14 +781,11 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
|
||||
if (AllBlocks.empty()) return false;
|
||||
|
||||
uint32_t cnt_cov = 0, cnt_sel = 0, cnt_sel_inc = 0, cnt_hidden_sel = 0,
|
||||
cnt_hidden_sel_inc = 0, skip_blocks = 0;
|
||||
uint32_t cnt_cov = 0, cnt_sel = 0, cnt_sel_inc = 0;
|
||||
static uint32_t first = 1;
|
||||
|
||||
for (auto &BB : F) {
|
||||
|
||||
bool block_is_instrumented = false;
|
||||
|
||||
for (auto &IN : BB) {
|
||||
|
||||
CallInst *callInst = nullptr;
|
||||
@ -808,11 +799,11 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
if (!FuncName.compare(StringRef("dlopen")) ||
|
||||
!FuncName.compare(StringRef("_dlopen"))) {
|
||||
|
||||
WARNF(
|
||||
"dlopen() detected. To have coverage for a library that your "
|
||||
"target dlopen()'s this must either happen before __AFL_INIT() "
|
||||
"or you must use AFL_PRELOAD to preload all dlopen()'ed "
|
||||
"libraries!\n");
|
||||
fprintf(stderr,
|
||||
"WARNING: dlopen() detected. To have coverage for a library "
|
||||
"that your target dlopen()'s this must either happen before "
|
||||
"__AFL_INIT() or you must use AFL_PRELOAD to preload all "
|
||||
"dlopen()'ed libraries!\n");
|
||||
continue;
|
||||
|
||||
}
|
||||
@ -820,183 +811,53 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
if (!FuncName.compare(StringRef("__afl_coverage_interesting"))) {
|
||||
|
||||
cnt_cov++;
|
||||
block_is_instrumented = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool instrumentInst = false;
|
||||
ICmpInst *icmp;
|
||||
FCmpInst *fcmp;
|
||||
SelectInst *selectInst = nullptr;
|
||||
|
||||
if ((icmp = dyn_cast<ICmpInst>(&IN)) ||
|
||||
(fcmp = dyn_cast<FCmpInst>(&IN)) || isa<SelectInst>(&IN)) {
|
||||
if ((selectInst = dyn_cast<SelectInst>(&IN))) {
|
||||
|
||||
// || isa<PHINode>(&IN)
|
||||
Value *c = selectInst->getCondition();
|
||||
auto t = c->getType();
|
||||
if (t->getTypeID() == llvm::Type::IntegerTyID) {
|
||||
|
||||
bool usedInBranch = false, usedInSelectDecision = false;
|
||||
cnt_sel++;
|
||||
cnt_sel_inc += 2;
|
||||
|
||||
for (auto *U : IN.users()) {
|
||||
}
|
||||
|
||||
if (isa<BranchInst>(U)) {
|
||||
else if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
|
||||
|
||||
usedInBranch = true;
|
||||
break;
|
||||
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
|
||||
if (tt) {
|
||||
|
||||
}
|
||||
|
||||
if (auto *sel = dyn_cast<SelectInst>(U)) {
|
||||
|
||||
if (icmp && sel->getCondition() == icmp) {
|
||||
|
||||
usedInSelectDecision = true;
|
||||
|
||||
} else if (fcmp && sel->getCondition() == fcmp) {
|
||||
|
||||
usedInSelectDecision = true;
|
||||
|
||||
}
|
||||
cnt_sel++;
|
||||
cnt_sel_inc += (tt->getElementCount().getKnownMinValue() * 2);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!usedInBranch && !usedInSelectDecision) {
|
||||
|
||||
// errs() << "Instrument! " << *(&IN) << "\n";
|
||||
instrumentInst = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (instrumentInst) {
|
||||
|
||||
block_is_instrumented = true;
|
||||
SelectInst *selectInst;
|
||||
ICmpInst *icmp;
|
||||
FCmpInst *fcmp;
|
||||
// PHINode *phiInst;
|
||||
// errs() << "IN: " << *(&IN) << "\n";
|
||||
|
||||
/* if ((phiInst = dyn_cast<PHINode>(&IN))) {
|
||||
|
||||
cnt_hidden_sel++;
|
||||
cnt_hidden_sel_inc += phiInst->getNumIncomingValues();
|
||||
|
||||
} else*/
|
||||
|
||||
if ((icmp = dyn_cast<ICmpInst>(&IN))) {
|
||||
|
||||
if (icmp->getType()->isIntegerTy(1)) {
|
||||
|
||||
cnt_sel++;
|
||||
cnt_sel_inc += 2;
|
||||
|
||||
} else {
|
||||
|
||||
unhandled++;
|
||||
|
||||
}
|
||||
|
||||
} else if ((fcmp = dyn_cast<FCmpInst>(&IN))) {
|
||||
|
||||
if (fcmp->getType()->isIntegerTy(1)) {
|
||||
|
||||
cnt_sel++;
|
||||
cnt_sel_inc += 2;
|
||||
|
||||
} else {
|
||||
|
||||
unhandled++;
|
||||
|
||||
}
|
||||
|
||||
} else if ((selectInst = dyn_cast<SelectInst>(&IN))) {
|
||||
|
||||
Value *c = selectInst->getCondition();
|
||||
auto t = c->getType();
|
||||
if (t->getTypeID() == llvm::Type::IntegerTyID) {
|
||||
|
||||
cnt_sel++;
|
||||
cnt_sel_inc += 2;
|
||||
|
||||
} else if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
|
||||
|
||||
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
|
||||
if (tt) {
|
||||
|
||||
cnt_sel++;
|
||||
cnt_sel_inc += (tt->getElementCount().getKnownMinValue() * 2);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (!be_quiet) {
|
||||
|
||||
WARNF("unknown select ID type: %u\n", t->getTypeID());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} /*else {
|
||||
|
||||
cnt_hidden_sel++;
|
||||
cnt_hidden_sel_inc += 2;
|
||||
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (block_is_instrumented && &BB != &BB.getParent()->getEntryBlock() &&
|
||||
llvm::is_contained(AllBlocks, &BB)) {
|
||||
|
||||
Instruction *instr = &*BB.begin();
|
||||
LLVMContext &Ctx = BB.getContext();
|
||||
MDNode *md = MDNode::get(Ctx, MDString::get(Ctx, "skipinstrument"));
|
||||
instr->setMetadata("tag", md);
|
||||
skip_blocks++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint32_t xtra = 0;
|
||||
if (skip_blocks < first + cnt_cov + cnt_sel_inc + cnt_hidden_sel_inc) {
|
||||
|
||||
xtra = first + cnt_cov + cnt_sel_inc + cnt_hidden_sel_inc - skip_blocks;
|
||||
|
||||
}
|
||||
|
||||
CreateFunctionLocalArrays(F, AllBlocks, xtra);
|
||||
|
||||
if (!FunctionGuardArray) {
|
||||
|
||||
WARNF(
|
||||
"SANCOV: FunctionGuardArray is NULL, failed to emit instrumentation.");
|
||||
return false;
|
||||
|
||||
}
|
||||
CreateFunctionLocalArrays(F, AllBlocks, first + cnt_cov + cnt_sel_inc);
|
||||
|
||||
if (first) { first = 0; }
|
||||
selects += cnt_sel;
|
||||
hidden += cnt_hidden_sel;
|
||||
|
||||
uint32_t special = 0, local_selects = 0, skip_select = 0, skip_icmp = 0;
|
||||
// uint32_t skip_phi = 0;
|
||||
uint32_t special = 0, local_selects = 0, skip_next = 0;
|
||||
|
||||
for (auto &BB : F) {
|
||||
|
||||
// errs() << *(&BB) << "\n";
|
||||
|
||||
for (auto &IN : BB) {
|
||||
|
||||
// errs() << *(&IN) << "\n";
|
||||
CallInst *callInst = nullptr;
|
||||
|
||||
if ((callInst = dyn_cast<CallInst>(&IN))) {
|
||||
@ -1014,6 +875,15 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
IRBuilder<> IRB(callInst);
|
||||
#endif
|
||||
|
||||
if (!FunctionGuardArray) {
|
||||
|
||||
fprintf(stderr,
|
||||
"SANCOV: FunctionGuardArray is NULL, failed to emit "
|
||||
"instrumentation.");
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
Value *GuardPtr = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
@ -1027,322 +897,132 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
|
||||
}
|
||||
|
||||
bool instrumentInst = false;
|
||||
ICmpInst *icmp;
|
||||
FCmpInst *fcmp;
|
||||
SelectInst *selectInst = nullptr;
|
||||
|
||||
if ((icmp = dyn_cast<ICmpInst>(&IN)) ||
|
||||
(fcmp = dyn_cast<FCmpInst>(&IN)) || isa<SelectInst>(&IN)) {
|
||||
if (!skip_next && (selectInst = dyn_cast<SelectInst>(&IN))) {
|
||||
|
||||
// || isa<PHINode>(&IN)
|
||||
|
||||
bool usedInBranch = false, usedInSelectDecision = false;
|
||||
|
||||
for (auto *U : IN.users()) {
|
||||
|
||||
if (isa<BranchInst>(U)) {
|
||||
|
||||
usedInBranch = true;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (auto *sel = dyn_cast<SelectInst>(U)) {
|
||||
|
||||
if (icmp && sel->getCondition() == icmp) {
|
||||
|
||||
usedInSelectDecision = true;
|
||||
break;
|
||||
|
||||
} else if (fcmp && sel->getCondition() == fcmp) {
|
||||
|
||||
usedInSelectDecision = true;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!usedInBranch && !usedInSelectDecision) {
|
||||
|
||||
// errs() << "Instrument! " << *(&IN) << "\n";
|
||||
instrumentInst = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (instrumentInst) {
|
||||
|
||||
Value *result = nullptr;
|
||||
uint32_t vector_cnt = 0;
|
||||
SelectInst *selectInst;
|
||||
// PHINode *phi = nullptr, *newPhi = nullptr;
|
||||
IRBuilder<> IRB(IN.getNextNode());
|
||||
Value *condition = selectInst->getCondition();
|
||||
Value *result;
|
||||
auto t = condition->getType();
|
||||
IRBuilder<> IRB(selectInst->getNextNode());
|
||||
|
||||
if ((icmp = dyn_cast<ICmpInst>(&IN))) {
|
||||
if (t->getTypeID() == llvm::Type::IntegerTyID) {
|
||||
|
||||
if (!icmp->getType()->isIntegerTy(1)) { continue; }
|
||||
if (!FunctionGuardArray) {
|
||||
|
||||
if (skip_icmp) {
|
||||
|
||||
skip_icmp--;
|
||||
fprintf(stderr,
|
||||
"SANCOV: FunctionGuardArray is NULL, failed to emit "
|
||||
"instrumentation.");
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
|
||||
if (DILocation *Loc = IN.getDebugLoc()) {
|
||||
|
||||
llvm::errs() << "DEBUG " << Loc->getFilename() << ":"
|
||||
<< Loc->getLine() << ":";
|
||||
std::string path =
|
||||
Loc->getDirectory().str() + "/" + Loc->getFilename().str();
|
||||
std::ifstream sourceFile(path);
|
||||
std::string lineContent;
|
||||
for (unsigned line = 1; line <= Loc->getLine(); ++line)
|
||||
std::getline(sourceFile, lineContent);
|
||||
llvm::errs() << lineContent << "\n";
|
||||
|
||||
}
|
||||
|
||||
errs() << *(&IN) << "\n";
|
||||
|
||||
}
|
||||
|
||||
auto res = icmp;
|
||||
auto GuardPtr1 = IRB.CreateInBoundsGEP(
|
||||
FunctionGuardArray->getValueType(), FunctionGuardArray,
|
||||
{IRB.getInt64(0),
|
||||
IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))});
|
||||
|
||||
auto GuardPtr2 = IRB.CreateInBoundsGEP(
|
||||
FunctionGuardArray->getValueType(), FunctionGuardArray,
|
||||
{IRB.getInt64(0),
|
||||
IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))});
|
||||
|
||||
result = IRB.CreateSelect(res, GuardPtr1, GuardPtr2);
|
||||
skip_select = 1;
|
||||
// fprintf(stderr, "Icmp!\n");
|
||||
|
||||
} else if ((fcmp = dyn_cast<FCmpInst>(&IN))) {
|
||||
|
||||
if (!fcmp->getType()->isIntegerTy(1)) { continue; }
|
||||
|
||||
if (debug) {
|
||||
|
||||
if (DILocation *Loc = IN.getDebugLoc()) {
|
||||
|
||||
llvm::errs() << "DEBUG " << Loc->getFilename() << ":"
|
||||
<< Loc->getLine() << ":";
|
||||
std::string path =
|
||||
Loc->getDirectory().str() + "/" + Loc->getFilename().str();
|
||||
std::ifstream sourceFile(path);
|
||||
std::string lineContent;
|
||||
for (unsigned line = 1; line <= Loc->getLine(); ++line)
|
||||
std::getline(sourceFile, lineContent);
|
||||
llvm::errs() << lineContent << "\n";
|
||||
|
||||
}
|
||||
|
||||
errs() << *(&IN) << "\n";
|
||||
|
||||
}
|
||||
|
||||
auto res = fcmp;
|
||||
auto GuardPtr1 = IRB.CreateInBoundsGEP(
|
||||
FunctionGuardArray->getValueType(), FunctionGuardArray,
|
||||
{IRB.getInt64(0),
|
||||
IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))});
|
||||
|
||||
auto GuardPtr2 = IRB.CreateInBoundsGEP(
|
||||
FunctionGuardArray->getValueType(), FunctionGuardArray,
|
||||
{IRB.getInt64(0),
|
||||
IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))});
|
||||
|
||||
result = IRB.CreateSelect(res, GuardPtr1, GuardPtr2);
|
||||
skip_select = 1;
|
||||
// fprintf(stderr, "Fcmp!\n");
|
||||
|
||||
/*} else if ((phi = dyn_cast<PHINode>(&IN))) {
|
||||
|
||||
if (skip_phi) {
|
||||
|
||||
skip_phi = 0;
|
||||
// errs() << "SKIP: " << *(&IN) << "\n";
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
// errs() << "-->PHI: " << *(&IN) << "\n";
|
||||
// continue;
|
||||
Instruction *insertBefore =
|
||||
&*phi->getParent()->getFirstInsertionPt(); newPhi =
|
||||
PHINode::Create(Int32PtrTy, 0, "", insertBefore); BasicBlock
|
||||
*phiBlock = phi->getParent();
|
||||
|
||||
for (BasicBlock *pred : predecessors(phiBlock)) {
|
||||
|
||||
IRBuilder<> predBuilder(pred->getTerminator());
|
||||
|
||||
Value *ptr = predBuilder.CreateInBoundsGEP(
|
||||
FunctionGuardArray->getValueType(), FunctionGuardArray,
|
||||
auto GuardPtr1 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy, (cnt_cov + local_selects++ +
|
||||
AllBlocks.size()))); newPhi->addIncoming(ptr, pred);
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
|
||||
Int32PtrTy);
|
||||
|
||||
}
|
||||
auto GuardPtr2 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
|
||||
Int32PtrTy);
|
||||
|
||||
result = newPhi;
|
||||
skip_phi = 1;
|
||||
// fprintf(stderr, "Phi!\n");
|
||||
*/
|
||||
result = IRB.CreateSelect(condition, GuardPtr1, GuardPtr2);
|
||||
|
||||
} else if ((selectInst = dyn_cast<SelectInst>(&IN))) {
|
||||
} else
|
||||
|
||||
if (skip_select) {
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
|
||||
|
||||
skip_select = 0;
|
||||
continue;
|
||||
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
|
||||
if (tt) {
|
||||
|
||||
} else {
|
||||
uint32_t elements = tt->getElementCount().getFixedValue();
|
||||
vector_cnt = elements;
|
||||
if (elements) {
|
||||
|
||||
// fprintf(stderr, "Select!\n");
|
||||
FixedVectorType *GuardPtr1 =
|
||||
FixedVectorType::get(Int32PtrTy, elements);
|
||||
FixedVectorType *GuardPtr2 =
|
||||
FixedVectorType::get(Int32PtrTy, elements);
|
||||
Value *x, *y;
|
||||
|
||||
}
|
||||
if (!FunctionGuardArray) {
|
||||
|
||||
Value *condition = selectInst->getCondition();
|
||||
auto t = condition->getType();
|
||||
|
||||
if (t->getTypeID() == llvm::Type::IntegerTyID) {
|
||||
|
||||
auto GuardPtr1 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
|
||||
Int32PtrTy);
|
||||
|
||||
auto GuardPtr2 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
|
||||
Int32PtrTy);
|
||||
|
||||
result = IRB.CreateSelect(condition, GuardPtr1, GuardPtr2);
|
||||
skip_select = 1;
|
||||
|
||||
} else
|
||||
|
||||
if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
|
||||
|
||||
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
|
||||
|
||||
if (tt) {
|
||||
|
||||
uint32_t elements = tt->getElementCount().getFixedValue();
|
||||
vector_cnt = elements;
|
||||
if (elements) {
|
||||
|
||||
FixedVectorType *GuardPtr1 =
|
||||
FixedVectorType::get(Int32PtrTy, elements);
|
||||
FixedVectorType *GuardPtr2 =
|
||||
FixedVectorType::get(Int32PtrTy, elements);
|
||||
Value *x, *y;
|
||||
|
||||
Value *val1 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(IntptrTy, (cnt_cov + local_selects++ +
|
||||
AllBlocks.size()) *
|
||||
4)),
|
||||
Int32PtrTy);
|
||||
x = IRB.CreateInsertElement(GuardPtr1, val1, (uint64_t)0);
|
||||
|
||||
Value *val2 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(IntptrTy, (cnt_cov + local_selects++ +
|
||||
AllBlocks.size()) *
|
||||
4)),
|
||||
Int32PtrTy);
|
||||
y = IRB.CreateInsertElement(GuardPtr2, val2, (uint64_t)0);
|
||||
|
||||
for (uint64_t i = 1; i < elements; i++) {
|
||||
|
||||
val1 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) *
|
||||
4)),
|
||||
Int32PtrTy);
|
||||
x = IRB.CreateInsertElement(x, val1, i);
|
||||
|
||||
val2 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) *
|
||||
4)),
|
||||
Int32PtrTy);
|
||||
y = IRB.CreateInsertElement(y, val2, i);
|
||||
|
||||
}
|
||||
|
||||
result = IRB.CreateSelect(condition, x, y);
|
||||
skip_select = 1;
|
||||
fprintf(stderr,
|
||||
"SANCOV: FunctionGuardArray is NULL, failed to emit "
|
||||
"instrumentation.");
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Value *val1 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
|
||||
Int32PtrTy);
|
||||
x = IRB.CreateInsertElement(GuardPtr1, val1, (uint64_t)0);
|
||||
|
||||
} else
|
||||
Value *val2 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
|
||||
Int32PtrTy);
|
||||
y = IRB.CreateInsertElement(GuardPtr2, val2, (uint64_t)0);
|
||||
|
||||
{
|
||||
for (uint64_t i = 1; i < elements; i++) {
|
||||
|
||||
if (!be_quiet) {
|
||||
val1 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(IntptrTy, (cnt_cov + local_selects++ +
|
||||
AllBlocks.size()) *
|
||||
4)),
|
||||
Int32PtrTy);
|
||||
x = IRB.CreateInsertElement(x, val1, i);
|
||||
|
||||
WARNF("Warning: Unhandled ID type: %u\n", t->getTypeID());
|
||||
val2 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(IntptrTy, (cnt_cov + local_selects++ +
|
||||
AllBlocks.size()) *
|
||||
4)),
|
||||
Int32PtrTy);
|
||||
y = IRB.CreateInsertElement(y, val2, i);
|
||||
|
||||
}
|
||||
|
||||
result = IRB.CreateSelect(condition, x, y);
|
||||
|
||||
}
|
||||
|
||||
unhandled++;
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
} else
|
||||
|
||||
#endif
|
||||
{
|
||||
|
||||
// fprintf(stderr, "UNHANDLED: %u\n", t->getTypeID());
|
||||
unhandled++;
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
uint32_t vector_cur = 0;
|
||||
|
||||
/* Load SHM pointer */
|
||||
/*
|
||||
if (newPhi) {
|
||||
|
||||
auto *inst = dyn_cast<Instruction>(result);
|
||||
PHINode *nphi;
|
||||
|
||||
while ((nphi = dyn_cast<PHINode>(inst))) {
|
||||
|
||||
// fprintf(stderr, "NEXT!\n");
|
||||
inst = inst->getNextNode();
|
||||
|
||||
}
|
||||
|
||||
IRB.SetInsertPoint(inst);
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
LoadInst *MapPtr =
|
||||
IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr);
|
||||
@ -1374,7 +1054,9 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
if (use_threadsafe_counters) {
|
||||
|
||||
IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One,
|
||||
#if LLVM_VERSION_MAJOR >= 13
|
||||
llvm::MaybeAlign(1),
|
||||
#endif
|
||||
llvm::AtomicOrdering::Monotonic);
|
||||
|
||||
} else {
|
||||
@ -1391,7 +1073,6 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
auto cf = IRB.CreateICmpEQ(Incr, Zero);
|
||||
auto carry = IRB.CreateZExt(cf, Int8Ty);
|
||||
Incr = IRB.CreateAdd(Incr, carry);
|
||||
skip_icmp++;
|
||||
|
||||
}
|
||||
|
||||
@ -1413,8 +1094,13 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
|
||||
}
|
||||
|
||||
skip_next = 1;
|
||||
instr += vector_cnt;
|
||||
|
||||
} else {
|
||||
|
||||
skip_next = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -1423,40 +1109,9 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
|
||||
if (AllBlocks.empty() && !special && !local_selects) return false;
|
||||
|
||||
uint32_t skipped = 0;
|
||||
|
||||
if (!AllBlocks.empty()) {
|
||||
|
||||
for (size_t i = 0, N = AllBlocks.size(); i < N; i++) {
|
||||
|
||||
auto instr = AllBlocks[i]->begin();
|
||||
if (instr->getMetadata("skipinstrument")) {
|
||||
|
||||
skipped++;
|
||||
// fprintf(stderr, "Skipped!\n");
|
||||
|
||||
} else {
|
||||
|
||||
InjectCoverageAtBlock(F, *AllBlocks[i], i - skipped, IsLeafFunc);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
skippedbb += skipped;
|
||||
|
||||
/*
|
||||
if (verifyFunction(F, &errs())) {
|
||||
|
||||
errs() << "Broken function after instrumentation\n";
|
||||
F.print(errs(), nullptr);
|
||||
report_fatal_error("Invalid IR");
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
if (!AllBlocks.empty())
|
||||
for (size_t i = 0, N = AllBlocks.size(); i < N; i++)
|
||||
InjectCoverageAtBlock(F, *AllBlocks[i], i, IsLeafFunc);
|
||||
|
||||
return true;
|
||||
|
||||
@ -1626,7 +1281,10 @@ void ModuleSanitizerCoverageAFL::InjectCoverageAtBlock(Function &F,
|
||||
if (use_threadsafe_counters) {
|
||||
|
||||
IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One,
|
||||
llvm::MaybeAlign(1), llvm::AtomicOrdering::Monotonic);
|
||||
#if LLVM_VERSION_MAJOR >= 13
|
||||
llvm::MaybeAlign(1),
|
||||
#endif
|
||||
llvm::AtomicOrdering::Monotonic);
|
||||
|
||||
} else {
|
||||
|
||||
@ -1694,3 +1352,4 @@ std::string ModuleSanitizerCoverageAFL::getSectionEnd(
|
||||
return "__stop___" + Section;
|
||||
|
||||
}
|
||||
|
||||
|
@ -119,8 +119,6 @@ u64 __afl_map_addr;
|
||||
u32 __afl_first_final_loc;
|
||||
u32 __afl_old_forkserver;
|
||||
|
||||
u8 __afl_forkserver_setenv = 0;
|
||||
|
||||
#ifdef __AFL_CODE_COVERAGE
|
||||
typedef struct afl_module_info_t afl_module_info_t;
|
||||
|
||||
@ -294,25 +292,6 @@ static void __afl_map_shm_fuzz() {
|
||||
u8 *map = NULL;
|
||||
|
||||
#ifdef USEMMAP
|
||||
|
||||
// Newer afl-fuzz versions will set a shm_fuzz page size env, else fall back
|
||||
size_t shm_fuzz_map_size = SHM_FUZZ_MAP_SIZE_DEFAULT;
|
||||
char *map_size_env = getenv(SHM_FUZZ_MAP_SIZE_ENV_VAR);
|
||||
if (map_size_env != NULL) {
|
||||
|
||||
char *endptr;
|
||||
errno = 0;
|
||||
shm_fuzz_map_size = (size_t)strtoul(map_size_env, &endptr, 10);
|
||||
if (errno != 0 || shm_fuzz_map_size == 0) {
|
||||
|
||||
perror("shm_fuzz mapping size parsing");
|
||||
send_forkserver_error(FS_ERROR_SHM_OPEN);
|
||||
_exit(1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const char *shm_file_path = id_str;
|
||||
int shm_fd = -1;
|
||||
|
||||
@ -326,7 +305,8 @@ static void __afl_map_shm_fuzz() {
|
||||
|
||||
}
|
||||
|
||||
map = (u8 *)mmap(0, shm_fuzz_map_size, PROT_READ, MAP_SHARED, shm_fd, 0);
|
||||
map =
|
||||
(u8 *)mmap(0, MAX_FILE + sizeof(u32), PROT_READ, MAP_SHARED, shm_fd, 0);
|
||||
|
||||
#else
|
||||
u32 shm_id = atoi(id_str);
|
||||
@ -382,7 +362,6 @@ static void __afl_map_shm(void) {
|
||||
if (getenv("AFL_DUMP_MAP_SIZE")) {
|
||||
|
||||
printf("%u\n", __afl_map_size);
|
||||
fflush(stdout);
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
@ -909,12 +888,6 @@ static void __afl_start_forkserver(void) {
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT") != NULL) {
|
||||
|
||||
__afl_forkserver_setenv = 1;
|
||||
|
||||
}
|
||||
|
||||
/* Phone home and tell the parent that we're OK. If parent isn't there,
|
||||
assume we're not running in forkserver mode and just execute program. */
|
||||
|
||||
@ -940,12 +913,7 @@ static void __afl_start_forkserver(void) {
|
||||
|
||||
}
|
||||
|
||||
if (write(FORKSRV_FD + 1, msg, 4) != 4) {
|
||||
|
||||
errno = 0;
|
||||
_exit(1);
|
||||
|
||||
}
|
||||
if (write(FORKSRV_FD + 1, msg, 4) != 4) { _exit(1); }
|
||||
|
||||
// Now send the parameters for the set options, increasing by option number
|
||||
|
||||
@ -1086,13 +1054,6 @@ static void __afl_start_forkserver(void) {
|
||||
|
||||
close(FORKSRV_FD);
|
||||
close(FORKSRV_FD + 1);
|
||||
|
||||
if (unlikely(__afl_forkserver_setenv)) {
|
||||
|
||||
unsetenv("AFL_FORKSERVER_PARENT");
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
@ -1265,15 +1226,6 @@ void __afl_manual_init(void) {
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_LLVM_ONLY_FSRV") || getenv("AFL_GCC_ONLY_FRSV")) {
|
||||
|
||||
fprintf(stderr,
|
||||
"DEBUG: Overwrite area_ptr to dummy due to "
|
||||
"AFL_LLVM_ONLY_FSRV/AFL_GCC_ONLY_FRSV\n");
|
||||
__afl_area_ptr = __afl_area_ptr_dummy;
|
||||
|
||||
}
|
||||
|
||||
if (!init_done) {
|
||||
|
||||
__afl_start_forkserver();
|
||||
|
@ -44,8 +44,8 @@ static const struct pass_data afl_cmplog_pass_data = {
|
||||
.properties_provided = 0,
|
||||
.properties_destroyed = 0,
|
||||
.todo_flags_start = 0,
|
||||
.todo_flags_finish =
|
||||
(TODO_update_ssa | TODO_cleanup_cfg | TODO_rebuild_cgraph_edges),
|
||||
.todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg | TODO_verify_il |
|
||||
TODO_rebuild_cgraph_edges),
|
||||
|
||||
};
|
||||
|
||||
|
@ -44,8 +44,8 @@ static const struct pass_data afl_cmptrs_pass_data = {
|
||||
.properties_provided = 0,
|
||||
.properties_destroyed = 0,
|
||||
.todo_flags_start = 0,
|
||||
.todo_flags_finish =
|
||||
(TODO_update_ssa | TODO_cleanup_cfg | TODO_rebuild_cgraph_edges),
|
||||
.todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg | TODO_verify_il |
|
||||
TODO_rebuild_cgraph_edges),
|
||||
|
||||
};
|
||||
|
||||
|
@ -65,6 +65,7 @@
|
||||
The new pass is to be a GIMPLE_PASS. Given the sort of
|
||||
instrumentation it's supposed to do, its todo_flags_finish will
|
||||
certainly need TODO_update_ssa, and TODO_cleanup_cfg.
|
||||
TODO_verify_il is probably desirable, at least during debugging.
|
||||
TODO_rebuild_cgraph_edges is required only in the out-of-line
|
||||
instrumentation mode.
|
||||
|
||||
@ -147,7 +148,7 @@ static constexpr struct pass_data afl_pass_data = {
|
||||
.properties_provided = 0,
|
||||
.properties_destroyed = 0,
|
||||
.todo_flags_start = 0,
|
||||
.todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg),
|
||||
.todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg | TODO_verify_il),
|
||||
|
||||
};
|
||||
|
||||
@ -461,7 +462,6 @@ static struct plugin_info afl_plugin = {
|
||||
.help = G_("AFL gcc plugin\n\
|
||||
\n\
|
||||
Set AFL_QUIET in the environment to silence it.\n\
|
||||
Set AFL_GCC_ONLY_FRSV in the environment to disable instrumentation.\n\
|
||||
\n\
|
||||
Set AFL_INST_RATIO in the environment to a number from 0 to 100\n\
|
||||
to control how likely a block will be chosen for instrumentation.\n\
|
||||
@ -502,10 +502,9 @@ int plugin_init(struct plugin_name_args *info,
|
||||
case it was specified in the command line's -frandom-seed for
|
||||
reproducible instrumentation. */
|
||||
srandom(get_random_seed(false));
|
||||
bool fsrv_only = !!getenv("AFL_GCC_ONLY_FRSV");
|
||||
|
||||
const char *name = info->base_name;
|
||||
if (!fsrv_only) { register_callback(name, PLUGIN_INFO, NULL, &afl_plugin); }
|
||||
register_callback(name, PLUGIN_INFO, NULL, &afl_plugin);
|
||||
|
||||
afl_pass *aflp = new afl_pass(quiet, inst_ratio);
|
||||
struct register_pass_info pass_info = {
|
||||
@ -517,20 +516,14 @@ int plugin_init(struct plugin_name_args *info,
|
||||
|
||||
};
|
||||
|
||||
if (!fsrv_only) {
|
||||
|
||||
register_callback(name, PLUGIN_PASS_MANAGER_SETUP, NULL, &pass_info);
|
||||
register_callback(name, PLUGIN_FINISH, afl_pass::plugin_finalize,
|
||||
pass_info.pass);
|
||||
|
||||
}
|
||||
register_callback(name, PLUGIN_PASS_MANAGER_SETUP, NULL, &pass_info);
|
||||
register_callback(name, PLUGIN_FINISH, afl_pass::plugin_finalize,
|
||||
pass_info.pass);
|
||||
|
||||
if (!quiet)
|
||||
ACTF(G_("%s instrumentation at ratio of %u%% in %s mode."),
|
||||
aflp->out_of_line ? G_("Call-based") : G_("Inline"), inst_ratio,
|
||||
getenv("AFL_HARDEN") ? G_("hardened") : G_("non-hardened"));
|
||||
else if (fsrv_only)
|
||||
ACTF("Instrumentation disabled due to AFL_GCC_ONLY_FRSV");
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -85,7 +85,10 @@ char *getBBName(const llvm::BasicBlock *BB) {
|
||||
std::string Str;
|
||||
raw_string_ostream OS(Str);
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 4 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7)
|
||||
BB->printAsOperand(OS, false);
|
||||
#endif
|
||||
name = strdup(OS.str().c_str());
|
||||
return name;
|
||||
|
||||
@ -336,6 +339,9 @@ void scanForDangerousFunctions(llvm::Module *M) {
|
||||
|
||||
if (!M) return;
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 4 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 9)
|
||||
|
||||
for (GlobalIFunc &IF : M->ifuncs()) {
|
||||
|
||||
StringRef ifunc_name = IF.getName();
|
||||
@ -402,6 +408,8 @@ void scanForDangerousFunctions(llvm::Module *M) {
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static std::string getSourceName(llvm::Function *F) {
|
||||
@ -412,6 +420,8 @@ static std::string getSourceName(llvm::Function *F) {
|
||||
IRBuilder<> IRB(&(*IP));
|
||||
DebugLoc Loc = IP->getDebugLoc();
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 4 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7)
|
||||
if (Loc) {
|
||||
|
||||
StringRef instFilename;
|
||||
@ -432,6 +442,20 @@ static std::string getSourceName(llvm::Function *F) {
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
if (!Loc.isUnknown()) {
|
||||
|
||||
DILocation cDILoc(Loc.getAsMDNode(F->getContext()));
|
||||
|
||||
StringRef instFilename = cDILoc.getFilename();
|
||||
|
||||
/* Continue only if we know where we actually are */
|
||||
return instFilename.str();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return std::string("");
|
||||
|
||||
}
|
||||
|
@ -18,6 +18,9 @@
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5
|
||||
typedef long double max_align_t;
|
||||
#endif
|
||||
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
@ -29,16 +32,27 @@
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#endif
|
||||
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#if LLVM_VERSION_MAJOR > 3 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#else
|
||||
#include "llvm/DebugInfo.h"
|
||||
#include "llvm/Support/CFG.h"
|
||||
#endif
|
||||
|
||||
#define MNAME M.getSourceFileName()
|
||||
#define FMNAME F.getParent()->getSourceFileName()
|
||||
#if LLVM_VERSION_MAJOR >= 16
|
||||
#if LLVM_VERSION_MAJOR >= 11
|
||||
#define MNAME M.getSourceFileName()
|
||||
#define FMNAME F.getParent()->getSourceFileName()
|
||||
#if LLVM_VERSION_MAJOR >= 16
|
||||
// None becomes deprecated
|
||||
// the standard std::nullopt_t is recommended instead
|
||||
// from C++17 and onwards.
|
||||
constexpr std::nullopt_t None = std::nullopt;
|
||||
#endif
|
||||
#else
|
||||
#define MNAME std::string("")
|
||||
#define FMNAME std::string("")
|
||||
#endif
|
||||
|
||||
char *getBBName(const llvm::BasicBlock *BB);
|
||||
|
@ -39,9 +39,13 @@
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#else
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#endif
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
@ -68,6 +72,7 @@ using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
class AFLdict2filePass : public PassInfoMixin<AFLdict2filePass> {
|
||||
|
||||
std::ofstream of;
|
||||
@ -76,16 +81,35 @@ class AFLdict2filePass : public PassInfoMixin<AFLdict2filePass> {
|
||||
public:
|
||||
AFLdict2filePass() {
|
||||
|
||||
#else
|
||||
|
||||
class AFLdict2filePass : public ModulePass {
|
||||
|
||||
std::ofstream of;
|
||||
void dict2file(u8 *, u32);
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
AFLdict2filePass() : ModulePass(ID) {
|
||||
|
||||
#endif
|
||||
|
||||
if (getenv("AFL_DEBUG")) debug = 1;
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
|
||||
#else
|
||||
bool runOnModule(Module &M) override;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#if LLVM_MAJOR >= 11
|
||||
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
|
||||
llvmGetPassPluginInfo() {
|
||||
|
||||
@ -93,12 +117,15 @@ llvmGetPassPluginInfo() {
|
||||
/* lambda to insert our pass into the pass pipeline. */
|
||||
[](PassBuilder &PB) {
|
||||
|
||||
#if LLVM_VERSION_MAJOR <= 13
|
||||
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
|
||||
#endif
|
||||
PB.registerOptimizerLastEPCallback([](ModulePassManager &MPM,
|
||||
OptimizationLevel OL
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
,
|
||||
ThinOrFullLTOPhase Phase
|
||||
#endif
|
||||
#endif
|
||||
) {
|
||||
|
||||
MPM.addPass(AFLdict2filePass());
|
||||
@ -109,6 +136,10 @@ llvmGetPassPluginInfo() {
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
char AFLdict2filePass::ID = 0;
|
||||
#endif
|
||||
|
||||
void AFLdict2filePass::dict2file(u8 *mem, u32 len) {
|
||||
|
||||
u32 i, j, binary = 0;
|
||||
@ -148,8 +179,14 @@ void AFLdict2filePass::dict2file(u8 *mem, u32 len) {
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
PreservedAnalyses AFLdict2filePass::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
|
||||
#else
|
||||
bool AFLdict2filePass::runOnModule(Module &M) {
|
||||
|
||||
#endif
|
||||
|
||||
DenseMap<Value *, std::string *> valueMap;
|
||||
char *ptr;
|
||||
int found = 0, handle_main = 1;
|
||||
@ -176,8 +213,12 @@ PreservedAnalyses AFLdict2filePass::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
|
||||
if (!ptr) {
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
auto PA = PreservedAnalyses::all();
|
||||
return PA;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@ -713,7 +754,32 @@ PreservedAnalyses AFLdict2filePass::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
auto PA = PreservedAnalyses::all();
|
||||
return PA;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 11 /* use old pass manager */
|
||||
static void registerAFLdict2filePass(const PassManagerBuilder &,
|
||||
legacy::PassManagerBase &PM) {
|
||||
|
||||
PM.add(new AFLdict2filePass());
|
||||
|
||||
}
|
||||
|
||||
static RegisterPass<AFLdict2filePass> X("afl-dict2file",
|
||||
"AFL++ dict2file instrumentation pass",
|
||||
false, false);
|
||||
|
||||
static RegisterStandardPasses RegisterAFLdict2filePass(
|
||||
PassManagerBuilder::EP_OptimizerLast, registerAFLdict2filePass);
|
||||
|
||||
static RegisterStandardPasses RegisterAFLdict2filePass0(
|
||||
PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLdict2filePass);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -43,7 +43,9 @@
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#include "llvm/Passes/OptimizationLevel.h"
|
||||
#if LLVM_VERSION_MAJOR >= 14 /* how about stable interfaces? */
|
||||
#include "llvm/Passes/OptimizationLevel.h"
|
||||
#endif
|
||||
|
||||
#include "afl-llvm-common.h"
|
||||
|
||||
@ -78,6 +80,9 @@ llvmGetPassPluginInfo() {
|
||||
/* lambda to insert our pass into the pass pipeline. */
|
||||
[](PassBuilder &PB) {
|
||||
|
||||
#if LLVM_VERSION_MAJOR <= 13
|
||||
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
|
||||
#endif
|
||||
PB.registerOptimizerLastEPCallback([](ModulePassManager &MPM,
|
||||
OptimizationLevel OL
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
@ -130,8 +135,15 @@ PreservedAnalyses AFLcheckIfInstrument::run(Module &M,
|
||||
|
||||
auto &Ctx = F.getContext();
|
||||
AttributeList Attrs = F.getAttributes();
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
AttributeList NewAttrs = Attrs.addFnAttribute(Ctx, "skipinstrument");
|
||||
F.setAttributes(NewAttrs);
|
||||
#else
|
||||
AttrBuilder NewAttrs;
|
||||
NewAttrs.addAttribute("skipinstrument");
|
||||
F.setAttributes(
|
||||
Attrs.addAttributes(Ctx, AttributeList::FunctionIndex, NewAttrs));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@ -142,3 +154,20 @@ PreservedAnalyses AFLcheckIfInstrument::run(Module &M,
|
||||
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void registerAFLcheckIfInstrumentpass(const PassManagerBuilder &,
|
||||
legacy::PassManagerBase &PM) {
|
||||
|
||||
PM.add(new AFLcheckIfInstrument());
|
||||
|
||||
}
|
||||
|
||||
static RegisterStandardPasses RegisterAFLcheckIfInstrumentpass(
|
||||
PassManagerBuilder::EP_ModuleOptimizerEarly,
|
||||
registerAFLcheckIfInstrumentpass);
|
||||
|
||||
static RegisterStandardPasses RegisterAFLcheckIfInstrumentpass0(
|
||||
PassManagerBuilder::EP_EnabledOnOptLevel0,
|
||||
registerAFLcheckIfInstrumentpass);
|
||||
#endif
|
||||
|
||||
|
@ -38,17 +38,30 @@ typedef long double max_align_t;
|
||||
#endif
|
||||
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#else
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#endif
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Passes/OptimizationLevel.h"
|
||||
#if LLVM_VERSION_MAJOR >= 14 /* how about stable interfaces? */
|
||||
#include "llvm/Passes/OptimizationLevel.h"
|
||||
#endif
|
||||
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#if LLVM_VERSION_MAJOR >= 4 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#else
|
||||
#include "llvm/DebugInfo.h"
|
||||
#include "llvm/Support/CFG.h"
|
||||
#endif
|
||||
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
|
||||
@ -59,16 +72,30 @@ using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
class AFLCoverage : public PassInfoMixin<AFLCoverage> {
|
||||
|
||||
public:
|
||||
AFLCoverage() {
|
||||
|
||||
#else
|
||||
class AFLCoverage : public ModulePass {
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
AFLCoverage() : ModulePass(ID) {
|
||||
|
||||
#endif
|
||||
|
||||
initInstrumentList();
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
|
||||
#else
|
||||
bool runOnModule(Module &M) override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
uint32_t ngram_size = 0;
|
||||
@ -82,37 +109,97 @@ class AFLCoverage : public PassInfoMixin<AFLCoverage> {
|
||||
|
||||
} // namespace
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
extern "C" LLVM_ATTRIBUTE_WEAK PassPluginLibraryInfo llvmGetPassPluginInfo() {
|
||||
|
||||
return {LLVM_PLUGIN_API_VERSION, "AFLCoverage", "v0.1",
|
||||
/* lambda to insert our pass into the pass pipeline. */
|
||||
[](PassBuilder &PB) {
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 16
|
||||
#if 1
|
||||
#if LLVM_VERSION_MAJOR <= 13
|
||||
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
|
||||
#endif
|
||||
#if LLVM_VERSION_MAJOR >= 16
|
||||
PB.registerOptimizerEarlyEPCallback(
|
||||
#else
|
||||
#else
|
||||
PB.registerOptimizerLastEPCallback(
|
||||
#endif
|
||||
#endif
|
||||
[](ModulePassManager &MPM, OptimizationLevel OL
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
,
|
||||
ThinOrFullLTOPhase Phase
|
||||
#endif
|
||||
#endif
|
||||
) {
|
||||
|
||||
MPM.addPass(AFLCoverage());
|
||||
|
||||
});
|
||||
|
||||
/* TODO LTO registration */
|
||||
#else
|
||||
using PipelineElement = typename PassBuilder::PipelineElement;
|
||||
PB.registerPipelineParsingCallback([](StringRef Name,
|
||||
ModulePassManager &MPM,
|
||||
ArrayRef<PipelineElement>) {
|
||||
|
||||
if (Name == "AFLCoverage") {
|
||||
|
||||
MPM.addPass(AFLCoverage());
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
#endif
|
||||
|
||||
}};
|
||||
|
||||
}
|
||||
|
||||
/* #if LLVM_VERSION_STRING >= "4.0.1" */
|
||||
#define AFL_HAVE_VECTOR_INTRINSICS 1
|
||||
#else
|
||||
|
||||
char AFLCoverage::ID = 0;
|
||||
#endif
|
||||
|
||||
/* needed up to 3.9.0 */
|
||||
#if LLVM_VERSION_MAJOR == 3 && \
|
||||
(LLVM_VERSION_MINOR < 9 || \
|
||||
(LLVM_VERSION_MINOR == 9 && LLVM_VERSION_PATCH < 1))
|
||||
uint64_t PowerOf2Ceil(unsigned in) {
|
||||
|
||||
uint64_t in64 = in - 1;
|
||||
in64 |= (in64 >> 1);
|
||||
in64 |= (in64 >> 2);
|
||||
in64 |= (in64 >> 4);
|
||||
in64 |= (in64 >> 8);
|
||||
in64 |= (in64 >> 16);
|
||||
in64 |= (in64 >> 32);
|
||||
return in64 + 1;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* #if LLVM_VERSION_STRING >= "4.0.1" */
|
||||
#if LLVM_VERSION_MAJOR >= 5 || \
|
||||
(LLVM_VERSION_MAJOR == 4 && LLVM_VERSION_PATCH >= 1)
|
||||
#define AFL_HAVE_VECTOR_INTRINSICS 1
|
||||
#endif
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
|
||||
#else
|
||||
bool AFLCoverage::runOnModule(Module &M) {
|
||||
|
||||
#endif
|
||||
|
||||
LLVMContext &C = M.getContext();
|
||||
|
||||
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
|
||||
@ -137,13 +224,24 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
|
||||
if (getenv("AFL_DEBUG")) debug = 1;
|
||||
|
||||
if (getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
if (getenv("AFL_SAN_NO_INST")) {
|
||||
|
||||
if (debug) { fprintf(stderr, "Instrumentation disabled\n"); }
|
||||
if (debug) { fprintf(stderr, "Instrument disabled\n"); }
|
||||
return PreservedAnalyses::all();
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
if (getenv("AFL_SAN_NO_INST")) {
|
||||
|
||||
if (debug) { fprintf(stderr, "Instrument disabled\n"); }
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
|
||||
|
||||
SAYF(cCYA "afl-llvm-pass" VERSION cRST
|
||||
@ -179,6 +277,9 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
char *neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO");
|
||||
#endif
|
||||
skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
|
||||
use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST");
|
||||
|
||||
@ -296,12 +397,24 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
int PrevLocVecSize = PowerOf2Ceil(PrevLocSize);
|
||||
if (ngram_size) PrevLocTy = VectorType::get(IntLocTy, PrevLocVecSize, false);
|
||||
if (ngram_size)
|
||||
PrevLocTy = VectorType::get(IntLocTy, PrevLocVecSize
|
||||
#if LLVM_VERSION_MAJOR >= 12
|
||||
,
|
||||
false
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
int PrevCallerVecSize = PowerOf2Ceil(PrevCallerSize);
|
||||
if (ctx_k) PrevCallerTy = VectorType::get(IntLocTy, PrevCallerVecSize, false);
|
||||
if (ctx_k)
|
||||
PrevCallerTy = VectorType::get(IntLocTy, PrevCallerVecSize
|
||||
#if LLVM_VERSION_MAJOR >= 12
|
||||
,
|
||||
false
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
|
||||
/* Get globals for the SHM region and the previous location. Note that
|
||||
@ -439,7 +552,11 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
if (ctx_k) {
|
||||
|
||||
PrevCaller = IRB.CreateLoad(PrevCallerTy, AFLPrevCaller);
|
||||
PrevCaller = IRB.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
PrevCallerTy,
|
||||
#endif
|
||||
AFLPrevCaller);
|
||||
PrevCaller->setMetadata(M.getMDKindID("nosanitize"),
|
||||
MDNode::get(C, None));
|
||||
PrevCtx =
|
||||
@ -452,7 +569,11 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
|
||||
// load the context ID of the previous function and write to a
|
||||
// local variable on the stack
|
||||
LoadInst *PrevCtxLoad = IRB.CreateLoad(IRB.getInt32Ty(), AFLContext);
|
||||
LoadInst *PrevCtxLoad = IRB.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
IRB.getInt32Ty(),
|
||||
#endif
|
||||
AFLContext);
|
||||
PrevCtxLoad->setMetadata(M.getMDKindID("nosanitize"),
|
||||
MDNode::get(C, None));
|
||||
PrevCtx = PrevCtxLoad;
|
||||
@ -526,11 +647,11 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
// cur_loc++;
|
||||
cur_loc = AFL_R(map_size);
|
||||
|
||||
/* There is a problem with Ubuntu 18.04 and llvm 6.0 (see issue #63).
|
||||
The inline function successors() is not inlined and also not found at
|
||||
runtime
|
||||
:-( As I am unable to detect Ubuntu18.04 here, the next best thing is
|
||||
to disable this optional optimization for LLVM 6.0.0 and Linux */
|
||||
/* There is a problem with Ubuntu 18.04 and llvm 6.0 (see issue #63).
|
||||
The inline function successors() is not inlined and also not found at runtime
|
||||
:-( As I am unable to detect Ubuntu18.04 here, the next best thing is to
|
||||
disable this optional optimization for LLVM 6.0.0 and Linux */
|
||||
#if !(LLVM_VERSION_MAJOR == 6 && LLVM_VERSION_MINOR == 0) || !defined __linux__
|
||||
// only instrument if this basic block is the destination of a previous
|
||||
// basic block that has multiple successors
|
||||
// this gets rid of ~5-10% of instrumentations that are unnecessary
|
||||
@ -575,11 +696,11 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
IRBuilder<> Post_IRB(Inst);
|
||||
|
||||
StoreInst *RestoreCtx;
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
if (ctx_k)
|
||||
RestoreCtx = IRB.CreateStore(PrevCaller, AFLPrevCaller);
|
||||
else
|
||||
#endif
|
||||
#endif
|
||||
RestoreCtx = Post_IRB.CreateStore(PrevCtx, AFLContext);
|
||||
RestoreCtx->setMetadata(M.getMDKindID("nosanitize"),
|
||||
MDNode::get(C, None));
|
||||
@ -592,6 +713,8 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ConstantInt *CurLoc;
|
||||
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
@ -607,11 +730,19 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
|
||||
if (ngram_size) {
|
||||
|
||||
PrevLoc = IRB.CreateLoad(PrevLocTy, AFLPrevLoc);
|
||||
PrevLoc = IRB.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
PrevLocTy,
|
||||
#endif
|
||||
AFLPrevLoc);
|
||||
|
||||
} else {
|
||||
|
||||
PrevLoc = IRB.CreateLoad(IRB.getInt32Ty(), AFLPrevLoc);
|
||||
PrevLoc = IRB.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
IRB.getInt32Ty(),
|
||||
#endif
|
||||
AFLPrevLoc);
|
||||
|
||||
}
|
||||
|
||||
@ -638,7 +769,11 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
|
||||
/* Load SHM pointer */
|
||||
|
||||
LoadInst *MapPtr = IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr);
|
||||
LoadInst *MapPtr = IRB.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
PointerType::get(Int8Ty, 0),
|
||||
#endif
|
||||
AFLMapPtr);
|
||||
MapPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
|
||||
Value *MapPtrIdx;
|
||||
@ -651,15 +786,20 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
Int32Ty));
|
||||
else
|
||||
#endif
|
||||
MapPtrIdx =
|
||||
IRB.CreateGEP(Int8Ty, MapPtr, IRB.CreateXor(PrevLocTrans, CurLoc));
|
||||
MapPtrIdx = IRB.CreateGEP(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
Int8Ty,
|
||||
#endif
|
||||
MapPtr, IRB.CreateXor(PrevLocTrans, CurLoc));
|
||||
|
||||
/* Update bitmap */
|
||||
|
||||
if (use_threadsafe_counters) { /* Atomic */
|
||||
|
||||
IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One,
|
||||
#if LLVM_VERSION_MAJOR >= 13
|
||||
llvm::MaybeAlign(1),
|
||||
#endif
|
||||
llvm::AtomicOrdering::Monotonic);
|
||||
/*
|
||||
|
||||
@ -669,13 +809,22 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
|
||||
} else {
|
||||
|
||||
LoadInst *Counter = IRB.CreateLoad(IRB.getInt8Ty(), MapPtrIdx);
|
||||
LoadInst *Counter = IRB.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
IRB.getInt8Ty(),
|
||||
#endif
|
||||
MapPtrIdx);
|
||||
Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
|
||||
Value *Incr = IRB.CreateAdd(Counter, One);
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
if (!skip_nozero) {
|
||||
|
||||
#else
|
||||
if (neverZero_counters_str != NULL) {
|
||||
|
||||
#endif
|
||||
/* hexcoder: Realize a counter that skips zero during overflow.
|
||||
* Once this counter reaches its maximum value, it next increments to
|
||||
* 1
|
||||
@ -754,6 +903,124 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (use_threadsafe_counters) { /*Atomic NeverZero */
|
||||
// handle the list of registered blocks to instrument
|
||||
for (auto val : todo) {
|
||||
|
||||
/* hexcoder: Realize a thread-safe counter that skips zero during
|
||||
* overflow. Once this counter reaches its maximum value, it next
|
||||
* increments to 1
|
||||
*
|
||||
* Instead of
|
||||
* Counter + 1 -> Counter
|
||||
* we inject now this
|
||||
* Counter + 1 -> {Counter, OverflowFlag}
|
||||
* Counter + OverflowFlag -> Counter
|
||||
*/
|
||||
|
||||
/* equivalent c code looks like this
|
||||
* Thanks to
|
||||
https://preshing.com/20150402/you-can-do-any-kind-of-atomic-read-modify-write-operation/
|
||||
|
||||
int old = atomic_load_explicit(&Counter, memory_order_relaxed);
|
||||
int new;
|
||||
do {
|
||||
|
||||
if (old == 255) {
|
||||
|
||||
new = 1;
|
||||
|
||||
} else {
|
||||
|
||||
new = old + 1;
|
||||
|
||||
}
|
||||
|
||||
} while (!atomic_compare_exchange_weak_explicit(&Counter, &old, new,
|
||||
|
||||
memory_order_relaxed, memory_order_relaxed));
|
||||
|
||||
*/
|
||||
|
||||
Value * MapPtrIdx = val;
|
||||
Instruction * MapPtrIdxInst = cast<Instruction>(val);
|
||||
BasicBlock::iterator it0(&(*MapPtrIdxInst));
|
||||
++it0;
|
||||
IRBuilder<> IRB(&(*it0));
|
||||
|
||||
// load the old counter value atomically
|
||||
LoadInst *Counter = IRB.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
IRB.getInt8Ty(),
|
||||
#endif
|
||||
MapPtrIdx);
|
||||
Counter->setAlignment(llvm::Align());
|
||||
Counter->setAtomic(llvm::AtomicOrdering::Monotonic);
|
||||
Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
|
||||
BasicBlock *BB = IRB.GetInsertBlock();
|
||||
// insert a basic block with the corpus of a do while loop
|
||||
// the calculation may need to repeat, if atomic compare_exchange is not
|
||||
// successful
|
||||
|
||||
BasicBlock::iterator it(*Counter);
|
||||
it++; // split after load counter
|
||||
BasicBlock *end_bb = BB->splitBasicBlock(it);
|
||||
end_bb->setName("injected");
|
||||
|
||||
// insert the block before the second half of the split
|
||||
BasicBlock *do_while_bb =
|
||||
BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb);
|
||||
|
||||
// set terminator of BB from target end_bb to target do_while_bb
|
||||
auto term = BB->getTerminator();
|
||||
BranchInst::Create(do_while_bb, BB);
|
||||
term->eraseFromParent();
|
||||
|
||||
// continue to fill instructions into the do_while loop
|
||||
IRB.SetInsertPoint(do_while_bb, do_while_bb->getFirstInsertionPt());
|
||||
|
||||
PHINode *PN = IRB.CreatePHI(Int8Ty, 2);
|
||||
|
||||
// compare with maximum value 0xff
|
||||
auto *Cmp = IRB.CreateICmpEQ(Counter, ConstantInt::get(Int8Ty, -1));
|
||||
|
||||
// increment the counter
|
||||
Value *Incr = IRB.CreateAdd(Counter, One);
|
||||
|
||||
// select the counter value or 1
|
||||
auto *Select = IRB.CreateSelect(Cmp, One, Incr);
|
||||
|
||||
// try to save back the new counter value
|
||||
auto *CmpXchg = IRB.CreateAtomicCmpXchg(
|
||||
MapPtrIdx, PN, Select, llvm::AtomicOrdering::Monotonic,
|
||||
llvm::AtomicOrdering::Monotonic);
|
||||
CmpXchg->setAlignment(llvm::Align());
|
||||
CmpXchg->setWeak(true);
|
||||
CmpXchg->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
|
||||
// get the result of trying to update the Counter
|
||||
Value *Success =
|
||||
IRB.CreateExtractValue(CmpXchg, ArrayRef<unsigned>({1}));
|
||||
// get the (possibly updated) value of Counter
|
||||
Value *OldVal =
|
||||
IRB.CreateExtractValue(CmpXchg, ArrayRef<unsigned>({0}));
|
||||
|
||||
// initially we use Counter
|
||||
PN->addIncoming(Counter, BB);
|
||||
// on retry, we use the updated value
|
||||
PN->addIncoming(OldVal, do_while_bb);
|
||||
|
||||
// if the cmpXchg was not successful, retry
|
||||
IRB.CreateCondBr(Success, end_bb, do_while_bb);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@ -828,6 +1095,26 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
return PreservedAnalyses();
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 11 /* use old pass manager */
|
||||
static void registerAFLPass(const PassManagerBuilder &,
|
||||
legacy::PassManagerBase &PM) {
|
||||
|
||||
PM.add(new AFLCoverage());
|
||||
|
||||
}
|
||||
|
||||
static RegisterStandardPasses RegisterAFLPass(
|
||||
PassManagerBuilder::EP_OptimizerLast, registerAFLPass);
|
||||
|
||||
static RegisterStandardPasses RegisterAFLPass0(
|
||||
PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLPass);
|
||||
#endif
|
||||
|
||||
|
@ -31,17 +31,31 @@
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#if LLVM_MAJOR >= 11
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#else
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#endif
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/Passes/OptimizationLevel.h"
|
||||
#if LLVM_VERSION_MAJOR >= 14 /* how about stable interfaces? */
|
||||
#include "llvm/Passes/OptimizationLevel.h"
|
||||
#endif
|
||||
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#if LLVM_VERSION_MAJOR >= 4 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#else
|
||||
#include "llvm/Analysis/Verifier.h"
|
||||
#include "llvm/DebugInfo.h"
|
||||
#define nullptr 0
|
||||
#endif
|
||||
|
||||
#include <set>
|
||||
#include "afl-llvm-common.h"
|
||||
@ -50,8 +64,7 @@ using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
using DomTreeCallback = function_ref<const DominatorTree *(Function &F)>;
|
||||
|
||||
#if LLVM_MAJOR >= 11 /* use new pass manager */
|
||||
class CmpLogInstructions : public PassInfoMixin<CmpLogInstructions> {
|
||||
|
||||
public:
|
||||
@ -61,15 +74,45 @@ class CmpLogInstructions : public PassInfoMixin<CmpLogInstructions> {
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
class CmpLogInstructions : public ModulePass {
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
CmpLogInstructions() : ModulePass(ID) {
|
||||
|
||||
initInstrumentList();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if LLVM_MAJOR >= 11 /* use new pass manager */
|
||||
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
|
||||
#else
|
||||
bool runOnModule(Module &M) override;
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 4
|
||||
StringRef getPassName() const override {
|
||||
|
||||
#else
|
||||
const char *getPassName() const override {
|
||||
|
||||
#endif
|
||||
return "cmplog instructions";
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool hookInstrs(Module &M, DomTreeCallback DTCallback);
|
||||
bool hookInstrs(Module &M);
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#if LLVM_MAJOR >= 11
|
||||
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
|
||||
llvmGetPassPluginInfo() {
|
||||
|
||||
@ -77,15 +120,15 @@ llvmGetPassPluginInfo() {
|
||||
/* lambda to insert our pass into the pass pipeline. */
|
||||
[](PassBuilder &PB) {
|
||||
|
||||
#if LLVM_VERSION_MAJOR <= 13
|
||||
#if LLVM_VERSION_MAJOR <= 13
|
||||
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
|
||||
#endif
|
||||
#endif
|
||||
PB.registerOptimizerLastEPCallback([](ModulePassManager &MPM,
|
||||
OptimizationLevel OL
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
,
|
||||
ThinOrFullLTOPhase Phase
|
||||
#endif
|
||||
#endif
|
||||
) {
|
||||
|
||||
MPM.addPass(CmpLogInstructions());
|
||||
@ -96,6 +139,10 @@ llvmGetPassPluginInfo() {
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
char CmpLogInstructions::ID = 0;
|
||||
#endif
|
||||
|
||||
template <class Iterator>
|
||||
Iterator Unique(Iterator first, Iterator last) {
|
||||
|
||||
@ -111,16 +158,7 @@ Iterator Unique(Iterator first, Iterator last) {
|
||||
|
||||
}
|
||||
|
||||
bool IsBackEdge(BasicBlock *From, BasicBlock *To, const DominatorTree *DT) {
|
||||
|
||||
if (DT->dominates(To, From)) return true;
|
||||
if (auto Next = To->getUniqueSuccessor())
|
||||
if (DT->dominates(Next, From)) return true;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
|
||||
bool CmpLogInstructions::hookInstrs(Module &M) {
|
||||
|
||||
std::vector<Instruction *> icomps;
|
||||
LLVMContext &C = M.getContext();
|
||||
@ -152,25 +190,95 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
|
||||
#endif
|
||||
*/
|
||||
|
||||
FunctionCallee c2 = M.getOrInsertFunction("__cmplog_ins_hook2", VoidTy,
|
||||
Int16Ty, Int16Ty, Int8Ty);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee
|
||||
#else
|
||||
Constant *
|
||||
#endif
|
||||
c2 = M.getOrInsertFunction("__cmplog_ins_hook2", VoidTy, Int16Ty, Int16Ty,
|
||||
Int8Ty
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee cmplogHookIns2 = c2;
|
||||
#else
|
||||
Function *cmplogHookIns2 = cast<Function>(c2);
|
||||
#endif
|
||||
|
||||
FunctionCallee c4 = M.getOrInsertFunction("__cmplog_ins_hook4", VoidTy,
|
||||
Int32Ty, Int32Ty, Int8Ty);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee
|
||||
#else
|
||||
Constant *
|
||||
#endif
|
||||
c4 = M.getOrInsertFunction("__cmplog_ins_hook4", VoidTy, Int32Ty, Int32Ty,
|
||||
Int8Ty
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee cmplogHookIns4 = c4;
|
||||
#else
|
||||
Function *cmplogHookIns4 = cast<Function>(c4);
|
||||
#endif
|
||||
|
||||
FunctionCallee c8 = M.getOrInsertFunction("__cmplog_ins_hook8", VoidTy,
|
||||
Int64Ty, Int64Ty, Int8Ty);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee
|
||||
#else
|
||||
Constant *
|
||||
#endif
|
||||
c8 = M.getOrInsertFunction("__cmplog_ins_hook8", VoidTy, Int64Ty, Int64Ty,
|
||||
Int8Ty
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee cmplogHookIns8 = c8;
|
||||
#else
|
||||
Function *cmplogHookIns8 = cast<Function>(c8);
|
||||
#endif
|
||||
|
||||
FunctionCallee c16 = M.getOrInsertFunction("__cmplog_ins_hook16", VoidTy,
|
||||
Int128Ty, Int128Ty, Int8Ty);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee
|
||||
#else
|
||||
Constant *
|
||||
#endif
|
||||
c16 = M.getOrInsertFunction("__cmplog_ins_hook16", VoidTy, Int128Ty,
|
||||
Int128Ty, Int8Ty
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
Function *cmplogHookIns16 = cast<Function>(c16);
|
||||
#else
|
||||
FunctionCallee cmplogHookIns16 = c16;
|
||||
#endif
|
||||
|
||||
FunctionCallee cN = M.getOrInsertFunction("__cmplog_ins_hookN", VoidTy,
|
||||
Int128Ty, Int128Ty, Int8Ty, Int8Ty);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee
|
||||
#else
|
||||
Constant *
|
||||
#endif
|
||||
cN = M.getOrInsertFunction("__cmplog_ins_hookN", VoidTy, Int128Ty,
|
||||
Int128Ty, Int8Ty, Int8Ty
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee cmplogHookInsN = cN;
|
||||
#else
|
||||
Function *cmplogHookInsN = cast<Function>(cN);
|
||||
#endif
|
||||
|
||||
GlobalVariable *AFLCmplogPtr = M.getNamedGlobal("__afl_cmp_map");
|
||||
|
||||
@ -188,7 +296,6 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
|
||||
for (auto &F : M) {
|
||||
|
||||
if (!isInInstrumentList(&F, MNAME)) continue;
|
||||
const DominatorTree *DT = DTCallback(F);
|
||||
|
||||
for (auto &BB : F) {
|
||||
|
||||
@ -197,12 +304,6 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
|
||||
CmpInst *selectcmpInst = nullptr;
|
||||
if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) {
|
||||
|
||||
// skip loop comparisons
|
||||
if (selectcmpInst->hasOneUse())
|
||||
if (auto BR = dyn_cast<BranchInst>(selectcmpInst->user_back()))
|
||||
for (BasicBlock *B : BR->successors())
|
||||
if (IsBackEdge(BR->getParent(), B, DT)) continue;
|
||||
|
||||
icomps.push_back(selectcmpInst);
|
||||
|
||||
}
|
||||
@ -222,8 +323,11 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
|
||||
|
||||
IRBuilder<> IRB2(selectcmpInst->getParent());
|
||||
IRB2.SetInsertPoint(selectcmpInst);
|
||||
LoadInst *CmpPtr =
|
||||
IRB2.CreateLoad(PointerType::get(Int8Ty, 0), AFLCmplogPtr);
|
||||
LoadInst *CmpPtr = IRB2.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
PointerType::get(Int8Ty, 0),
|
||||
#endif
|
||||
AFLCmplogPtr);
|
||||
CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
|
||||
auto ThenTerm =
|
||||
@ -297,12 +401,18 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
|
||||
|
||||
}
|
||||
|
||||
#if (LLVM_VERSION_MAJOR >= 12)
|
||||
vector_cnt = tt->getElementCount().getKnownMinValue();
|
||||
ty0 = tt->getElementType();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
if (ty0->isHalfTy() || ty0->isBFloatTy())
|
||||
if (ty0->isHalfTy()
|
||||
#if LLVM_VERSION_MAJOR >= 11
|
||||
|| ty0->isBFloatTy()
|
||||
#endif
|
||||
)
|
||||
max_size = 16;
|
||||
else if (ty0->isFloatTy())
|
||||
max_size = 32;
|
||||
@ -312,9 +422,11 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
|
||||
max_size = 80;
|
||||
else if (ty0->isFP128Ty() || ty0->isPPC_FP128Ty())
|
||||
max_size = 128;
|
||||
#if (LLVM_VERSION_MAJOR >= 12)
|
||||
else if (ty0->getTypeID() != llvm::Type::PointerTyID && !be_quiet)
|
||||
fprintf(stderr, "Warning: unsupported cmp type for cmplog: %u!\n",
|
||||
ty0->getTypeID());
|
||||
#endif
|
||||
|
||||
attr += 8;
|
||||
is_fp = 1;
|
||||
@ -324,6 +436,7 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
|
||||
|
||||
if (ty0->isVectorTy()) {
|
||||
|
||||
#if (LLVM_VERSION_MAJOR >= 12)
|
||||
VectorType *tt = dyn_cast<VectorType>(ty0);
|
||||
if (!tt) {
|
||||
|
||||
@ -334,6 +447,7 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
|
||||
|
||||
vector_cnt = tt->getElementCount().getKnownMinValue();
|
||||
ty1 = ty0 = tt->getElementType();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@ -348,6 +462,7 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
|
||||
|
||||
} else {
|
||||
|
||||
#if (LLVM_VERSION_MAJOR >= 12)
|
||||
if (ty0->getTypeID() != llvm::Type::PointerTyID && !be_quiet) {
|
||||
|
||||
fprintf(stderr, "Warning: unsupported cmp type for cmplog: %u\n",
|
||||
@ -355,6 +470,8 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -555,27 +672,52 @@ bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) {
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_MAJOR >= 11 /* use new pass manager */
|
||||
PreservedAnalyses CmpLogInstructions::run(Module &M,
|
||||
ModuleAnalysisManager &MAM) {
|
||||
|
||||
auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
|
||||
auto DTCallback = [&FAM](Function &F) -> const DominatorTree *{
|
||||
#else
|
||||
bool CmpLogInstructions::runOnModule(Module &M) {
|
||||
|
||||
return &FAM.getResult<DominatorTreeAnalysis>(F);
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
if (getenv("AFL_QUIET") == NULL)
|
||||
printf("Running cmplog-instructions-pass by andreafioraldi@gmail.com\n");
|
||||
else
|
||||
be_quiet = 1;
|
||||
|
||||
bool ret = hookInstrs(M, DTCallback);
|
||||
bool ret = hookInstrs(M);
|
||||
verifyModule(M);
|
||||
|
||||
#if LLVM_MAJOR >= 11 /* use new pass manager */
|
||||
if (ret == false)
|
||||
return PreservedAnalyses::all();
|
||||
else
|
||||
return PreservedAnalyses();
|
||||
#else
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_MAJOR < 11 /* use old pass manager */
|
||||
static void registerCmpLogInstructionsPass(const PassManagerBuilder &,
|
||||
legacy::PassManagerBase &PM) {
|
||||
|
||||
auto p = new CmpLogInstructions();
|
||||
PM.add(p);
|
||||
|
||||
}
|
||||
|
||||
static RegisterStandardPasses RegisterCmpLogInstructionsPass(
|
||||
PassManagerBuilder::EP_OptimizerLast, registerCmpLogInstructionsPass);
|
||||
|
||||
static RegisterStandardPasses RegisterCmpLogInstructionsPass0(
|
||||
PassManagerBuilder::EP_EnabledOnOptLevel0, registerCmpLogInstructionsPass);
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11
|
||||
static RegisterStandardPasses RegisterCmpLogInstructionsPassLTO(
|
||||
PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
|
||||
registerCmpLogInstructionsPass);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -27,9 +27,14 @@
|
||||
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#else
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#endif
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
@ -41,8 +46,15 @@
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#if LLVM_VERSION_MAJOR >= 4 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#else
|
||||
#include "llvm/Analysis/Verifier.h"
|
||||
#include "llvm/DebugInfo.h"
|
||||
#define nullptr 0
|
||||
#endif
|
||||
|
||||
#include <set>
|
||||
#include "afl-llvm-common.h"
|
||||
@ -51,16 +63,42 @@ using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
class CmpLogRoutines : public PassInfoMixin<CmpLogRoutines> {
|
||||
|
||||
public:
|
||||
CmpLogRoutines() {
|
||||
|
||||
#else
|
||||
class CmpLogRoutines : public ModulePass {
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
CmpLogRoutines() : ModulePass(ID) {
|
||||
|
||||
#endif
|
||||
|
||||
initInstrumentList();
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
|
||||
#else
|
||||
bool runOnModule(Module &M) override;
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 4
|
||||
StringRef getPassName() const override {
|
||||
|
||||
#else
|
||||
const char *getPassName() const override {
|
||||
|
||||
#endif
|
||||
return "cmplog routines";
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool hookRtns(Module &M);
|
||||
@ -69,6 +107,7 @@ class CmpLogRoutines : public PassInfoMixin<CmpLogRoutines> {
|
||||
|
||||
} // namespace
|
||||
|
||||
#if LLVM_MAJOR >= 11
|
||||
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
|
||||
llvmGetPassPluginInfo() {
|
||||
|
||||
@ -76,15 +115,15 @@ llvmGetPassPluginInfo() {
|
||||
/* lambda to insert our pass into the pass pipeline. */
|
||||
[](PassBuilder &PB) {
|
||||
|
||||
#if LLVM_VERSION_MAJOR <= 13
|
||||
#if LLVM_VERSION_MAJOR <= 13
|
||||
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
|
||||
#endif
|
||||
#endif
|
||||
PB.registerOptimizerLastEPCallback([](ModulePassManager &MPM,
|
||||
OptimizationLevel OL
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
,
|
||||
ThinOrFullLTOPhase Phase
|
||||
#endif
|
||||
#endif
|
||||
) {
|
||||
|
||||
MPM.addPass(CmpLogRoutines());
|
||||
@ -95,6 +134,10 @@ llvmGetPassPluginInfo() {
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
char CmpLogRoutines::ID = 0;
|
||||
#endif
|
||||
|
||||
bool CmpLogRoutines::hookRtns(Module &M) {
|
||||
|
||||
std::vector<CallInst *> calls, llvmStdStd, llvmStdC, gccStdStd, gccStdC,
|
||||
@ -107,37 +150,148 @@ bool CmpLogRoutines::hookRtns(Module &M) {
|
||||
IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
|
||||
PointerType *i8PtrTy = PointerType::get(Int8Ty, 0);
|
||||
|
||||
FunctionCallee c =
|
||||
M.getOrInsertFunction("__cmplog_rtn_hook", VoidTy, i8PtrTy, i8PtrTy);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee
|
||||
#else
|
||||
Constant *
|
||||
#endif
|
||||
c = M.getOrInsertFunction("__cmplog_rtn_hook", VoidTy, i8PtrTy, i8PtrTy
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee cmplogHookFn = c;
|
||||
#else
|
||||
Function *cmplogHookFn = cast<Function>(c);
|
||||
#endif
|
||||
|
||||
FunctionCallee c1 = M.getOrInsertFunction(
|
||||
"__cmplog_rtn_llvm_stdstring_stdstring", VoidTy, i8PtrTy, i8PtrTy);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee
|
||||
#else
|
||||
Constant *
|
||||
#endif
|
||||
c1 = M.getOrInsertFunction("__cmplog_rtn_llvm_stdstring_stdstring",
|
||||
VoidTy, i8PtrTy, i8PtrTy
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee cmplogLlvmStdStd = c1;
|
||||
#else
|
||||
Function *cmplogLlvmStdStd = cast<Function>(c1);
|
||||
#endif
|
||||
|
||||
FunctionCallee c2 = M.getOrInsertFunction(
|
||||
"__cmplog_rtn_llvm_stdstring_cstring", VoidTy, i8PtrTy, i8PtrTy);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee
|
||||
#else
|
||||
Constant *
|
||||
#endif
|
||||
c2 = M.getOrInsertFunction("__cmplog_rtn_llvm_stdstring_cstring", VoidTy,
|
||||
i8PtrTy, i8PtrTy
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee cmplogLlvmStdC = c2;
|
||||
#else
|
||||
Function *cmplogLlvmStdC = cast<Function>(c2);
|
||||
#endif
|
||||
|
||||
FunctionCallee c3 = M.getOrInsertFunction(
|
||||
"__cmplog_rtn_gcc_stdstring_stdstring", VoidTy, i8PtrTy, i8PtrTy);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee
|
||||
#else
|
||||
Constant *
|
||||
#endif
|
||||
c3 = M.getOrInsertFunction("__cmplog_rtn_gcc_stdstring_stdstring", VoidTy,
|
||||
i8PtrTy, i8PtrTy
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee cmplogGccStdStd = c3;
|
||||
#else
|
||||
Function *cmplogGccStdStd = cast<Function>(c3);
|
||||
#endif
|
||||
|
||||
FunctionCallee c4 = M.getOrInsertFunction(
|
||||
"__cmplog_rtn_gcc_stdstring_cstring", VoidTy, i8PtrTy, i8PtrTy);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee
|
||||
#else
|
||||
Constant *
|
||||
#endif
|
||||
c4 = M.getOrInsertFunction("__cmplog_rtn_gcc_stdstring_cstring", VoidTy,
|
||||
i8PtrTy, i8PtrTy
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee cmplogGccStdC = c4;
|
||||
#else
|
||||
Function *cmplogGccStdC = cast<Function>(c4);
|
||||
#endif
|
||||
|
||||
FunctionCallee c5 = M.getOrInsertFunction("__cmplog_rtn_hook_n", VoidTy,
|
||||
i8PtrTy, i8PtrTy, Int64Ty);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee
|
||||
#else
|
||||
Constant *
|
||||
#endif
|
||||
c5 = M.getOrInsertFunction("__cmplog_rtn_hook_n", VoidTy, i8PtrTy,
|
||||
i8PtrTy, Int64Ty
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee cmplogHookFnN = c5;
|
||||
#else
|
||||
Function *cmplogHookFnN = cast<Function>(c5);
|
||||
#endif
|
||||
|
||||
FunctionCallee c6 = M.getOrInsertFunction("__cmplog_rtn_hook_strn", VoidTy,
|
||||
i8PtrTy, i8PtrTy, Int64Ty);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee
|
||||
#else
|
||||
Constant *
|
||||
#endif
|
||||
c6 = M.getOrInsertFunction("__cmplog_rtn_hook_strn", VoidTy, i8PtrTy,
|
||||
i8PtrTy, Int64Ty
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee cmplogHookFnStrN = c6;
|
||||
#else
|
||||
Function *cmplogHookFnStrN = cast<Function>(c6);
|
||||
#endif
|
||||
|
||||
FunctionCallee c7 =
|
||||
M.getOrInsertFunction("__cmplog_rtn_hook_str", VoidTy, i8PtrTy, i8PtrTy);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee
|
||||
#else
|
||||
Constant *
|
||||
#endif
|
||||
c7 = M.getOrInsertFunction("__cmplog_rtn_hook_str", VoidTy, i8PtrTy,
|
||||
i8PtrTy
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee cmplogHookFnStr = c7;
|
||||
#else
|
||||
Function *cmplogHookFnStr = cast<Function>(c7);
|
||||
#endif
|
||||
|
||||
GlobalVariable *AFLCmplogPtr = M.getNamedGlobal("__afl_cmp_map");
|
||||
|
||||
@ -332,7 +486,7 @@ bool CmpLogRoutines::hookRtns(Module &M) {
|
||||
|
||||
if (!calls.size() && !gccStdStd.size() && !gccStdC.size() &&
|
||||
!llvmStdStd.size() && !llvmStdC.size() && !Memcmp.size() &&
|
||||
!Strcmp.size() && !Strncmp.size())
|
||||
Strcmp.size() && Strncmp.size())
|
||||
return false;
|
||||
|
||||
/*
|
||||
@ -348,8 +502,11 @@ bool CmpLogRoutines::hookRtns(Module &M) {
|
||||
IRBuilder<> IRB2(callInst->getParent());
|
||||
IRB2.SetInsertPoint(callInst);
|
||||
|
||||
LoadInst *CmpPtr =
|
||||
IRB2.CreateLoad(PointerType::get(Int8Ty, 0), AFLCmplogPtr);
|
||||
LoadInst *CmpPtr = IRB2.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
PointerType::get(Int8Ty, 0),
|
||||
#endif
|
||||
AFLCmplogPtr);
|
||||
CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
|
||||
auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
|
||||
@ -376,8 +533,11 @@ bool CmpLogRoutines::hookRtns(Module &M) {
|
||||
IRBuilder<> IRB2(callInst->getParent());
|
||||
IRB2.SetInsertPoint(callInst);
|
||||
|
||||
LoadInst *CmpPtr =
|
||||
IRB2.CreateLoad(PointerType::get(Int8Ty, 0), AFLCmplogPtr);
|
||||
LoadInst *CmpPtr = IRB2.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
PointerType::get(Int8Ty, 0),
|
||||
#endif
|
||||
AFLCmplogPtr);
|
||||
CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
|
||||
auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
|
||||
@ -408,8 +568,11 @@ bool CmpLogRoutines::hookRtns(Module &M) {
|
||||
IRBuilder<> IRB2(callInst->getParent());
|
||||
IRB2.SetInsertPoint(callInst);
|
||||
|
||||
LoadInst *CmpPtr =
|
||||
IRB2.CreateLoad(PointerType::get(Int8Ty, 0), AFLCmplogPtr);
|
||||
LoadInst *CmpPtr = IRB2.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
PointerType::get(Int8Ty, 0),
|
||||
#endif
|
||||
AFLCmplogPtr);
|
||||
CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
|
||||
auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
|
||||
@ -436,8 +599,11 @@ bool CmpLogRoutines::hookRtns(Module &M) {
|
||||
IRBuilder<> IRB2(callInst->getParent());
|
||||
IRB2.SetInsertPoint(callInst);
|
||||
|
||||
LoadInst *CmpPtr =
|
||||
IRB2.CreateLoad(PointerType::get(Int8Ty, 0), AFLCmplogPtr);
|
||||
LoadInst *CmpPtr = IRB2.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
PointerType::get(Int8Ty, 0),
|
||||
#endif
|
||||
AFLCmplogPtr);
|
||||
CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
|
||||
auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
|
||||
@ -468,8 +634,11 @@ bool CmpLogRoutines::hookRtns(Module &M) {
|
||||
IRBuilder<> IRB2(callInst->getParent());
|
||||
IRB2.SetInsertPoint(callInst);
|
||||
|
||||
LoadInst *CmpPtr =
|
||||
IRB2.CreateLoad(PointerType::get(Int8Ty, 0), AFLCmplogPtr);
|
||||
LoadInst *CmpPtr = IRB2.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
PointerType::get(Int8Ty, 0),
|
||||
#endif
|
||||
AFLCmplogPtr);
|
||||
CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
|
||||
auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
|
||||
@ -495,8 +664,11 @@ bool CmpLogRoutines::hookRtns(Module &M) {
|
||||
IRBuilder<> IRB2(callInst->getParent());
|
||||
IRB2.SetInsertPoint(callInst);
|
||||
|
||||
LoadInst *CmpPtr =
|
||||
IRB2.CreateLoad(PointerType::get(Int8Ty, 0), AFLCmplogPtr);
|
||||
LoadInst *CmpPtr = IRB2.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
PointerType::get(Int8Ty, 0),
|
||||
#endif
|
||||
AFLCmplogPtr);
|
||||
CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
|
||||
auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
|
||||
@ -522,8 +694,11 @@ bool CmpLogRoutines::hookRtns(Module &M) {
|
||||
IRBuilder<> IRB2(callInst->getParent());
|
||||
IRB2.SetInsertPoint(callInst);
|
||||
|
||||
LoadInst *CmpPtr =
|
||||
IRB2.CreateLoad(PointerType::get(Int8Ty, 0), AFLCmplogPtr);
|
||||
LoadInst *CmpPtr = IRB2.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
PointerType::get(Int8Ty, 0),
|
||||
#endif
|
||||
AFLCmplogPtr);
|
||||
CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
|
||||
auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
|
||||
@ -549,8 +724,11 @@ bool CmpLogRoutines::hookRtns(Module &M) {
|
||||
IRBuilder<> IRB2(callInst->getParent());
|
||||
IRB2.SetInsertPoint(callInst);
|
||||
|
||||
LoadInst *CmpPtr =
|
||||
IRB2.CreateLoad(PointerType::get(Int8Ty, 0), AFLCmplogPtr);
|
||||
LoadInst *CmpPtr = IRB2.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
PointerType::get(Int8Ty, 0),
|
||||
#endif
|
||||
AFLCmplogPtr);
|
||||
CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
|
||||
auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
|
||||
@ -573,8 +751,14 @@ bool CmpLogRoutines::hookRtns(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
PreservedAnalyses CmpLogRoutines::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
|
||||
#else
|
||||
bool CmpLogRoutines::runOnModule(Module &M) {
|
||||
|
||||
#endif
|
||||
|
||||
if (getenv("AFL_QUIET") == NULL)
|
||||
printf("Running cmplog-routines-pass by andreafioraldi@gmail.com\n");
|
||||
else
|
||||
@ -582,10 +766,36 @@ PreservedAnalyses CmpLogRoutines::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
bool ret = hookRtns(M);
|
||||
verifyModule(M);
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
if (ret == false)
|
||||
return PreservedAnalyses::all();
|
||||
else
|
||||
return PreservedAnalyses();
|
||||
#else
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 11 /* use old pass manager */
|
||||
static void registerCmpLogRoutinesPass(const PassManagerBuilder &,
|
||||
legacy::PassManagerBase &PM) {
|
||||
|
||||
auto p = new CmpLogRoutines();
|
||||
PM.add(p);
|
||||
|
||||
}
|
||||
|
||||
static RegisterStandardPasses RegisterCmpLogRoutinesPass(
|
||||
PassManagerBuilder::EP_OptimizerLast, registerCmpLogRoutinesPass);
|
||||
|
||||
static RegisterStandardPasses RegisterCmpLogRoutinesPass0(
|
||||
PassManagerBuilder::EP_EnabledOnOptLevel0, registerCmpLogRoutinesPass);
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11
|
||||
static RegisterStandardPasses RegisterCmpLogRoutinesPassLTO(
|
||||
PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
|
||||
registerCmpLogRoutinesPass);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -28,9 +28,14 @@
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#else
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#endif
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
@ -42,8 +47,15 @@
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#if LLVM_VERSION_MAJOR >= 4 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#else
|
||||
#include "llvm/Analysis/Verifier.h"
|
||||
#include "llvm/DebugInfo.h"
|
||||
#define nullptr 0
|
||||
#endif
|
||||
|
||||
#include <set>
|
||||
#include "afl-llvm-common.h"
|
||||
@ -52,16 +64,41 @@ using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
class CmplogSwitches : public PassInfoMixin<CmplogSwitches> {
|
||||
|
||||
public:
|
||||
CmplogSwitches() {
|
||||
|
||||
#else
|
||||
class CmplogSwitches : public ModulePass {
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
CmplogSwitches() : ModulePass(ID) {
|
||||
|
||||
#endif
|
||||
initInstrumentList();
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
|
||||
#else
|
||||
bool runOnModule(Module &M) override;
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 4
|
||||
const char *getPassName() const override {
|
||||
|
||||
#else
|
||||
StringRef getPassName() const override {
|
||||
|
||||
#endif
|
||||
return "cmplog switch split";
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool hookInstrs(Module &M);
|
||||
@ -70,6 +107,7 @@ class CmplogSwitches : public PassInfoMixin<CmplogSwitches> {
|
||||
|
||||
} // namespace
|
||||
|
||||
#if LLVM_MAJOR >= 11
|
||||
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
|
||||
llvmGetPassPluginInfo() {
|
||||
|
||||
@ -77,15 +115,15 @@ llvmGetPassPluginInfo() {
|
||||
/* lambda to insert our pass into the pass pipeline. */
|
||||
[](PassBuilder &PB) {
|
||||
|
||||
#if LLVM_VERSION_MAJOR <= 13
|
||||
#if LLVM_VERSION_MAJOR <= 13
|
||||
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
|
||||
#endif
|
||||
#endif
|
||||
PB.registerOptimizerLastEPCallback([](ModulePassManager &MPM,
|
||||
OptimizationLevel OL
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
,
|
||||
ThinOrFullLTOPhase Phase
|
||||
#endif
|
||||
#endif
|
||||
) {
|
||||
|
||||
MPM.addPass(CmplogSwitches());
|
||||
@ -96,6 +134,10 @@ llvmGetPassPluginInfo() {
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
char CmplogSwitches::ID = 0;
|
||||
#endif
|
||||
|
||||
template <class Iterator>
|
||||
Iterator Unique(Iterator first, Iterator last) {
|
||||
|
||||
@ -122,21 +164,77 @@ bool CmplogSwitches::hookInstrs(Module &M) {
|
||||
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
|
||||
IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
|
||||
|
||||
FunctionCallee c1 = M.getOrInsertFunction("__cmplog_ins_hook1", VoidTy,
|
||||
Int8Ty, Int8Ty, Int8Ty);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee
|
||||
#else
|
||||
Constant *
|
||||
#endif
|
||||
c1 = M.getOrInsertFunction("__cmplog_ins_hook1", VoidTy, Int8Ty, Int8Ty,
|
||||
Int8Ty
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee cmplogHookIns1 = c1;
|
||||
#else
|
||||
Function *cmplogHookIns1 = cast<Function>(c1);
|
||||
#endif
|
||||
|
||||
FunctionCallee c2 = M.getOrInsertFunction("__cmplog_ins_hook2", VoidTy,
|
||||
Int16Ty, Int16Ty, Int8Ty);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee
|
||||
#else
|
||||
Constant *
|
||||
#endif
|
||||
c2 = M.getOrInsertFunction("__cmplog_ins_hook2", VoidTy, Int16Ty, Int16Ty,
|
||||
Int8Ty
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee cmplogHookIns2 = c2;
|
||||
#else
|
||||
Function *cmplogHookIns2 = cast<Function>(c2);
|
||||
#endif
|
||||
|
||||
FunctionCallee c4 = M.getOrInsertFunction("__cmplog_ins_hook4", VoidTy,
|
||||
Int32Ty, Int32Ty, Int8Ty);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee
|
||||
#else
|
||||
Constant *
|
||||
#endif
|
||||
c4 = M.getOrInsertFunction("__cmplog_ins_hook4", VoidTy, Int32Ty, Int32Ty,
|
||||
Int8Ty
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee cmplogHookIns4 = c4;
|
||||
#else
|
||||
Function *cmplogHookIns4 = cast<Function>(c4);
|
||||
#endif
|
||||
|
||||
FunctionCallee c8 = M.getOrInsertFunction("__cmplog_ins_hook8", VoidTy,
|
||||
Int64Ty, Int64Ty, Int8Ty);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee
|
||||
#else
|
||||
Constant *
|
||||
#endif
|
||||
c8 = M.getOrInsertFunction("__cmplog_ins_hook8", VoidTy, Int64Ty, Int64Ty,
|
||||
Int8Ty
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee cmplogHookIns8 = c8;
|
||||
#else
|
||||
Function *cmplogHookIns8 = cast<Function>(c8);
|
||||
#endif
|
||||
|
||||
GlobalVariable *AFLCmplogPtr = M.getNamedGlobal("__afl_cmp_map");
|
||||
|
||||
@ -200,8 +298,11 @@ bool CmplogSwitches::hookInstrs(Module &M) {
|
||||
IRBuilder<> IRB2(SI->getParent());
|
||||
IRB2.SetInsertPoint(SI);
|
||||
|
||||
LoadInst *CmpPtr =
|
||||
IRB2.CreateLoad(PointerType::get(Int8Ty, 0), AFLCmplogPtr);
|
||||
LoadInst *CmpPtr = IRB2.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
PointerType::get(Int8Ty, 0),
|
||||
#endif
|
||||
AFLCmplogPtr);
|
||||
CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
|
||||
auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, SI, false);
|
||||
@ -251,7 +352,11 @@ bool CmplogSwitches::hookInstrs(Module &M) {
|
||||
for (SwitchInst::CaseIt i = SI->case_begin(), e = SI->case_end(); i != e;
|
||||
++i) {
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
ConstantInt *cint = i.getCaseValue();
|
||||
#else
|
||||
ConstantInt *cint = i->getCaseValue();
|
||||
#endif
|
||||
|
||||
if (cint) {
|
||||
|
||||
@ -330,8 +435,14 @@ bool CmplogSwitches::hookInstrs(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
PreservedAnalyses CmplogSwitches::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
|
||||
#else
|
||||
bool CmplogSwitches::runOnModule(Module &M) {
|
||||
|
||||
#endif
|
||||
|
||||
if (getenv("AFL_QUIET") == NULL)
|
||||
printf("Running cmplog-switches-pass by andreafioraldi@gmail.com\n");
|
||||
else
|
||||
@ -339,10 +450,36 @@ PreservedAnalyses CmplogSwitches::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
bool ret = hookInstrs(M);
|
||||
verifyModule(M);
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
if (ret == false)
|
||||
return PreservedAnalyses::all();
|
||||
else
|
||||
return PreservedAnalyses();
|
||||
#else
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 11 /* use old pass manager */
|
||||
static void registerCmplogSwitchesPass(const PassManagerBuilder &,
|
||||
legacy::PassManagerBase &PM) {
|
||||
|
||||
auto p = new CmplogSwitches();
|
||||
PM.add(p);
|
||||
|
||||
}
|
||||
|
||||
static RegisterStandardPasses RegisterCmplogSwitchesPass(
|
||||
PassManagerBuilder::EP_OptimizerLast, registerCmplogSwitchesPass);
|
||||
|
||||
static RegisterStandardPasses RegisterCmplogSwitchesPass0(
|
||||
PassManagerBuilder::EP_EnabledOnOptLevel0, registerCmplogSwitchesPass);
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11
|
||||
static RegisterStandardPasses RegisterCmplogSwitchesPassLTO(
|
||||
PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
|
||||
registerCmplogSwitchesPass);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -27,9 +27,14 @@
|
||||
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#else
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#endif
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
@ -41,8 +46,15 @@
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#if LLVM_VERSION_MAJOR >= 4 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#else
|
||||
#include "llvm/Analysis/Verifier.h"
|
||||
#include "llvm/DebugInfo.h"
|
||||
#define nullptr 0
|
||||
#endif
|
||||
|
||||
#include <set>
|
||||
#include "afl-llvm-common.h"
|
||||
@ -51,16 +63,42 @@ using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
class InjectionRoutines : public PassInfoMixin<InjectionRoutines> {
|
||||
|
||||
public:
|
||||
InjectionRoutines() {
|
||||
|
||||
#else
|
||||
class InjectionRoutines : public ModulePass {
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
InjectionRoutines() : ModulePass(ID) {
|
||||
|
||||
#endif
|
||||
|
||||
initInstrumentList();
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
|
||||
#else
|
||||
bool runOnModule(Module &M) override;
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 4
|
||||
StringRef getPassName() const override {
|
||||
|
||||
#else
|
||||
const char *getPassName() const override {
|
||||
|
||||
#endif
|
||||
return "Injection routines";
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool hookRtns(Module &M);
|
||||
@ -73,6 +111,7 @@ class InjectionRoutines : public PassInfoMixin<InjectionRoutines> {
|
||||
|
||||
} // namespace
|
||||
|
||||
#if LLVM_MAJOR >= 11
|
||||
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
|
||||
llvmGetPassPluginInfo() {
|
||||
|
||||
@ -80,12 +119,15 @@ llvmGetPassPluginInfo() {
|
||||
/* lambda to insert our pass into the pass pipeline. */
|
||||
[](PassBuilder &PB) {
|
||||
|
||||
#if LLVM_VERSION_MAJOR <= 13
|
||||
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
|
||||
#endif
|
||||
PB.registerOptimizerLastEPCallback([](ModulePassManager &MPM,
|
||||
OptimizationLevel OL
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
,
|
||||
ThinOrFullLTOPhase Phase
|
||||
#endif
|
||||
#endif
|
||||
) {
|
||||
|
||||
MPM.addPass(InjectionRoutines());
|
||||
@ -96,6 +138,10 @@ llvmGetPassPluginInfo() {
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
char InjectionRoutines::ID = 0;
|
||||
#endif
|
||||
|
||||
bool InjectionRoutines::hookRtns(Module &M) {
|
||||
|
||||
std::vector<CallInst *> calls, llvmStdStd, llvmStdC, gccStdStd, gccStdC,
|
||||
@ -106,19 +152,62 @@ bool InjectionRoutines::hookRtns(Module &M) {
|
||||
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
|
||||
PointerType *i8PtrTy = PointerType::get(Int8Ty, 0);
|
||||
|
||||
FunctionCallee c1 =
|
||||
M.getOrInsertFunction("__afl_injection_sql", VoidTy, i8PtrTy);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee
|
||||
#else
|
||||
Constant *
|
||||
#endif
|
||||
c1 = M.getOrInsertFunction("__afl_injection_sql", VoidTy, i8PtrTy
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee sqlfunc = c1;
|
||||
#else
|
||||
Function *sqlfunc = cast<Function>(c1);
|
||||
#endif
|
||||
|
||||
FunctionCallee c2 =
|
||||
M.getOrInsertFunction("__afl_injection_ldap", VoidTy, i8PtrTy);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee
|
||||
#else
|
||||
Constant *
|
||||
#endif
|
||||
c2 = M.getOrInsertFunction("__afl_injection_ldap", VoidTy, i8PtrTy
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee ldapfunc = c2;
|
||||
#else
|
||||
Function *ldapfunc = cast<Function>(c2);
|
||||
#endif
|
||||
|
||||
FunctionCallee c3 =
|
||||
M.getOrInsertFunction("__afl_injection_xss", VoidTy, i8PtrTy);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee
|
||||
#else
|
||||
Constant *
|
||||
#endif
|
||||
c3 = M.getOrInsertFunction("__afl_injection_xss", VoidTy, i8PtrTy
|
||||
#if LLVM_VERSION_MAJOR < 5
|
||||
,
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee xssfunc = c3;
|
||||
#else
|
||||
Function *xssfunc = cast<Function>(c3);
|
||||
#endif
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
FunctionCallee FuncPtr;
|
||||
#else
|
||||
Function *FuncPtr;
|
||||
#endif
|
||||
|
||||
bool ret = false;
|
||||
|
||||
@ -222,9 +311,15 @@ bool InjectionRoutines::hookRtns(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
PreservedAnalyses InjectionRoutines::run(Module &M,
|
||||
ModuleAnalysisManager &MAM) {
|
||||
|
||||
#else
|
||||
bool InjectionRoutines::runOnModule(Module &M) {
|
||||
|
||||
#endif
|
||||
|
||||
if (getenv("AFL_QUIET") == NULL)
|
||||
printf("Running injection-pass by Marc Heuse (mh@mh-sec.de)\n");
|
||||
else
|
||||
@ -244,9 +339,36 @@ PreservedAnalyses InjectionRoutines::run(Module &M,
|
||||
bool ret = hookRtns(M);
|
||||
verifyModule(M);
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
if (ret == false)
|
||||
return PreservedAnalyses::all();
|
||||
else
|
||||
return PreservedAnalyses();
|
||||
#else
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 11 /* use old pass manager */
|
||||
static void registerInjectionRoutinesPass(const PassManagerBuilder &,
|
||||
legacy::PassManagerBase &PM) {
|
||||
|
||||
auto p = new InjectionRoutines();
|
||||
PM.add(p);
|
||||
|
||||
}
|
||||
|
||||
static RegisterStandardPasses RegisterInjectionRoutinesPass(
|
||||
PassManagerBuilder::EP_OptimizerLast, registerInjectionRoutinesPass);
|
||||
|
||||
static RegisterStandardPasses RegisterInjectionRoutinesPass0(
|
||||
PassManagerBuilder::EP_EnabledOnOptLevel0, registerInjectionRoutinesPass);
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11
|
||||
static RegisterStandardPasses RegisterInjectionRoutinesPassLTO(
|
||||
PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
|
||||
registerInjectionRoutinesPass);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -30,16 +30,30 @@
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#if LLVM_MAJOR >= 11
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#else
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#endif
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Passes/OptimizationLevel.h"
|
||||
#if LLVM_VERSION_MAJOR >= 14 /* how about stable interfaces? */
|
||||
#include "llvm/Passes/OptimizationLevel.h"
|
||||
#endif
|
||||
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#if LLVM_VERSION_MAJOR >= 4 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#else
|
||||
#include "llvm/Analysis/Verifier.h"
|
||||
#include "llvm/DebugInfo.h"
|
||||
#define nullptr 0
|
||||
#endif
|
||||
|
||||
using namespace llvm;
|
||||
#include "afl-llvm-common.h"
|
||||
@ -50,17 +64,31 @@ using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
#if LLVM_MAJOR >= 11
|
||||
class SplitComparesTransform : public PassInfoMixin<SplitComparesTransform> {
|
||||
|
||||
public:
|
||||
// static char ID;
|
||||
SplitComparesTransform() : enableFPSplit(0) {
|
||||
|
||||
#else
|
||||
class SplitComparesTransform : public ModulePass {
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
SplitComparesTransform() : ModulePass(ID), enableFPSplit(0) {
|
||||
|
||||
#endif
|
||||
|
||||
initInstrumentList();
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_MAJOR >= 11
|
||||
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
|
||||
#else
|
||||
bool runOnModule(Module &M) override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
int enableFPSplit;
|
||||
@ -149,6 +177,7 @@ class SplitComparesTransform : public PassInfoMixin<SplitComparesTransform> {
|
||||
|
||||
} // namespace
|
||||
|
||||
#if LLVM_MAJOR >= 11
|
||||
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
|
||||
llvmGetPassPluginInfo() {
|
||||
|
||||
@ -156,26 +185,56 @@ llvmGetPassPluginInfo() {
|
||||
/* lambda to insert our pass into the pass pipeline. */
|
||||
[](PassBuilder &PB) {
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 16
|
||||
#if 1
|
||||
#if LLVM_VERSION_MAJOR <= 13
|
||||
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
|
||||
#endif
|
||||
#if LLVM_VERSION_MAJOR >= 16
|
||||
PB.registerOptimizerEarlyEPCallback(
|
||||
#else
|
||||
#else
|
||||
PB.registerOptimizerLastEPCallback(
|
||||
#endif
|
||||
#endif
|
||||
[](ModulePassManager &MPM, OptimizationLevel OL
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
,
|
||||
ThinOrFullLTOPhase Phase
|
||||
#endif
|
||||
#endif
|
||||
) {
|
||||
|
||||
MPM.addPass(SplitComparesTransform());
|
||||
|
||||
});
|
||||
|
||||
/* TODO LTO registration */
|
||||
#else
|
||||
using PipelineElement = typename PassBuilder::PipelineElement;
|
||||
PB.registerPipelineParsingCallback([](StringRef Name,
|
||||
ModulePassManager &MPM,
|
||||
ArrayRef<PipelineElement>) {
|
||||
|
||||
if (Name == "splitcompares") {
|
||||
|
||||
MPM.addPass(SplitComparesTransform());
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
#endif
|
||||
|
||||
}};
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
char SplitComparesTransform::ID = 0;
|
||||
#endif
|
||||
|
||||
/// This function splits FCMP instructions with xGE or xLE predicates into two
|
||||
/// FCMP instructions with predicate xGT or xLT and EQ
|
||||
bool SplitComparesTransform::simplifyFPCompares(Module &M) {
|
||||
@ -892,6 +951,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
||||
|
||||
LLVMContext &C = M.getContext();
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 4 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 7)
|
||||
const DataLayout &dl = M.getDataLayout();
|
||||
|
||||
/* define unions with floating point and (sign, exponent, mantissa) triples
|
||||
@ -906,6 +967,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
std::vector<CmpInst *> fcomps;
|
||||
|
||||
/* get all EQ, NE, GT, and LT fcmps. if the other two
|
||||
@ -1647,9 +1710,15 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_MAJOR >= 11
|
||||
PreservedAnalyses SplitComparesTransform::run(Module &M,
|
||||
ModuleAnalysisManager &MAM) {
|
||||
|
||||
#else
|
||||
bool SplitComparesTransform::runOnModule(Module &M) {
|
||||
|
||||
#endif
|
||||
|
||||
if ((isatty(2) && getenv("AFL_QUIET") == NULL) ||
|
||||
getenv("AFL_DEBUG") != NULL) {
|
||||
|
||||
@ -1754,8 +1823,12 @@ PreservedAnalyses SplitComparesTransform::run(Module &M,
|
||||
bool ret = count == 0 ? false : true;
|
||||
|
||||
bool brokenDebug = false;
|
||||
if (verifyModule(M, &errs(),
|
||||
if (verifyModule(M, &errs()
|
||||
#if LLVM_VERSION_MAJOR >= 4 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 9)
|
||||
,
|
||||
&brokenDebug // 9th May 2016
|
||||
#endif
|
||||
)) {
|
||||
|
||||
reportError(
|
||||
@ -1780,6 +1853,7 @@ PreservedAnalyses SplitComparesTransform::run(Module &M,
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_MAJOR >= 11
|
||||
/* if (modified) {
|
||||
|
||||
PA.abandon<XX_Manager>();
|
||||
@ -1790,5 +1864,36 @@ PreservedAnalyses SplitComparesTransform::run(Module &M,
|
||||
return PreservedAnalyses::all();
|
||||
else
|
||||
return PreservedAnalyses();
|
||||
#else
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_MAJOR < 11 /* use old pass manager */
|
||||
|
||||
static void registerSplitComparesPass(const PassManagerBuilder &,
|
||||
legacy::PassManagerBase &PM) {
|
||||
|
||||
PM.add(new SplitComparesTransform());
|
||||
|
||||
}
|
||||
|
||||
static RegisterStandardPasses RegisterSplitComparesPass(
|
||||
PassManagerBuilder::EP_OptimizerLast, registerSplitComparesPass);
|
||||
|
||||
static RegisterStandardPasses RegisterSplitComparesTransPass0(
|
||||
PassManagerBuilder::EP_EnabledOnOptLevel0, registerSplitComparesPass);
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11
|
||||
static RegisterStandardPasses RegisterSplitComparesTransPassLTO(
|
||||
PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
|
||||
registerSplitComparesPass);
|
||||
#endif
|
||||
|
||||
static RegisterPass<SplitComparesTransform> X("splitcompares",
|
||||
"AFL++ split compares",
|
||||
true /* Only looks at CFG */,
|
||||
true /* Analysis Pass */);
|
||||
#endif
|
||||
|
||||
|
@ -27,20 +27,34 @@
|
||||
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#else
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#endif
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/Passes/OptimizationLevel.h"
|
||||
#if LLVM_VERSION_MAJOR >= 14 /* how about stable interfaces? */
|
||||
#include "llvm/Passes/OptimizationLevel.h"
|
||||
#endif
|
||||
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#if LLVM_VERSION_MAJOR >= 4 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#else
|
||||
#include "llvm/Analysis/Verifier.h"
|
||||
#include "llvm/DebugInfo.h"
|
||||
#define nullptr 0
|
||||
#endif
|
||||
|
||||
#include <set>
|
||||
#include "afl-llvm-common.h"
|
||||
@ -49,16 +63,42 @@ using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
class SplitSwitchesTransform : public PassInfoMixin<SplitSwitchesTransform> {
|
||||
|
||||
public:
|
||||
SplitSwitchesTransform() {
|
||||
|
||||
#else
|
||||
class SplitSwitchesTransform : public ModulePass {
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
SplitSwitchesTransform() : ModulePass(ID) {
|
||||
|
||||
#endif
|
||||
initInstrumentList();
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
|
||||
#else
|
||||
bool runOnModule(Module &M) override;
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 4
|
||||
StringRef getPassName() const override {
|
||||
|
||||
#else
|
||||
const char *getPassName() const override {
|
||||
|
||||
#endif
|
||||
return "splits switch constructs";
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct CaseExpr {
|
||||
|
||||
ConstantInt *Val;
|
||||
@ -85,6 +125,7 @@ class SplitSwitchesTransform : public PassInfoMixin<SplitSwitchesTransform> {
|
||||
|
||||
} // namespace
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
|
||||
llvmGetPassPluginInfo() {
|
||||
|
||||
@ -92,16 +133,20 @@ llvmGetPassPluginInfo() {
|
||||
/* lambda to insert our pass into the pass pipeline. */
|
||||
[](PassBuilder &PB) {
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 16
|
||||
#if 1
|
||||
#if LLVM_VERSION_MAJOR <= 13
|
||||
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
|
||||
#endif
|
||||
#if LLVM_VERSION_MAJOR >= 16
|
||||
PB.registerOptimizerEarlyEPCallback(
|
||||
#else
|
||||
#else
|
||||
PB.registerOptimizerLastEPCallback(
|
||||
#endif
|
||||
#endif
|
||||
[](ModulePassManager &MPM, OptimizationLevel OL
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
,
|
||||
ThinOrFullLTOPhase Phase
|
||||
#endif
|
||||
#endif
|
||||
|
||||
) {
|
||||
|
||||
@ -109,10 +154,36 @@ llvmGetPassPluginInfo() {
|
||||
|
||||
});
|
||||
|
||||
/* TODO LTO registration */
|
||||
#else
|
||||
using PipelineElement = typename PassBuilder::PipelineElement;
|
||||
PB.registerPipelineParsingCallback([](StringRef Name,
|
||||
ModulePassManager &MPM,
|
||||
ArrayRef<PipelineElement>) {
|
||||
|
||||
if (Name == "splitswitches") {
|
||||
|
||||
MPM.addPass(SplitSwitchesTransform());
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
#endif
|
||||
|
||||
}};
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
char SplitSwitchesTransform::ID = 0;
|
||||
#endif
|
||||
|
||||
/* switchConvert - Transform simple list of Cases into list of CaseRange's */
|
||||
BasicBlock *SplitSwitchesTransform::switchConvert(
|
||||
CaseVector Cases, std::vector<bool> bytesChecked, BasicBlock *OrigBlock,
|
||||
@ -321,7 +392,10 @@ BasicBlock *SplitSwitchesTransform::switchConvert(
|
||||
|
||||
bool SplitSwitchesTransform::splitSwitches(Module &M) {
|
||||
|
||||
LLVMContext &C = M.getContext();
|
||||
#if (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7)
|
||||
LLVMContext &C = M.getContext();
|
||||
#endif
|
||||
|
||||
std::vector<SwitchInst *> switches;
|
||||
|
||||
/* iterate over all functions, bbs and instruction and add
|
||||
@ -388,7 +462,11 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) {
|
||||
CaseVector Cases;
|
||||
for (SwitchInst::CaseIt i = SI->case_begin(), e = SI->case_end(); i != e;
|
||||
++i)
|
||||
#if LLVM_VERSION_MAJOR >= 5
|
||||
Cases.push_back(CaseExpr(i->getCaseValue(), i->getCaseSuccessor()));
|
||||
#else
|
||||
Cases.push_back(CaseExpr(i.getCaseValue(), i.getCaseSuccessor()));
|
||||
#endif
|
||||
/* bugfix thanks to pbst
|
||||
* round up bytesChecked (in case getBitWidth() % 8 != 0) */
|
||||
std::vector<bool> bytesChecked((7 + Cases[0].Val->getBitWidth()) / 8,
|
||||
@ -434,9 +512,15 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
PreservedAnalyses SplitSwitchesTransform::run(Module &M,
|
||||
ModuleAnalysisManager &MAM) {
|
||||
|
||||
#else
|
||||
bool SplitSwitchesTransform::runOnModule(Module &M) {
|
||||
|
||||
#endif
|
||||
|
||||
if ((isatty(2) && getenv("AFL_QUIET") == NULL) || getenv("AFL_DEBUG") != NULL)
|
||||
printf("Running split-switches-pass by laf.intel@gmail.com\n");
|
||||
else
|
||||
@ -445,16 +529,42 @@ PreservedAnalyses SplitSwitchesTransform::run(Module &M,
|
||||
bool ret = splitSwitches(M);
|
||||
verifyModule(M);
|
||||
|
||||
/* if (modified) {
|
||||
|
||||
PA.abandon<XX_Manager>();
|
||||
|
||||
}*/
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
/* if (modified) {
|
||||
|
||||
PA.abandon<XX_Manager>();
|
||||
|
||||
}*/
|
||||
|
||||
if (ret == false)
|
||||
return PreservedAnalyses::all();
|
||||
else
|
||||
return PreservedAnalyses();
|
||||
#else
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 11 /* use old pass manager */
|
||||
static void registerSplitSwitchesTransPass(const PassManagerBuilder &,
|
||||
legacy::PassManagerBase &PM) {
|
||||
|
||||
auto p = new SplitSwitchesTransform();
|
||||
PM.add(p);
|
||||
|
||||
}
|
||||
|
||||
static RegisterStandardPasses RegisterSplitSwitchesTransPass(
|
||||
PassManagerBuilder::EP_OptimizerLast, registerSplitSwitchesTransPass);
|
||||
|
||||
static RegisterStandardPasses RegisterSplitSwitchesTransPass0(
|
||||
PassManagerBuilder::EP_EnabledOnOptLevel0, registerSplitSwitchesTransPass);
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11
|
||||
static RegisterStandardPasses RegisterSplitSwitchesTransPassLTO(
|
||||
PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
|
||||
registerSplitSwitchesTransPass);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -1 +1 @@
|
||||
8c7f180c5a
|
||||
ef1cd9a8cb
|
||||
|
@ -68,11 +68,6 @@ which can be a huge speed improvement.
|
||||
|
||||
For an example, see [README.deferred_initialization_example.md](README.deferred_initialization_example.md).
|
||||
|
||||
Note that there is also `AFL_EXITPOINT` which you can set to an address that
|
||||
will trigger a termination of the qemu forked instance when the block that
|
||||
contains this address is reached. Read again: when the block where the address
|
||||
is is reached!
|
||||
|
||||
## 4) Persistent mode
|
||||
|
||||
AFL++'s QEMU mode now supports also persistent mode for x86, x86_64, arm, and
|
||||
|
Submodule qemu_mode/qemuafl updated: 8c7f180c5a...ef1cd9a8cb
@ -75,6 +75,7 @@ static bool edges_only, /* Ignore hit counts? */
|
||||
static volatile u8 stop_soon; /* Ctrl-C pressed? */
|
||||
|
||||
static u8 *target_path;
|
||||
static u8 frida_mode;
|
||||
static u8 qemu_mode;
|
||||
static u8 cs_mode;
|
||||
static u32 map_size = MAP_SIZE;
|
||||
@ -627,7 +628,9 @@ static void handle_stop_sig(int sig) {
|
||||
|
||||
static void set_up_environment(char **argv) {
|
||||
|
||||
u8 *x;
|
||||
u8 *x;
|
||||
char *afl_preload;
|
||||
char *frida_afl_preload = NULL;
|
||||
|
||||
fsrv.dev_null_fd = open("/dev/null", O_RDWR);
|
||||
if (fsrv.dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
|
||||
@ -669,7 +672,57 @@ static void set_up_environment(char **argv) {
|
||||
}
|
||||
|
||||
set_sanitizer_defaults();
|
||||
afl_fsrv_setup_preload(&fsrv, argv[0]);
|
||||
|
||||
if (get_afl_env("AFL_PRELOAD")) {
|
||||
|
||||
if (qemu_mode) {
|
||||
|
||||
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
|
||||
|
||||
} else if (frida_mode) {
|
||||
|
||||
afl_preload = getenv("AFL_PRELOAD");
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
if (afl_preload) {
|
||||
|
||||
frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
|
||||
|
||||
} else {
|
||||
|
||||
frida_afl_preload = alloc_printf("%s", frida_binary);
|
||||
|
||||
}
|
||||
|
||||
ck_free(frida_binary);
|
||||
|
||||
setenv("LD_PRELOAD", frida_afl_preload, 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
|
||||
/* CoreSight mode uses the default behavior. */
|
||||
|
||||
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
} else if (frida_mode) {
|
||||
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
setenv("LD_PRELOAD", frida_binary, 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
|
||||
#endif
|
||||
ck_free(frida_binary);
|
||||
|
||||
}
|
||||
|
||||
if (frida_afl_preload) { ck_free(frida_afl_preload); }
|
||||
|
||||
}
|
||||
|
||||
@ -883,9 +936,10 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
case 'O': /* FRIDA mode */
|
||||
|
||||
if (fsrv.frida_mode) { FATAL("Multiple -O options not supported"); }
|
||||
if (frida_mode) { FATAL("Multiple -O options not supported"); }
|
||||
|
||||
fsrv.frida_mode = true;
|
||||
frida_mode = 1;
|
||||
fsrv.frida_mode = frida_mode;
|
||||
setenv("AFL_FRIDA_INST_SEED", "1", 1);
|
||||
|
||||
break;
|
||||
@ -984,7 +1038,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
fsrv.target_path = find_binary(argv[optind]);
|
||||
#endif
|
||||
|
||||
fsrv.trace_bits = afl_shm_init(&shm, map_size, 0, DEFAULT_PERMISSION, -1);
|
||||
fsrv.trace_bits = afl_shm_init(&shm, map_size, 0);
|
||||
detect_file_args(argv + optind, fsrv.out_file, &use_stdin);
|
||||
signal(SIGALRM, kill_child);
|
||||
|
||||
|
13
src/afl-cc.c
13
src/afl-cc.c
@ -244,7 +244,7 @@ static inline void insert_object(aflcc_state_t *aflcc, u8 *obj, u8 *fmt,
|
||||
/* Insert params into the new argv, make clang load the pass. */
|
||||
static inline void load_llvm_pass(aflcc_state_t *aflcc, u8 *pass) {
|
||||
|
||||
if (getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
if (getenv("AFL_SAN_NO_INST")) {
|
||||
|
||||
if (!be_quiet) { DEBUGF("SAND: Coverage instrumentation disabled\n"); }
|
||||
return;
|
||||
@ -2097,7 +2097,7 @@ void add_native_pcguard(aflcc_state_t *aflcc) {
|
||||
* anyway.
|
||||
*/
|
||||
if (aflcc->have_rust_asanrt) { return; }
|
||||
if (getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
if (getenv("AFL_SAN_NO_INST")) {
|
||||
|
||||
if (!be_quiet) { DEBUGF("SAND: Coverage instrumentation disabled\n"); }
|
||||
return;
|
||||
@ -2138,7 +2138,7 @@ void add_native_pcguard(aflcc_state_t *aflcc) {
|
||||
*/
|
||||
void add_optimized_pcguard(aflcc_state_t *aflcc) {
|
||||
|
||||
if (getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
if (getenv("AFL_SAN_NO_INST")) {
|
||||
|
||||
if (!be_quiet) { DEBUGF("SAND: Coverage instrumentation disabled\n"); }
|
||||
return;
|
||||
@ -2600,13 +2600,6 @@ void add_assembler(aflcc_state_t *aflcc) {
|
||||
/* Add params to launch the gcc plugins for instrumentation. */
|
||||
void add_gcc_plugin(aflcc_state_t *aflcc) {
|
||||
|
||||
if (getenv("AFL_GCC_ONLY_FSRV")) {
|
||||
|
||||
if (!be_quiet) { DEBUGF("SAND: Coverage instrumentation disabled\n"); }
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if (aflcc->cmplog_mode) {
|
||||
|
||||
insert_object(aflcc, "afl-gcc-cmplog-pass.so", "-fplugin=%s", 0);
|
||||
|
@ -179,7 +179,7 @@ u32 check_binary_signatures(u8 *fn) {
|
||||
if (f_data == MAP_FAILED) { PFATAL("Unable to mmap file '%s'", fn); }
|
||||
close(fd);
|
||||
|
||||
if (afl_memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG))) {
|
||||
if (afl_memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG) + 1)) {
|
||||
|
||||
if (!be_quiet) { OKF(cPIN "Persistent mode binary detected."); }
|
||||
setenv(PERSIST_ENV_VAR, "1", 1);
|
||||
@ -204,7 +204,7 @@ u32 check_binary_signatures(u8 *fn) {
|
||||
|
||||
}
|
||||
|
||||
if (afl_memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG))) {
|
||||
if (afl_memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
|
||||
|
||||
if (!be_quiet) { OKF(cPIN "Deferred forkserver binary detected."); }
|
||||
setenv(DEFER_ENV_VAR, "1", 1);
|
||||
@ -819,21 +819,7 @@ void check_environment_vars(char **envp) {
|
||||
|
||||
WARNF("AFL environment variable %s is deprecated!",
|
||||
afl_environment_deprecated[i]);
|
||||
|
||||
if (strncmp(afl_environment_deprecated[i], "AFL_SAN_NO_INST",
|
||||
strlen(afl_environment_deprecated[i])) == 0) {
|
||||
|
||||
WARNF(
|
||||
"AFL_LLVM_ONLY_FSRV/AFL_GCC_ONLY_FSRV is induced and set "
|
||||
"instead.");
|
||||
setenv("AFL_GCC_ONLY_FSRV", "1", 0);
|
||||
setenv("AFL_LLVM_ONLY_FSRV", "1", 0);
|
||||
|
||||
} else {
|
||||
|
||||
issue_detected = 1;
|
||||
|
||||
}
|
||||
issue_detected = 1;
|
||||
|
||||
} else {
|
||||
|
||||
@ -1397,12 +1383,12 @@ u32 get_map_size(void) {
|
||||
|
||||
/* Create a stream file */
|
||||
|
||||
FILE *create_ffile(u8 *fn, mode_t mode) {
|
||||
FILE *create_ffile(u8 *fn) {
|
||||
|
||||
s32 fd;
|
||||
FILE *f;
|
||||
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, mode);
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
|
||||
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
|
||||
|
||||
@ -1416,11 +1402,11 @@ FILE *create_ffile(u8 *fn, mode_t mode) {
|
||||
|
||||
/* Create a file */
|
||||
|
||||
s32 create_file(u8 *fn, mode_t mode) {
|
||||
s32 create_file(u8 *fn) {
|
||||
|
||||
s32 fd;
|
||||
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, mode);
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
|
||||
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
|
||||
|
||||
|
@ -51,7 +51,6 @@
|
||||
#include <sys/resource.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/stat.h>
|
||||
#include <grp.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <dlfcn.h>
|
||||
@ -141,7 +140,7 @@ nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) {
|
||||
if (plugin->nyx_get_target_hash64 == NULL) { goto fail; }
|
||||
|
||||
plugin->nyx_config_free = dlsym(handle, "nyx_config_free");
|
||||
if (plugin->nyx_config_free == NULL) { goto fail; }
|
||||
if (plugin->nyx_get_target_hash64 == NULL) { goto fail; }
|
||||
|
||||
OKF("libnyx plugin is ready!");
|
||||
return plugin;
|
||||
@ -209,53 +208,9 @@ static void fsrv_exec_child(afl_forkserver_t *fsrv, char **argv) {
|
||||
|
||||
}
|
||||
|
||||
if (fsrv->gid_set) {
|
||||
|
||||
if (setregid(fsrv->gid, fsrv->gid) == -1) {
|
||||
|
||||
FATAL("setgid failed: %s\n", strerror(errno));
|
||||
|
||||
}
|
||||
|
||||
if (setgroups(fsrv->nb_supl_gids, fsrv->supl_gids) == -1) {
|
||||
|
||||
FATAL("setgroups failed: %s\n", strerror(errno));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (fsrv->uid_set) {
|
||||
|
||||
if (setreuid(fsrv->uid, fsrv->uid) == -1) {
|
||||
|
||||
FATAL("setuid failed: %s\n", strerror(errno));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (fsrv->chown_needed && fsrv->out_file != NULL) {
|
||||
|
||||
if (access(fsrv->out_file, R_OK) == -1) {
|
||||
|
||||
if (errno == EACCES) {
|
||||
|
||||
FATAL(
|
||||
"Access to the file to fuzz denied. Most likely the requested\n"
|
||||
" UID and/or GID is denied search permission ('x') for one of "
|
||||
"the directories\n in the path prefix of \"%s\".",
|
||||
fsrv->out_file);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
execv(fsrv->target_path, argv);
|
||||
|
||||
WARNF("Execv failed in forkserver: %s.", strerror(errno));
|
||||
WARNF("Execv failed in forkserver.");
|
||||
|
||||
}
|
||||
|
||||
@ -295,16 +250,6 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
|
||||
fsrv->child_kill_signal = SIGKILL;
|
||||
fsrv->max_length = MAX_FILE;
|
||||
|
||||
if (getenv("AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT") != NULL) {
|
||||
|
||||
fsrv->setenv = 1;
|
||||
|
||||
} else {
|
||||
|
||||
fsrv->setenv = 0;
|
||||
|
||||
}
|
||||
|
||||
/* exec related stuff */
|
||||
fsrv->child_pid = -1;
|
||||
fsrv->map_size = get_map_size();
|
||||
@ -319,9 +264,6 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
|
||||
fsrv->persistent_trace_bits = NULL;
|
||||
#endif
|
||||
|
||||
fsrv->uid_set = 0;
|
||||
fsrv->gid_set = 0;
|
||||
|
||||
fsrv->init_child_func = fsrv_exec_child;
|
||||
list_append(&fsrv_list, fsrv);
|
||||
|
||||
@ -368,38 +310,6 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
|
||||
|
||||
}
|
||||
|
||||
void afl_fsrv_setup_preload(afl_forkserver_t *fsrv, char *argv0) {
|
||||
|
||||
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
|
||||
if (fsrv->qemu_mode) return;
|
||||
|
||||
u8 *afl_preload = getenv("AFL_PRELOAD");
|
||||
u8 *preload_path = NULL;
|
||||
u8 *frida_binary = NULL;
|
||||
if (fsrv->frida_mode)
|
||||
frida_binary = find_afl_binary(argv0, "afl-frida-trace.so");
|
||||
|
||||
if (afl_preload && frida_binary)
|
||||
preload_path = alloc_printf("%s:%s", afl_preload, frida_binary);
|
||||
else if (afl_preload)
|
||||
preload_path = ck_strdup(afl_preload);
|
||||
else if (frida_binary)
|
||||
preload_path = ck_strdup(frida_binary);
|
||||
|
||||
ck_free(frida_binary);
|
||||
|
||||
if (preload_path) {
|
||||
|
||||
setenv("LD_PRELOAD", preload_path, 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", preload_path, 1);
|
||||
#endif
|
||||
ck_free(preload_path);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Wrapper for select() and read(), reading a 32 bit var.
|
||||
Returns the time passed to read.
|
||||
If the wait times out, returns timeout_ms + 1;
|
||||
@ -541,26 +451,6 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) {
|
||||
close(FORKSRV_FD);
|
||||
close(FORKSRV_FD + 1);
|
||||
|
||||
if (fsrv->gid_set) {
|
||||
|
||||
if (setgid(fsrv->gid) == -1) {
|
||||
|
||||
FATAL("setgid failed: %s\n", strerror(errno));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (fsrv->uid_set) {
|
||||
|
||||
if (setuid(fsrv->uid) == -1) {
|
||||
|
||||
FATAL("setuid failed: %s\n", strerror(errno));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// finally: exec...
|
||||
execv(fsrv->target_path, argv);
|
||||
|
||||
@ -988,8 +878,6 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
|
||||
/* CHILD PROCESS */
|
||||
|
||||
if (unlikely(fsrv->setenv)) { setenv("AFL_FORKSERVER_PARENT", "1", 0); }
|
||||
|
||||
// enable terminating on sigpipe in the children
|
||||
struct sigaction sa;
|
||||
memset((char *)&sa, 0, sizeof(sa));
|
||||
@ -1907,18 +1795,14 @@ void __attribute__((hot)) afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv,
|
||||
|
||||
if (unlikely(fsrv->no_unlink)) {
|
||||
|
||||
fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_TRUNC, fsrv->perm);
|
||||
fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
DEFAULT_PERMISSION);
|
||||
|
||||
} else {
|
||||
|
||||
unlink(fsrv->out_file); /* Ignore errors. */
|
||||
fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_EXCL, fsrv->perm);
|
||||
|
||||
}
|
||||
|
||||
if (fsrv->chown_needed) {
|
||||
|
||||
if (fchown(fd, -1, fsrv->gid) == -1) { PFATAL("fchown() failed"); }
|
||||
fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_EXCL,
|
||||
DEFAULT_PERMISSION);
|
||||
|
||||
}
|
||||
|
||||
|
@ -84,16 +84,10 @@ void write_bitmap(afl_state_t *afl) {
|
||||
afl->bitmap_changed = 0;
|
||||
|
||||
snprintf(fname, PATH_MAX, "%s/fuzz_bitmap", afl->out_dir);
|
||||
fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, afl->perm);
|
||||
fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
|
||||
|
||||
if (fd < 0) { PFATAL("Unable to open '%s'", fname); }
|
||||
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
|
||||
|
||||
}
|
||||
|
||||
ck_write(fd, afl->virgin_bits, afl->fsrv.map_size, fname);
|
||||
|
||||
close(fd);
|
||||
@ -261,8 +255,7 @@ inline u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) {
|
||||
* on rare cases it fall backs to the slow path: classify_counts() first, then
|
||||
* return has_new_bits(). */
|
||||
|
||||
static inline u8 has_new_bits_unclassified(afl_state_t *afl, u8 *virgin_map,
|
||||
bool *classified) {
|
||||
inline u8 has_new_bits_unclassified(afl_state_t *afl, u8 *virgin_map) {
|
||||
|
||||
/* Handle the hot path first: no new coverage */
|
||||
u8 *end = afl->fsrv.trace_bits + afl->fsrv.map_size;
|
||||
@ -279,7 +272,6 @@ static inline u8 has_new_bits_unclassified(afl_state_t *afl, u8 *virgin_map,
|
||||
|
||||
#endif /* ^WORD_SIZE_64 */
|
||||
classify_counts(&afl->fsrv);
|
||||
*classified = true;
|
||||
return has_new_bits(afl, virgin_map);
|
||||
|
||||
}
|
||||
@ -325,15 +317,7 @@ u8 *describe_op(afl_state_t *afl, u8 new_bits, size_t max_description_len) {
|
||||
|
||||
if (unlikely(afl->syncing_party)) {
|
||||
|
||||
if (unlikely(afl->foreign_file)) {
|
||||
|
||||
sprintf(ret, "sync:%s,src:%.20s", afl->syncing_party, afl->foreign_file);
|
||||
|
||||
} else {
|
||||
|
||||
sprintf(ret, "sync:%s,src:%06u", afl->syncing_party, afl->syncing_case);
|
||||
|
||||
}
|
||||
sprintf(ret, "sync:%s,src:%06u", afl->syncing_party, afl->syncing_case);
|
||||
|
||||
} else {
|
||||
|
||||
@ -435,18 +419,12 @@ void write_crash_readme(afl_state_t *afl) {
|
||||
|
||||
sprintf(fn, "%s/crashes/README.txt", afl->out_dir);
|
||||
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, afl->perm);
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
|
||||
/* Do not die on errors here - that would be impolite. */
|
||||
|
||||
if (unlikely(fd < 0)) { return; }
|
||||
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
|
||||
|
||||
}
|
||||
|
||||
f = fdopen(fd, "w");
|
||||
|
||||
if (unlikely(!f)) {
|
||||
@ -484,46 +462,6 @@ void write_crash_readme(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
static inline void classify_if_necessary(afl_state_t *afl, bool *classified) {
|
||||
|
||||
if (*classified) return;
|
||||
classify_counts(&afl->fsrv);
|
||||
*classified = true;
|
||||
|
||||
}
|
||||
|
||||
static inline void calculate_cksum_if_necessary(afl_state_t *afl, u64 *cksum,
|
||||
bool *cksumed,
|
||||
bool *classified) {
|
||||
|
||||
if (*cksumed) return;
|
||||
classify_if_necessary(afl, classified);
|
||||
*cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
|
||||
*cksumed = true;
|
||||
|
||||
}
|
||||
|
||||
static inline void calculate_new_bits_if_necessary(afl_state_t *afl,
|
||||
u8 *new_bits,
|
||||
bool *bits_counted,
|
||||
bool *classified) {
|
||||
|
||||
if (*bits_counted) return;
|
||||
|
||||
if (*classified) {
|
||||
|
||||
*new_bits = has_new_bits(afl, afl->virgin_bits);
|
||||
|
||||
} else {
|
||||
|
||||
*new_bits = has_new_bits_unclassified(afl, afl->virgin_bits, classified);
|
||||
|
||||
}
|
||||
|
||||
*bits_counted = true;
|
||||
|
||||
}
|
||||
|
||||
/* Check if the result of an execve() during routine fuzzing is interesting,
|
||||
save or queue the input test case for further analysis if so. Returns 1 if
|
||||
entry is saved, 0 otherwise. */
|
||||
@ -531,6 +469,8 @@ static inline void calculate_new_bits_if_necessary(afl_state_t *afl,
|
||||
u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
u32 len, u8 fault) {
|
||||
|
||||
u8 classified = 0;
|
||||
|
||||
if (unlikely(len == 0)) { return 0; }
|
||||
|
||||
if (unlikely(fault == FSRV_RUN_TMOUT && afl->afl_env.afl_ignore_timeouts)) {
|
||||
@ -539,6 +479,7 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
|
||||
classify_counts(&afl->fsrv);
|
||||
u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
|
||||
classified = 1;
|
||||
|
||||
// Saturated increment
|
||||
if (likely(afl->n_fuzz[cksum % N_FUZZ_SIZE] < 0xFFFFFFFF))
|
||||
@ -552,14 +493,13 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
|
||||
u8 fn[PATH_MAX];
|
||||
u8 *queue_fn = "";
|
||||
u8 keeping = 0, res, is_timeout = 0;
|
||||
u8 san_fault = 0, san_idx = 0, feed_san = 0;
|
||||
u8 new_bits = 0, keeping = 0, res, is_timeout = 0, need_hash = 1;
|
||||
s32 fd;
|
||||
u64 cksum = 0;
|
||||
u32 cksum_simplified = 0, cksum_unique = 0;
|
||||
|
||||
bool classified = false, bits_counted = false, cksumed = false;
|
||||
u8 new_bits = 0; /* valid if bits_counted is true */
|
||||
u64 cksum = 0; /* valid if cksumed is true */
|
||||
u8 san_fault = 0;
|
||||
u8 san_idx = 0;
|
||||
u8 feed_san = 0;
|
||||
|
||||
afl->san_case_status = 0;
|
||||
|
||||
@ -569,7 +509,10 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
only be used for special schedules */
|
||||
if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
|
||||
|
||||
calculate_cksum_if_necessary(afl, &cksum, &cksumed, &classified);
|
||||
classify_counts(&afl->fsrv);
|
||||
need_hash = 0;
|
||||
|
||||
cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
|
||||
|
||||
/* Saturated increment */
|
||||
if (likely(afl->n_fuzz[cksum % N_FUZZ_SIZE] < 0xFFFFFFFF))
|
||||
@ -604,8 +547,7 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
unlikely(afl->san_abstraction == COVERAGE_INCREASE)) {
|
||||
|
||||
/* Check if the input increase the coverage */
|
||||
calculate_new_bits_if_necessary(afl, &new_bits, &bits_counted,
|
||||
&classified);
|
||||
new_bits = has_new_bits_unclassified(afl, afl->virgin_bits);
|
||||
|
||||
if (unlikely(new_bits)) { feed_san = 1; }
|
||||
|
||||
@ -614,9 +556,15 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
if (unlikely(afl->san_binary_length) &&
|
||||
likely(afl->san_abstraction == UNIQUE_TRACE)) {
|
||||
|
||||
// If schedule is not FAST..RARE, we need to classify counts here
|
||||
// Note: SAND was evaluated under FAST schedule but should also work
|
||||
// with other scedules.
|
||||
classify_if_necessary(afl, &classified);
|
||||
if (!classified) {
|
||||
|
||||
classify_counts(&afl->fsrv);
|
||||
classified = 1;
|
||||
|
||||
}
|
||||
|
||||
cksum_unique =
|
||||
hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
|
||||
@ -676,7 +624,22 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
|
||||
/* Keep only if there are new bits in the map, add to queue for
|
||||
future fuzzing, etc. */
|
||||
calculate_new_bits_if_necessary(afl, &new_bits, &bits_counted, &classified);
|
||||
if (!unlikely(afl->san_abstraction == COVERAGE_INCREASE && feed_san)) {
|
||||
|
||||
/* If we are in coverage increasing abstraction and have fed input to
|
||||
sanitizers, we are sure it has new bits.*/
|
||||
if (classified) {
|
||||
|
||||
/* We could have classified the bits in SAND with UNIQUE_TRACE */
|
||||
new_bits = has_new_bits(afl, afl->virgin_bits);
|
||||
|
||||
} else {
|
||||
|
||||
new_bits = has_new_bits_unclassified(afl, afl->virgin_bits);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (likely(!new_bits)) {
|
||||
|
||||
@ -699,11 +662,6 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
|
||||
save_to_queue:
|
||||
|
||||
/* these calculations are necessary because some code flow may jump here via
|
||||
goto */
|
||||
calculate_cksum_if_necessary(afl, &cksum, &cksumed, &classified);
|
||||
calculate_new_bits_if_necessary(afl, &new_bits, &bits_counted, &classified);
|
||||
|
||||
#ifndef SIMPLE_FILES
|
||||
|
||||
if (!afl->afl_env.afl_sha1_filenames) {
|
||||
@ -785,8 +743,6 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
|
||||
#endif
|
||||
|
||||
afl->queue_top->exec_cksum = cksum;
|
||||
|
||||
if (new_bits == 2) {
|
||||
|
||||
afl->queue_top->has_new_cov = 1;
|
||||
@ -794,8 +750,17 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
|
||||
}
|
||||
|
||||
if (unlikely(need_hash && new_bits)) {
|
||||
|
||||
/* due to classify counts we have to recalculate the checksum */
|
||||
afl->queue_top->exec_cksum =
|
||||
hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
|
||||
need_hash = 0;
|
||||
|
||||
}
|
||||
|
||||
/* For AFLFast schedules we update the new queue entry */
|
||||
if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
|
||||
if (likely(cksum)) {
|
||||
|
||||
afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE;
|
||||
afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1;
|
||||
@ -894,9 +859,7 @@ may_save_fault:
|
||||
}
|
||||
|
||||
new_fault = fuzz_run_target(afl, &afl->fsrv, afl->hang_tmout);
|
||||
classified = false;
|
||||
bits_counted = false;
|
||||
cksumed = false;
|
||||
classify_counts(&afl->fsrv);
|
||||
|
||||
/* A corner case that one user reported bumping into: increasing the
|
||||
timeout actually uncovers a crash. Make sure we don't discard it if
|
||||
@ -1088,15 +1051,9 @@ may_save_fault:
|
||||
u8 fn_log[PATH_MAX];
|
||||
|
||||
(void)(snprintf(fn_log, PATH_MAX, "%s.log", fn) + 1);
|
||||
fd = open(fn_log, O_WRONLY | O_CREAT | O_EXCL, afl->perm);
|
||||
fd = open(fn_log, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", fn_log); }
|
||||
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
|
||||
|
||||
}
|
||||
|
||||
u32 nyx_aux_string_len = afl->fsrv.nyx_handlers->nyx_get_aux_string(
|
||||
afl->fsrv.nyx_runner, afl->fsrv.nyx_aux_string,
|
||||
afl->fsrv.nyx_aux_string_len);
|
||||
|
@ -748,16 +748,10 @@ void save_auto(afl_state_t *afl) {
|
||||
|
||||
s32 fd;
|
||||
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, afl->perm);
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
|
||||
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
|
||||
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
|
||||
|
||||
}
|
||||
|
||||
ck_write(fd, afl->a_extras[i].data, afl->a_extras[i].len, fn);
|
||||
|
||||
close(fd);
|
||||
|
@ -589,6 +589,8 @@ void read_foreign_testcases(afl_state_t *afl, int first) {
|
||||
u8 *fn2 =
|
||||
alloc_printf("%s/%s", afl->foreign_syncs[iter].dir, nl[i]->d_name);
|
||||
|
||||
free(nl[i]); /* not tracked */
|
||||
|
||||
if (unlikely(lstat(fn2, &st) || access(fn2, R_OK))) {
|
||||
|
||||
if (first) PFATAL("Unable to access '%s'", fn2);
|
||||
@ -651,14 +653,17 @@ void read_foreign_testcases(afl_state_t *afl, int first) {
|
||||
u32 len = write_to_testcase(afl, (void **)&mem, st.st_size, 1);
|
||||
fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
|
||||
afl->syncing_party = foreign_name;
|
||||
afl->foreign_file = nl[i]->d_name;
|
||||
afl->queued_imported += save_if_interesting(afl, mem, len, fault);
|
||||
|
||||
afl->syncing_party = 0;
|
||||
munmap(mem, st.st_size);
|
||||
close(fd);
|
||||
|
||||
if (st.st_mtime > mtime_max) { mtime_max = st.st_mtime; }
|
||||
show_stats(afl);
|
||||
if (st.st_mtime > mtime_max) {
|
||||
|
||||
mtime_max = st.st_mtime;
|
||||
show_stats(afl);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -668,21 +673,12 @@ void read_foreign_testcases(afl_state_t *afl, int first) {
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < (u32)nl_cnt; ++i) {
|
||||
|
||||
free(nl[i]); /* not tracked */
|
||||
|
||||
}
|
||||
|
||||
free(nl); /* not tracked */
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
afl->foreign_file = NULL;
|
||||
afl->syncing_party = 0;
|
||||
|
||||
if (first) {
|
||||
|
||||
afl->last_find_time = 0;
|
||||
@ -760,10 +756,21 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
|
||||
if (nl_cnt) {
|
||||
|
||||
u32 done = 0;
|
||||
i = 0;
|
||||
|
||||
if (unlikely(afl->in_place_resume)) {
|
||||
|
||||
i = nl_cnt;
|
||||
|
||||
} else {
|
||||
|
||||
i = 0;
|
||||
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
if (unlikely(afl->in_place_resume)) { --i; }
|
||||
|
||||
struct stat st;
|
||||
u8 dfn[PATH_MAX];
|
||||
snprintf(dfn, PATH_MAX, "%s/.state/deterministic_done/%s", afl->in_dir,
|
||||
@ -843,12 +850,22 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
|
||||
}
|
||||
|
||||
next_entry:
|
||||
if (unlikely(++i >= (u32)nl_cnt)) { done = 1; }
|
||||
if (unlikely(afl->in_place_resume)) {
|
||||
|
||||
if (unlikely(i == 0)) { done = 1; }
|
||||
|
||||
} else {
|
||||
|
||||
if (unlikely(++i >= (u32)nl_cnt)) { done = 1; }
|
||||
|
||||
}
|
||||
|
||||
} while (!done);
|
||||
|
||||
}
|
||||
|
||||
// if (getenv("MYTEST")) afl->in_place_resume = 0;
|
||||
|
||||
free(nl); /* not tracked */
|
||||
|
||||
if (!afl->queued_items && directory == NULL) {
|
||||
@ -892,21 +909,9 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
|
||||
struct queue_entry *q;
|
||||
u32 cal_failures = 0, idx;
|
||||
u8 *use_mem, done = 0;
|
||||
u8 *use_mem;
|
||||
|
||||
if (afl->in_place_resume) {
|
||||
|
||||
idx = afl->queued_items;
|
||||
|
||||
} else {
|
||||
|
||||
idx = 0;
|
||||
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
if (afl->in_place_resume) { --idx; }
|
||||
for (idx = 0; idx < afl->queued_items; idx++) {
|
||||
|
||||
q = afl->queue_buf[idx];
|
||||
if (unlikely(!q || q->disabled)) { continue; }
|
||||
@ -1268,20 +1273,9 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
|
||||
++afl->saved_crashes;
|
||||
|
||||
fd = open(crash_fn, O_WRONLY | O_CREAT | O_EXCL, afl->perm);
|
||||
fd = open(crash_fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", crash_fn); }
|
||||
ck_write(fd, use_mem, read_len, crash_fn);
|
||||
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (fchown(fd, -1, afl->fsrv.gid) == -1) {
|
||||
|
||||
PFATAL("fchown() failed");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
#ifdef __linux__
|
||||
@ -1290,7 +1284,8 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
u8 crash_log_fn[PATH_MAX];
|
||||
|
||||
snprintf(crash_log_fn, PATH_MAX, "%s.log", crash_fn);
|
||||
fd = open(crash_log_fn, O_WRONLY | O_CREAT | O_EXCL, afl->perm);
|
||||
fd = open(crash_log_fn, O_WRONLY | O_CREAT | O_EXCL,
|
||||
DEFAULT_PERMISSION);
|
||||
if (unlikely(fd < 0)) {
|
||||
|
||||
PFATAL("Unable to create '%s'", crash_log_fn);
|
||||
@ -1303,17 +1298,6 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
|
||||
ck_write(fd, afl->fsrv.nyx_aux_string, nyx_aux_string_len,
|
||||
crash_log_fn);
|
||||
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (fchown(fd, -1, afl->fsrv.gid) == -1) {
|
||||
|
||||
PFATAL("fchown() failed");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
}
|
||||
@ -1394,17 +1378,7 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
if (!afl->in_place_resume) {
|
||||
|
||||
if (++idx >= afl->queued_items) { done = 1; }
|
||||
|
||||
} else {
|
||||
|
||||
if (idx == 0) { done = 1; }
|
||||
|
||||
}
|
||||
|
||||
} while (!done);
|
||||
}
|
||||
|
||||
if (cal_failures) {
|
||||
|
||||
@ -1433,51 +1407,67 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
|
||||
q = afl->queue_buf[idx];
|
||||
if (!q || q->disabled || q->cal_failed || !q->exec_cksum) { continue; }
|
||||
u32 done = 0;
|
||||
|
||||
for (i = idx + 1; likely(i < afl->queued_items && afl->queue_buf[i]); ++i) {
|
||||
for (i = idx + 1;
|
||||
likely(i < afl->queued_items && afl->queue_buf[i] && !done); ++i) {
|
||||
|
||||
struct queue_entry *p = afl->queue_buf[i];
|
||||
if (p->disabled || p->cal_failed || !p->exec_cksum) { continue; }
|
||||
if (p->exec_cksum != q->exec_cksum) continue;
|
||||
|
||||
duplicates = 1;
|
||||
if (p->exec_cksum == q->exec_cksum) {
|
||||
|
||||
// we keep the shorter file
|
||||
struct queue_entry *to_disable, *to_keep;
|
||||
if (p->len >= q->len) {
|
||||
duplicates = 1;
|
||||
|
||||
to_disable = p;
|
||||
to_keep = q;
|
||||
// we keep the shorter file
|
||||
if (p->len >= q->len) {
|
||||
|
||||
} else {
|
||||
if (!p->was_fuzzed) {
|
||||
|
||||
to_disable = q;
|
||||
to_keep = p;
|
||||
p->was_fuzzed = 1;
|
||||
afl->reinit_table = 1;
|
||||
--afl->pending_not_fuzzed;
|
||||
--afl->active_items;
|
||||
|
||||
}
|
||||
|
||||
p->disabled = 1;
|
||||
p->perf_score = 0;
|
||||
|
||||
if (afl->debug) {
|
||||
|
||||
WARNF("Same coverage - %s is kept active, %s is disabled.",
|
||||
q->fname, p->fname);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (!q->was_fuzzed) {
|
||||
|
||||
q->was_fuzzed = 1;
|
||||
afl->reinit_table = 1;
|
||||
--afl->pending_not_fuzzed;
|
||||
--afl->active_items;
|
||||
|
||||
}
|
||||
|
||||
q->disabled = 1;
|
||||
q->perf_score = 0;
|
||||
|
||||
if (afl->debug) {
|
||||
|
||||
WARNF("Same coverage - %s is kept active, %s is disabled.",
|
||||
p->fname, q->fname);
|
||||
|
||||
}
|
||||
|
||||
done = 1; // end inner loop because outer loop entry is disabled now
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!to_disable->was_fuzzed) {
|
||||
|
||||
to_disable->was_fuzzed = 1;
|
||||
afl->reinit_table = 1;
|
||||
--afl->pending_not_fuzzed;
|
||||
--afl->active_items;
|
||||
|
||||
}
|
||||
|
||||
to_disable->disabled = 1;
|
||||
to_disable->perf_score = 0;
|
||||
|
||||
if (afl->debug) {
|
||||
|
||||
WARNF("Same coverage - %s is kept active, %s is disabled.",
|
||||
to_keep->fname, to_disable->fname);
|
||||
|
||||
}
|
||||
|
||||
// end inner loop because outer loop entry is disabled now
|
||||
if (to_disable == q) break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -1504,7 +1494,7 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
|
||||
/* Helper function: link() if possible, copy otherwise. */
|
||||
|
||||
static void link_or_copy(u8 *old_path, u8 *new_path, mode_t perm) {
|
||||
static void link_or_copy(u8 *old_path, u8 *new_path) {
|
||||
|
||||
s32 i = link(old_path, new_path);
|
||||
if (!i) { return; }
|
||||
@ -1515,7 +1505,7 @@ static void link_or_copy(u8 *old_path, u8 *new_path, mode_t perm) {
|
||||
sfd = open(old_path, O_RDONLY);
|
||||
if (sfd < 0) { PFATAL("Unable to open '%s'", old_path); }
|
||||
|
||||
dfd = open(new_path, O_WRONLY | O_CREAT | O_EXCL, perm);
|
||||
dfd = open(new_path, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
if (dfd < 0) { PFATAL("Unable to create '%s'", new_path); }
|
||||
|
||||
tmp = ck_alloc(64 * 1024);
|
||||
@ -1567,9 +1557,8 @@ void pivot_inputs(afl_state_t *afl) {
|
||||
ID matches the one we'd assign, just use the original file name.
|
||||
This is valuable for resuming fuzzing runs. */
|
||||
|
||||
if (afl->in_place_resume ||
|
||||
(!strncmp(rsl, CASE_PREFIX, 3) &&
|
||||
sscanf(rsl + 3, "%06u", &orig_id) == 1 && orig_id == id)) {
|
||||
if (!strncmp(rsl, CASE_PREFIX, 3) &&
|
||||
sscanf(rsl + 3, "%06u", &orig_id) == 1 && orig_id == id) {
|
||||
|
||||
u8 *src_str;
|
||||
u32 src_id;
|
||||
@ -1651,16 +1640,10 @@ void pivot_inputs(afl_state_t *afl) {
|
||||
|
||||
/* Pivot to the new queue entry. */
|
||||
|
||||
link_or_copy(q->fname, nfn, afl->perm);
|
||||
link_or_copy(q->fname, nfn);
|
||||
ck_free(q->fname);
|
||||
q->fname = nfn;
|
||||
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (chown(nfn, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
|
||||
|
||||
}
|
||||
|
||||
/* Make sure that the passed_det value carries over, too. */
|
||||
|
||||
if (q->passed_det) { mark_as_det_done(afl, q); }
|
||||
@ -2267,13 +2250,13 @@ void setup_dirs_fds(afl_state_t *afl) {
|
||||
|
||||
ACTF("Setting up output directories...");
|
||||
|
||||
if (afl->sync_id && mkdir(afl->sync_dir, afl->dir_perm) && errno != EEXIST) {
|
||||
if (afl->sync_id && mkdir(afl->sync_dir, 0700) && errno != EEXIST) {
|
||||
|
||||
PFATAL("Unable to create '%s'", afl->sync_dir);
|
||||
|
||||
}
|
||||
|
||||
if (mkdir(afl->out_dir, afl->dir_perm)) {
|
||||
if (mkdir(afl->out_dir, 0700)) {
|
||||
|
||||
if (errno != EEXIST) { PFATAL("Unable to create '%s'", afl->out_dir); }
|
||||
|
||||
@ -2281,16 +2264,6 @@ void setup_dirs_fds(afl_state_t *afl) {
|
||||
|
||||
} else {
|
||||
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (chown(afl->out_dir, -1, afl->fsrv.gid) == -1) {
|
||||
|
||||
PFATAL("fchown() failed");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (afl->in_place_resume) {
|
||||
|
||||
FATAL("Resume attempted but old output directory not found");
|
||||
@ -2325,27 +2298,27 @@ void setup_dirs_fds(afl_state_t *afl) {
|
||||
/* Queue directory for any starting & discovered paths. */
|
||||
|
||||
tmp = alloc_printf("%s/queue", afl->out_dir);
|
||||
if (mkdir(tmp, afl->dir_perm)) { PFATAL("Unable to create '%s'", tmp); }
|
||||
if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
|
||||
ck_free(tmp);
|
||||
|
||||
/* Top-level directory for queue metadata used for session
|
||||
resume and related tasks. */
|
||||
|
||||
tmp = alloc_printf("%s/queue/.state/", afl->out_dir);
|
||||
if (mkdir(tmp, afl->dir_perm)) { PFATAL("Unable to create '%s'", tmp); }
|
||||
if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
|
||||
ck_free(tmp);
|
||||
|
||||
/* Directory for flagging queue entries that went through
|
||||
deterministic fuzzing in the past. */
|
||||
|
||||
tmp = alloc_printf("%s/queue/.state/deterministic_done/", afl->out_dir);
|
||||
if (mkdir(tmp, afl->dir_perm)) { PFATAL("Unable to create '%s'", tmp); }
|
||||
if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
|
||||
ck_free(tmp);
|
||||
|
||||
/* Directory with the auto-selected dictionary entries. */
|
||||
|
||||
tmp = alloc_printf("%s/queue/.state/auto_extras/", afl->out_dir);
|
||||
if (mkdir(tmp, afl->dir_perm)) { PFATAL("Unable to create '%s'", tmp); }
|
||||
if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
|
||||
ck_free(tmp);
|
||||
|
||||
/* Sync directory for keeping track of cooperating fuzzers. */
|
||||
@ -2354,8 +2327,7 @@ void setup_dirs_fds(afl_state_t *afl) {
|
||||
|
||||
tmp = alloc_printf("%s/.synced/", afl->out_dir);
|
||||
|
||||
if (mkdir(tmp, afl->dir_perm) &&
|
||||
(!afl->in_place_resume || errno != EEXIST)) {
|
||||
if (mkdir(tmp, 0700) && (!afl->in_place_resume || errno != EEXIST)) {
|
||||
|
||||
PFATAL("Unable to create '%s'", tmp);
|
||||
|
||||
@ -2368,13 +2340,13 @@ void setup_dirs_fds(afl_state_t *afl) {
|
||||
/* All recorded crashes. */
|
||||
|
||||
tmp = alloc_printf("%s/crashes", afl->out_dir);
|
||||
if (mkdir(tmp, afl->dir_perm)) { PFATAL("Unable to create '%s'", tmp); }
|
||||
if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
|
||||
ck_free(tmp);
|
||||
|
||||
/* All recorded hangs. */
|
||||
|
||||
tmp = alloc_printf("%s/hangs", afl->out_dir);
|
||||
if (mkdir(tmp, afl->dir_perm)) { PFATAL("Unable to create '%s'", tmp); }
|
||||
if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
|
||||
ck_free(tmp);
|
||||
|
||||
/* Generally useful file descriptors. */
|
||||
@ -2391,14 +2363,8 @@ void setup_dirs_fds(afl_state_t *afl) {
|
||||
|
||||
if (!afl->in_place_resume) {
|
||||
|
||||
int fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, afl->perm);
|
||||
int fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", tmp); }
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
|
||||
|
||||
}
|
||||
|
||||
ck_free(tmp);
|
||||
|
||||
afl->fsrv.plot_file = fdopen(fd, "w");
|
||||
@ -2424,14 +2390,8 @@ void setup_dirs_fds(afl_state_t *afl) {
|
||||
|
||||
} else {
|
||||
|
||||
int fd = open(tmp, O_WRONLY | O_CREAT, afl->perm);
|
||||
int fd = open(tmp, O_WRONLY | O_CREAT, DEFAULT_PERMISSION);
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", tmp); }
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
|
||||
|
||||
}
|
||||
|
||||
ck_free(tmp);
|
||||
|
||||
afl->fsrv.plot_file = fdopen(fd, "w");
|
||||
@ -2447,14 +2407,8 @@ void setup_dirs_fds(afl_state_t *afl) {
|
||||
|
||||
tmp = alloc_printf("%s/plot_det_data", afl->out_dir);
|
||||
|
||||
int fd = open(tmp, O_WRONLY | O_CREAT, afl->perm);
|
||||
int fd = open(tmp, O_WRONLY | O_CREAT, DEFAULT_PERMISSION);
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", tmp); }
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
|
||||
|
||||
}
|
||||
|
||||
ck_free(tmp);
|
||||
|
||||
afl->fsrv.det_plot_file = fdopen(fd, "w");
|
||||
@ -2478,14 +2432,8 @@ void setup_cmdline_file(afl_state_t *afl, char **argv) {
|
||||
|
||||
/* Store the command line to reproduce our findings */
|
||||
tmp = alloc_printf("%s/cmdline", afl->out_dir);
|
||||
fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, afl->perm);
|
||||
fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", tmp); }
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
|
||||
|
||||
}
|
||||
|
||||
ck_free(tmp);
|
||||
|
||||
cmdline_file = fdopen(fd, "w");
|
||||
@ -2520,7 +2468,7 @@ void setup_stdio_file(afl_state_t *afl) {
|
||||
unlink(afl->fsrv.out_file); /* Ignore errors */
|
||||
|
||||
afl->fsrv.out_fd =
|
||||
open(afl->fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, afl->perm);
|
||||
open(afl->fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
|
||||
if (afl->fsrv.out_fd < 0) {
|
||||
|
||||
@ -2528,16 +2476,6 @@ void setup_stdio_file(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (fchown(afl->fsrv.out_fd, -1, afl->fsrv.gid) == -1) {
|
||||
|
||||
PFATAL("fchown() failed");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Make sure that core dumps don't go to a program. */
|
||||
@ -2863,9 +2801,9 @@ void fix_up_sync(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
if (strlen(afl->sync_id) > SYNC_ID_MAX_LEN) {
|
||||
if (strlen(afl->sync_id) > 50) {
|
||||
|
||||
FATAL("sync_id max length is %d characters", SYNC_ID_MAX_LEN);
|
||||
FATAL("sync_id max length is 50 characters");
|
||||
|
||||
}
|
||||
|
||||
@ -2973,17 +2911,11 @@ void setup_testcase_shmem(afl_state_t *afl) {
|
||||
afl->shm_fuzz = ck_alloc(sizeof(sharedmem_t));
|
||||
|
||||
// we need to set the non-instrumented mode to not overwrite the SHM_ENV_VAR
|
||||
size_t shm_fuzz_map_size = SHM_FUZZ_MAP_SIZE_DEFAULT;
|
||||
u8 *map = afl_shm_init(afl->shm_fuzz, shm_fuzz_map_size, 1, afl->perm,
|
||||
afl->chown_needed ? afl->fsrv.gid : -1);
|
||||
u8 *map = afl_shm_init(afl->shm_fuzz, MAX_FILE + sizeof(u32), 1);
|
||||
afl->shm_fuzz->shmemfuzz_mode = 1;
|
||||
|
||||
if (!map) { FATAL("BUG: Zero return from afl_shm_init."); }
|
||||
|
||||
u8 *shm_fuzz_map_size_str = alloc_printf("%zu", shm_fuzz_map_size);
|
||||
setenv(SHM_FUZZ_MAP_SIZE_ENV_VAR, shm_fuzz_map_size_str, 1);
|
||||
ck_free(shm_fuzz_map_size_str);
|
||||
|
||||
#ifdef USEMMAP
|
||||
setenv(SHM_FUZZ_ENV_VAR, afl->shm_fuzz->g_shm_file_path, 1);
|
||||
#else
|
||||
@ -3184,7 +3116,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
|
||||
!afl->fsrv.nyx_mode &&
|
||||
#endif
|
||||
!afl->fsrv.cs_mode && !afl->non_instrumented_mode &&
|
||||
!afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR))) {
|
||||
!afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
|
||||
|
||||
SAYF("\n" cLRD "[-] " cRST
|
||||
"Looks like the target binary is not instrumented! The fuzzer depends "
|
||||
@ -3215,7 +3147,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
|
||||
}
|
||||
|
||||
if ((afl->fsrv.cs_mode || afl->fsrv.qemu_mode || afl->fsrv.frida_mode) &&
|
||||
afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR))) {
|
||||
afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
|
||||
|
||||
SAYF("\n" cLRD "[-] " cRST
|
||||
"This program appears to be instrumented with AFL++ compilers, but is "
|
||||
@ -3250,7 +3182,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
|
||||
|
||||
/* Detect persistent & deferred init signatures in the binary. */
|
||||
|
||||
if (afl_memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG))) {
|
||||
if (afl_memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG) + 1)) {
|
||||
|
||||
OKF(cPIN "Persistent mode binary detected.");
|
||||
setenv(PERSIST_ENV_VAR, "1", 1);
|
||||
@ -3277,7 +3209,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
|
||||
}
|
||||
|
||||
if (afl->fsrv.frida_mode ||
|
||||
afl_memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG))) {
|
||||
afl_memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
|
||||
|
||||
OKF(cPIN "Deferred forkserver binary detected.");
|
||||
setenv(DEFER_ENV_VAR, "1", 1);
|
||||
|
@ -623,16 +623,10 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
|
||||
|
||||
unlink(q->fname); /* ignore errors */
|
||||
|
||||
fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, afl->perm);
|
||||
fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); }
|
||||
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
|
||||
|
||||
}
|
||||
|
||||
ck_write(fd, out_buf, out_len, q->fname);
|
||||
close(fd);
|
||||
|
||||
|
@ -411,12 +411,11 @@ u8 fuzz_one_original(afl_state_t *afl) {
|
||||
u_simplestring_time_diff(time_tmp, afl->prev_run_time + get_cur_time(),
|
||||
afl->start_time);
|
||||
ACTF(
|
||||
"Fuzzing test case #%u (%u total, %s%llu crashes saved%s, state: %s, "
|
||||
"Fuzzing test case #%u (%u total, %llu crashes saved, state: %s, "
|
||||
"mode=%s, "
|
||||
"perf_score=%0.0f, weight=%0.0f, favorite=%u, was_fuzzed=%u, "
|
||||
"exec_us=%llu, hits=%u, map=%u, ascii=%u, run_time=%s)...",
|
||||
afl->current_entry, afl->queued_items,
|
||||
afl->saved_crashes != 0 ? cRED : "", afl->saved_crashes, cRST,
|
||||
afl->current_entry, afl->queued_items, afl->saved_crashes,
|
||||
get_fuzzing_state(afl), afl->fuzz_mode ? "exploit" : "explore",
|
||||
afl->queue_cur->perf_score, afl->queue_cur->weight,
|
||||
afl->queue_cur->favored, afl->queue_cur->was_fuzzed,
|
||||
@ -6178,8 +6177,7 @@ u8 fuzz_one(afl_state_t *afl) {
|
||||
if (afl->do_document == 0) {
|
||||
|
||||
snprintf(path_buf, PATH_MAX, "%s/mutations", afl->out_dir);
|
||||
afl->do_document =
|
||||
mkdir(path_buf, afl->dir_perm); // if it exists we do not care
|
||||
afl->do_document = mkdir(path_buf, 0700); // if it exists we do not care
|
||||
afl->do_document = 1;
|
||||
|
||||
} else {
|
||||
|
@ -432,15 +432,8 @@ void mark_as_det_done(afl_state_t *afl, struct queue_entry *q) {
|
||||
snprintf(fn, PATH_MAX, "%s/queue/.state/deterministic_done/%s", afl->out_dir,
|
||||
strrchr((char *)q->fname, '/') + 1);
|
||||
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, afl->perm);
|
||||
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
|
||||
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
|
||||
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
q->passed_det = 1;
|
||||
|
@ -26,10 +26,8 @@
|
||||
|
||||
#include "afl-fuzz.h"
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <signal.h>
|
||||
#include <limits.h>
|
||||
#include <glob.h>
|
||||
#if !defined NAME_MAX
|
||||
#define NAME_MAX _XOPEN_NAME_MAX
|
||||
#endif
|
||||
@ -258,21 +256,11 @@ u32 __attribute__((hot)) write_to_testcase(afl_state_t *afl, void **mem,
|
||||
afl->document_counter++,
|
||||
describe_op(afl, 0, NAME_MAX - strlen("000000000:")));
|
||||
|
||||
if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, afl->perm)) >= 0) {
|
||||
if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION)) >=
|
||||
0) {
|
||||
|
||||
if (write(doc_fd, *mem, len) != len)
|
||||
PFATAL("write to mutation file failed: %s", fn);
|
||||
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (fchown(doc_fd, -1, afl->fsrv.gid) == -1) {
|
||||
|
||||
PFATAL("fchown() failed");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
close(doc_fd);
|
||||
|
||||
}
|
||||
@ -396,23 +384,19 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at,
|
||||
|
||||
if (unlikely(afl->no_unlink)) {
|
||||
|
||||
fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_TRUNC, afl->perm);
|
||||
fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
DEFAULT_PERMISSION);
|
||||
|
||||
} else {
|
||||
|
||||
unlink(afl->fsrv.out_file); /* Ignore errors. */
|
||||
fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_EXCL, afl->perm);
|
||||
fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_EXCL,
|
||||
DEFAULT_PERMISSION);
|
||||
|
||||
}
|
||||
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", afl->fsrv.out_file); }
|
||||
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
@ -509,41 +493,36 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
|
||||
afl->afl_env.afl_post_process_keep_original = 1;
|
||||
|
||||
/* we need a dummy run if this is LTO + cmplog */
|
||||
/*
|
||||
if (unlikely(afl->shm.cmplog_mode)) {
|
||||
if (unlikely(afl->shm.cmplog_mode)) {
|
||||
|
||||
(void)write_to_testcase(afl, (void **)&use_mem, q->len, 1);
|
||||
(void)write_to_testcase(afl, (void **)&use_mem, q->len, 1);
|
||||
|
||||
fault = fuzz_run_target(afl, &afl->fsrv, use_tmout);
|
||||
fault = fuzz_run_target(afl, &afl->fsrv, use_tmout);
|
||||
|
||||
// afl->stop_soon is set by the handler for Ctrl+C. When it's pressed,
|
||||
// we want to bail out quickly.
|
||||
/* afl->stop_soon is set by the handler for Ctrl+C. When it's pressed,
|
||||
we want to bail out quickly. */
|
||||
|
||||
if (afl->stop_soon || fault != afl->crash_mode) { goto abort_calibration;
|
||||
if (afl->stop_soon || fault != afl->crash_mode) { goto abort_calibration; }
|
||||
|
||||
}
|
||||
if (!afl->non_instrumented_mode && !afl->stage_cur &&
|
||||
!count_bytes(afl, afl->fsrv.trace_bits)) {
|
||||
|
||||
if (!afl->non_instrumented_mode &&
|
||||
!count_bytes(afl, afl->fsrv.trace_bits)) {
|
||||
|
||||
fault = FSRV_RUN_NOINST;
|
||||
goto abort_calibration;
|
||||
|
||||
}
|
||||
|
||||
#ifdef INTROSPECTION
|
||||
if (unlikely(!q->bitsmap_size)) { q->bitsmap_size = afl->bitsmap_size; }
|
||||
#endif
|
||||
fault = FSRV_RUN_NOINST;
|
||||
goto abort_calibration;
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
#ifdef INTROSPECTION
|
||||
if (unlikely(!q->bitsmap_size)) q->bitsmap_size = afl->bitsmap_size;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
if (q->exec_cksum) {
|
||||
|
||||
memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size);
|
||||
hnb = has_new_bits(afl, afl->virgin_bits);
|
||||
if (unlikely(hnb > new_bits)) { new_bits = hnb; }
|
||||
if (hnb > new_bits) { new_bits = hnb; }
|
||||
|
||||
}
|
||||
|
||||
@ -572,7 +551,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
|
||||
|
||||
if (afl->stop_soon || fault != afl->crash_mode) { goto abort_calibration; }
|
||||
|
||||
if (!afl->non_instrumented_mode &&
|
||||
if (!afl->non_instrumented_mode && !afl->stage_cur &&
|
||||
!count_bytes(afl, afl->fsrv.trace_bits)) {
|
||||
|
||||
fault = FSRV_RUN_NOINST;
|
||||
@ -581,19 +560,17 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
|
||||
}
|
||||
|
||||
#ifdef INTROSPECTION
|
||||
if (unlikely(!q->bitsmap_size)) { q->bitsmap_size = afl->bitsmap_size; }
|
||||
if (unlikely(!q->bitsmap_size)) q->bitsmap_size = afl->bitsmap_size;
|
||||
#endif
|
||||
|
||||
classify_counts(&afl->fsrv);
|
||||
cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
|
||||
|
||||
if (unlikely(q->exec_cksum != cksum)) {
|
||||
if (q->exec_cksum != cksum) {
|
||||
|
||||
hnb = has_new_bits(afl, afl->virgin_bits);
|
||||
if (hnb > new_bits) { new_bits = hnb; }
|
||||
|
||||
if (unlikely(hnb > new_bits)) { new_bits = hnb; }
|
||||
|
||||
if (likely(q->exec_cksum)) {
|
||||
if (q->exec_cksum) {
|
||||
|
||||
u32 i;
|
||||
|
||||
@ -720,110 +697,6 @@ abort_calibration:
|
||||
|
||||
}
|
||||
|
||||
/* Do not sync items that were synced from us */
|
||||
|
||||
static bool is_known_case(afl_state_t *afl, u8 *name) {
|
||||
|
||||
static char coming_from_me_str[SYNC_ID_MAX_LEN + 2];
|
||||
static u32 coming_from_me_len = 0;
|
||||
static u32 min_len = 15 + 4 + 6;
|
||||
|
||||
if (!coming_from_me_len) {
|
||||
|
||||
snprintf(coming_from_me_str, sizeof(coming_from_me_str), "%s,",
|
||||
afl->sync_id);
|
||||
min_len += coming_from_me_len = strlen(coming_from_me_str);
|
||||
|
||||
}
|
||||
|
||||
// file name length long enough so it can be ours
|
||||
if (unlikely(strlen(name) < min_len)) { return false; }
|
||||
// is it based on a sync? allow optimizer to make an integer comparison
|
||||
if (likely(memcmp(name + 10, "sync", 4) != 0)) { return false; }
|
||||
// we jump over the ':' after 'sync' and compare to our sync name
|
||||
if (unlikely(memcmp(name + 15, coming_from_me_str, coming_from_me_len) !=
|
||||
0)) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/* We do not need this as we now look on startup how many files are in sync
|
||||
targets.
|
||||
int src_id = atoi(name + 15 + coming_from_me_len + 4);
|
||||
if (unlikely(src_id >= afl->queued_items)) return false;
|
||||
*/
|
||||
|
||||
// yes it is highly likely a current testcase we already know
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/* Write into .sync/INSTANCE.max how many queue files were there on startup */
|
||||
|
||||
void check_sync_fuzzers(afl_state_t *afl) {
|
||||
|
||||
if (unlikely(afl->afl_env.afl_no_sync)) { return; }
|
||||
|
||||
DIR *sd, *dir;
|
||||
struct dirent *sd_ent, *entry;
|
||||
u8 qd_path[PATH_MAX], qd_synced_maxid[PATH_MAX];
|
||||
|
||||
sd = opendir(afl->sync_dir);
|
||||
if (!sd) { PFATAL("Unable to open '%s'", afl->sync_dir); }
|
||||
|
||||
u64 sync_start_us = get_cur_time_us();
|
||||
// Look at the entries created for every other fuzzer in the sync directory.
|
||||
|
||||
while ((sd_ent = readdir(sd))) {
|
||||
|
||||
if (sd_ent->d_name[0] == '.' || !strcmp(afl->sync_id, sd_ent->d_name)) {
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
sprintf(qd_path, "%s/%s/queue", afl->sync_dir, sd_ent->d_name);
|
||||
|
||||
dir = opendir(qd_path);
|
||||
if (dir) {
|
||||
|
||||
u32 max_start_id = 0;
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
|
||||
max_start_id++;
|
||||
|
||||
}
|
||||
|
||||
if (max_start_id > 4) {
|
||||
|
||||
sprintf(qd_synced_maxid, "%s/.synced/%s.max", afl->out_dir,
|
||||
sd_ent->d_name);
|
||||
s32 max_fd = open(qd_synced_maxid, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
DEFAULT_PERMISSION);
|
||||
|
||||
if (max_fd >= 0) {
|
||||
|
||||
max_start_id -= 4; // without ".", "..", ".state" and counting from 0
|
||||
write(max_fd, &max_start_id, sizeof(u32));
|
||||
close(max_fd);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
}
|
||||
|
||||
closedir(sd);
|
||||
|
||||
update_sync_time(afl, &sync_start_us);
|
||||
|
||||
}
|
||||
|
||||
/* Grab interesting test cases from other fuzzers. */
|
||||
|
||||
void sync_fuzzers(afl_state_t *afl) {
|
||||
@ -842,7 +715,8 @@ void sync_fuzzers(afl_state_t *afl) {
|
||||
afl->cur_depth = 0;
|
||||
|
||||
u64 sync_start_us = get_cur_time_us();
|
||||
// Look at the entries created for every other fuzzer in the sync directory.
|
||||
/* Look at the entries created for every other fuzzer in the sync directory.
|
||||
*/
|
||||
|
||||
while ((sd_ent = readdir(sd))) {
|
||||
|
||||
@ -850,11 +724,12 @@ void sync_fuzzers(afl_state_t *afl) {
|
||||
// iteration
|
||||
update_sync_time(afl, &sync_start_us);
|
||||
|
||||
u8 qd_synced_path[PATH_MAX], qd_path[PATH_MAX], qd_synced_maxid[PATH_MAX];
|
||||
u32 min_accept = 0, next_min_accept = 0, max_start_id = 0;
|
||||
u8 qd_synced_path[PATH_MAX], qd_path[PATH_MAX];
|
||||
u32 min_accept = 0, next_min_accept = 0;
|
||||
|
||||
s32 id_fd;
|
||||
|
||||
// Skip dot files and our own output directory.
|
||||
/* Skip dot files and our own output directory. */
|
||||
|
||||
if (sd_ent->d_name[0] == '.' || !strcmp(afl->sync_id, sd_ent->d_name)) {
|
||||
|
||||
@ -889,7 +764,14 @@ void sync_fuzzers(afl_state_t *afl) {
|
||||
|
||||
synced++;
|
||||
|
||||
// Skip anything that doesn't have a queue/ subdirectory.
|
||||
/* document the attempt to sync to this instance */
|
||||
|
||||
sprintf(qd_synced_path, "%s/.synced/%s.last", afl->out_dir, sd_ent->d_name);
|
||||
id_fd =
|
||||
open(qd_synced_path, O_RDWR | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
|
||||
if (id_fd >= 0) close(id_fd);
|
||||
|
||||
/* Skip anything that doesn't have a queue/ subdirectory. */
|
||||
|
||||
sprintf(qd_path, "%s/%s/queue", afl->sync_dir, sd_ent->d_name);
|
||||
|
||||
@ -905,20 +787,14 @@ void sync_fuzzers(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
// Retrieve the ID of the last seen test case.
|
||||
/* Retrieve the ID of the last seen test case. */
|
||||
|
||||
sprintf(qd_synced_path, "%s/.synced/%s", afl->out_dir, sd_ent->d_name);
|
||||
|
||||
id_fd = open(qd_synced_path, O_RDWR | O_CREAT, afl->perm);
|
||||
id_fd = open(qd_synced_path, O_RDWR | O_CREAT, DEFAULT_PERMISSION);
|
||||
|
||||
if (id_fd < 0) { PFATAL("Unable to create '%s'", qd_synced_path); }
|
||||
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (fchown(id_fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
|
||||
|
||||
}
|
||||
|
||||
if (read(id_fd, &min_accept, sizeof(u32)) == sizeof(u32)) {
|
||||
|
||||
next_min_accept = min_accept;
|
||||
@ -926,55 +802,6 @@ void sync_fuzzers(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
// now document the attempt to sync to this instance
|
||||
sprintf(qd_synced_path, "%s/.synced/%s.last", afl->out_dir, sd_ent->d_name);
|
||||
int id_fd2 =
|
||||
open(qd_synced_path, O_RDWR | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
|
||||
if (id_fd2 >= 0) close(id_fd2);
|
||||
|
||||
// It could be that the target syncing instance was restarted, check!
|
||||
time_t last_mtime = 0;
|
||||
char id0[PATH_MAX];
|
||||
struct stat st;
|
||||
|
||||
if (stat(qd_synced_path, &st) == 0) { last_mtime = st.st_mtime; }
|
||||
|
||||
snprintf(id0, sizeof(id0), "%s/%s/cmdline", afl->sync_dir, sd_ent->d_name);
|
||||
|
||||
if (likely(stat(id0, &st) == 0)) {
|
||||
|
||||
if (unlikely(last_mtime && last_mtime <= st.st_mtime)) {
|
||||
|
||||
// the first entry is newer than when we synced last - instance was
|
||||
// restarted - we have to reset our counter and will skip this instance
|
||||
// this time. It could also be this was trimmed later, or restated with
|
||||
// resume-in-place though but better be safe.
|
||||
min_accept = 0;
|
||||
ck_write(id_fd, &min_accept, sizeof(u32), qd_synced_path);
|
||||
goto close_sync;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// something went wrong - this cannot be right, mabye the instance is
|
||||
// restarting, skip
|
||||
goto close_sync;
|
||||
|
||||
}
|
||||
|
||||
// check if there is a file documented the maximum id seen on startup
|
||||
sprintf(qd_synced_maxid, "%s/.synced/%s.max", afl->out_dir, sd_ent->d_name);
|
||||
s32 max_fd = open(qd_synced_maxid, O_RDONLY, DEFAULT_PERMISSION);
|
||||
|
||||
if (max_fd >= 0) {
|
||||
|
||||
read(max_fd, &max_start_id, sizeof(u32));
|
||||
close(max_fd);
|
||||
if (max_start_id < next_min_accept) { unlink(qd_synced_maxid); }
|
||||
|
||||
}
|
||||
|
||||
/* Show stats */
|
||||
|
||||
snprintf(afl->stage_name_buf, STAGE_BUF_SIZE, "sync %u", ++sync_cnt);
|
||||
@ -1028,37 +855,34 @@ void sync_fuzzers(afl_state_t *afl) {
|
||||
|
||||
if (st.st_size && st.st_size <= MAX_FILE) {
|
||||
|
||||
if (likely(next_min_accept < max_start_id ||
|
||||
!is_known_case(afl, namelist[o]->d_name))) {
|
||||
u8 fault;
|
||||
u8 *mem = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
|
||||
/* See what happens. We rely on save_if_interesting() to catch major
|
||||
errors and save the test case. */
|
||||
if (mem == MAP_FAILED) { PFATAL("Unable to mmap '%s'", path); }
|
||||
|
||||
u8 *mem = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
/* See what happens. We rely on save_if_interesting() to catch major
|
||||
errors and save the test case. */
|
||||
|
||||
if (mem == MAP_FAILED) { PFATAL("Unable to mmap '%s'", path); }
|
||||
u32 new_len = write_to_testcase(afl, (void **)&mem, st.st_size, 1);
|
||||
|
||||
u32 new_len = write_to_testcase(afl, (void **)&mem, st.st_size, 1);
|
||||
fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
|
||||
|
||||
u8 fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
|
||||
if (afl->stop_soon) {
|
||||
|
||||
if (afl->stop_soon) {
|
||||
|
||||
munmap(mem, st.st_size);
|
||||
close(fd);
|
||||
|
||||
goto close_sync;
|
||||
|
||||
}
|
||||
|
||||
afl->syncing_party = sd_ent->d_name;
|
||||
afl->queued_imported += save_if_interesting(afl, mem, new_len, fault);
|
||||
show_stats(afl);
|
||||
afl->syncing_party = 0;
|
||||
munmap(mem, st.st_size);
|
||||
close(fd);
|
||||
|
||||
goto close_sync;
|
||||
|
||||
}
|
||||
|
||||
afl->syncing_party = sd_ent->d_name;
|
||||
afl->queued_imported += save_if_interesting(afl, mem, new_len, fault);
|
||||
show_stats(afl);
|
||||
afl->syncing_party = 0;
|
||||
|
||||
munmap(mem, st.st_size);
|
||||
|
||||
}
|
||||
|
||||
close(fd);
|
||||
@ -1316,7 +1140,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
|
||||
|
||||
if (unlikely(afl->no_unlink)) {
|
||||
|
||||
fd = open(q->fname, O_WRONLY | O_CREAT | O_TRUNC, afl->perm);
|
||||
fd = open(q->fname, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
|
||||
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); }
|
||||
|
||||
@ -1331,7 +1155,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
|
||||
} else {
|
||||
|
||||
unlink(q->fname); /* ignore errors */
|
||||
fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, afl->perm);
|
||||
fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
|
||||
if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); }
|
||||
|
||||
@ -1339,12 +1163,6 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
|
||||
|
||||
}
|
||||
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
|
||||
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
queue_testcase_retake_mem(afl, q, in_buf, q->len, orig_len);
|
||||
|
@ -39,9 +39,6 @@ void sanfuzz_exec_child(afl_forkserver_t *fsrv, char **argv) {
|
||||
|
||||
}
|
||||
|
||||
// In case users provide the normally instrumented binaries, this servers as
|
||||
// the last resort to avoid collecting incorrect coverage.
|
||||
setenv("AFL_LLVM_ONLY_FSRV", "1", 0);
|
||||
execv(fsrv->target_path, argv);
|
||||
|
||||
}
|
||||
|
@ -148,34 +148,6 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) {
|
||||
|
||||
}
|
||||
|
||||
void afl_resize_map_buffers(afl_state_t *afl, u32 old_size, u32 new_size) {
|
||||
|
||||
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_size);
|
||||
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_size);
|
||||
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_size);
|
||||
afl->var_bytes = ck_realloc(afl->var_bytes, new_size);
|
||||
afl->top_rated = ck_realloc(afl->top_rated, new_size * sizeof(void *));
|
||||
afl->clean_trace = ck_realloc(afl->clean_trace, new_size);
|
||||
afl->clean_trace_custom = ck_realloc(afl->clean_trace_custom, new_size);
|
||||
afl->first_trace = ck_realloc(afl->first_trace, new_size);
|
||||
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_size);
|
||||
|
||||
if (old_size < new_size) {
|
||||
|
||||
u32 size_diff = new_size - old_size;
|
||||
|
||||
memset(afl->var_bytes + old_size, 0, size_diff);
|
||||
memset(afl->top_rated + old_size * sizeof(void *), 0,
|
||||
size_diff * sizeof(void *));
|
||||
memset(afl->clean_trace + old_size, 0, size_diff);
|
||||
memset(afl->clean_trace_custom + old_size, 0, size_diff);
|
||||
memset(afl->first_trace + old_size, 0, size_diff);
|
||||
memset(afl->map_tmp_buf + old_size, 0, size_diff);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*This sets up the environment variables for afl-fuzz into the afl_state
|
||||
* struct*/
|
||||
|
||||
@ -683,89 +655,6 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
|
||||
afl->afl_env.afl_sha1_filenames =
|
||||
get_afl_env(afl_environment_variables[i]) ? 1 : 0;
|
||||
|
||||
} else if (!strncmp(env, "AFL_FORKSRV_UID",
|
||||
|
||||
afl_environment_variable_len)) {
|
||||
|
||||
u8 *uid_str = (u8 *)get_afl_env(afl_environment_variables[i]);
|
||||
char *ret;
|
||||
int uid = strtol(uid_str, &ret, 10);
|
||||
if (*ret != '\0') {
|
||||
|
||||
WARNF("Incorrect value given to AFL_FORKSRV_UID\n");
|
||||
|
||||
} else {
|
||||
|
||||
afl->afl_env.afl_forksrv_uid_set = 1;
|
||||
afl->afl_env.afl_forksrv_uid = uid;
|
||||
|
||||
}
|
||||
|
||||
} else if (!strncmp(env, "AFL_FORKSRV_GID",
|
||||
|
||||
afl_environment_variable_len)) {
|
||||
|
||||
u8 *gid_str = (u8 *)get_afl_env(afl_environment_variables[i]);
|
||||
|
||||
// Count the number of supplementary GIDs
|
||||
// and prepare the string for the next loop
|
||||
afl->afl_env.afl_forksrv_nb_supl_gids = 0;
|
||||
for (u32 i = 0; gid_str[i] != '\0'; i++) {
|
||||
|
||||
if (gid_str[i] == ',') {
|
||||
|
||||
afl->afl_env.afl_forksrv_nb_supl_gids++;
|
||||
gid_str[i] = '\0';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (afl->afl_env.afl_forksrv_nb_supl_gids > 0) {
|
||||
|
||||
afl->afl_env.afl_forksrv_supl_gids = ck_alloc(
|
||||
sizeof(gid_t) * afl->afl_env.afl_forksrv_nb_supl_gids);
|
||||
|
||||
}
|
||||
|
||||
for (u16 i = 0; i < afl->afl_env.afl_forksrv_nb_supl_gids + 1;
|
||||
i++) {
|
||||
|
||||
char *ret;
|
||||
int gid = strtol(gid_str, &ret, 10);
|
||||
|
||||
if (*ret != '\0') {
|
||||
|
||||
WARNF("Incorrect value given to AFL_FORKSRV_GID\n");
|
||||
|
||||
afl->afl_env.afl_forksrv_gid_set = 0;
|
||||
afl->afl_env.afl_forksrv_gid = 0;
|
||||
free(afl->afl_env.afl_forksrv_supl_gids);
|
||||
|
||||
break;
|
||||
|
||||
} else {
|
||||
|
||||
// First GID is the effective one, others are supplementary
|
||||
// ones.
|
||||
if (i == 0) {
|
||||
|
||||
afl->afl_env.afl_forksrv_gid_set = 1;
|
||||
afl->afl_env.afl_forksrv_gid = gid;
|
||||
|
||||
} else {
|
||||
|
||||
afl->afl_env.afl_forksrv_supl_gids[i - 1] = gid;
|
||||
|
||||
}
|
||||
|
||||
// Jump to next GID
|
||||
gid_str = ret + 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -891,8 +780,6 @@ void afl_state_deinit(afl_state_t *afl) {
|
||||
ck_free(afl->skipdet_g);
|
||||
ck_free(afl->havoc_prof);
|
||||
|
||||
ck_free(afl->afl_env.afl_forksrv_supl_gids);
|
||||
|
||||
list_remove(&afl_states, afl);
|
||||
|
||||
}
|
||||
|
@ -28,13 +28,8 @@
|
||||
#include "envs.h"
|
||||
#include <limits.h>
|
||||
|
||||
// 7 is the number of characters in a color control code
|
||||
// 11 is the number of characters in the fuzzing state itself
|
||||
// 5 is the number of characters in `cRST`
|
||||
// 1 is for the null character
|
||||
static char fuzzing_state[4][7 + 11 + 5 + 1] = {
|
||||
|
||||
"started :-)", "in progress", "final phase", cRED "finished..." cRST};
|
||||
static char fuzzing_state[4][12] = {"started :-)", "in progress", "final phase",
|
||||
"finished..."};
|
||||
|
||||
char *get_fuzzing_state(afl_state_t *afl) {
|
||||
|
||||
@ -59,13 +54,13 @@ char *get_fuzzing_state(afl_state_t *afl) {
|
||||
u64 percent_cur = last_find_100 / cur_run_time;
|
||||
u64 percent_total = last_find_100 / cur_total_run_time;
|
||||
|
||||
if (unlikely(percent_cur >= 75 && percent_total >= 75)) {
|
||||
if (unlikely(percent_cur >= 80 && percent_total >= 80)) {
|
||||
|
||||
if (unlikely(afl->afl_env.afl_exit_when_done)) { afl->stop_soon = 2; }
|
||||
|
||||
return fuzzing_state[3];
|
||||
|
||||
} else if (unlikely(percent_cur >= 50 && percent_total >= 50)) {
|
||||
} else if (unlikely(percent_cur >= 55 && percent_total >= 55)) {
|
||||
|
||||
return fuzzing_state[2];
|
||||
|
||||
@ -86,13 +81,7 @@ void write_setup_file(afl_state_t *afl, u32 argc, char **argv) {
|
||||
u8 fn[PATH_MAX], fn2[PATH_MAX];
|
||||
|
||||
snprintf(fn2, PATH_MAX, "%s/target_hash", afl->out_dir);
|
||||
FILE *f2 = create_ffile(fn2, afl->perm);
|
||||
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (chown(fn2, -1, afl->fsrv.gid) == -1) { PFATAL("chown() failed"); }
|
||||
|
||||
}
|
||||
FILE *f2 = create_ffile(fn2);
|
||||
|
||||
#ifdef __linux__
|
||||
if (afl->fsrv.nyx_mode) {
|
||||
@ -112,15 +101,9 @@ void write_setup_file(afl_state_t *afl, u32 argc, char **argv) {
|
||||
fclose(f2);
|
||||
|
||||
snprintf(fn, PATH_MAX, "%s/fuzzer_setup", afl->out_dir);
|
||||
FILE *f = create_ffile(fn, afl->perm);
|
||||
FILE *f = create_ffile(fn);
|
||||
u32 i;
|
||||
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (chown(fn, -1, afl->fsrv.gid) == -1) { PFATAL("chown() failed"); }
|
||||
|
||||
}
|
||||
|
||||
fprintf(f, "# environment variables:\n");
|
||||
u32 s_afl_env = (u32)sizeof(afl_environment_variables) /
|
||||
sizeof(afl_environment_variables[0]) -
|
||||
@ -335,13 +318,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
|
||||
|
||||
snprintf(fn_tmp, PATH_MAX, "%s/.fuzzer_stats_tmp", afl->out_dir);
|
||||
snprintf(fn_final, PATH_MAX, "%s/fuzzer_stats", afl->out_dir);
|
||||
f = create_ffile(fn_tmp, afl->perm);
|
||||
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (chown(fn_tmp, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
|
||||
|
||||
}
|
||||
f = create_ffile(fn_tmp);
|
||||
|
||||
/* Keep last values in case we're called from another context
|
||||
where exec/sec stats and such are not readily available. */
|
||||
|
175
src/afl-fuzz.c
175
src/afl-fuzz.c
@ -602,49 +602,6 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
if (debug) { afl->fsrv.debug = true; }
|
||||
read_afl_environment(afl, envp);
|
||||
if (afl->shm.map_size) { afl->fsrv.map_size = afl->shm.map_size; }
|
||||
|
||||
if (afl->afl_env.afl_forksrv_uid_set) {
|
||||
|
||||
afl->fsrv.uid_set = 1;
|
||||
afl->fsrv.uid = afl->afl_env.afl_forksrv_uid;
|
||||
|
||||
}
|
||||
|
||||
if (afl->afl_env.afl_forksrv_gid_set) {
|
||||
|
||||
afl->fsrv.gid_set = 1;
|
||||
afl->fsrv.gid = afl->afl_env.afl_forksrv_gid;
|
||||
afl->fsrv.nb_supl_gids = afl->afl_env.afl_forksrv_nb_supl_gids;
|
||||
afl->fsrv.supl_gids = afl->afl_env.afl_forksrv_supl_gids;
|
||||
|
||||
}
|
||||
|
||||
if (afl->fsrv.uid_set) {
|
||||
|
||||
/* If the UID is modified, allow group to open files and dirs */
|
||||
afl->perm = DEFAULT_PERMISSION | 0060;
|
||||
afl->fsrv.perm = afl->perm;
|
||||
afl->dir_perm = DEFAULT_DIRS_PERMISSION | 0070;
|
||||
|
||||
/* Ensure permissions will be really set*/
|
||||
umask(~(afl->perm | afl->dir_perm));
|
||||
|
||||
/* If the GID is also modified, then change the group of files and dirs */
|
||||
if (afl->fsrv.gid_set) {
|
||||
|
||||
afl->chown_needed = 1;
|
||||
afl->fsrv.chown_needed = 1;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
afl->perm = DEFAULT_PERMISSION;
|
||||
afl->fsrv.perm = afl->perm;
|
||||
afl->dir_perm = DEFAULT_DIRS_PERMISSION;
|
||||
|
||||
}
|
||||
|
||||
exit_1 = !!afl->afl_env.afl_bench_just_one;
|
||||
|
||||
SAYF(cCYA "afl-fuzz" VERSION cRST
|
||||
@ -1545,9 +1502,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
if (afl->is_main_node == 1 && afl->schedule != FAST &&
|
||||
afl->schedule != EXPLORE) {
|
||||
|
||||
WARNF(
|
||||
"When using -M, it is recommended to use only fast or explore -p power "
|
||||
"schedules");
|
||||
FATAL("-M is compatible only with fast and explore -p power schedules");
|
||||
|
||||
}
|
||||
|
||||
@ -1790,7 +1745,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
if (afl->cycle_schedules) {
|
||||
|
||||
afl->top_rated_candidates = ck_alloc(map_size * sizeof(u32 *));
|
||||
afl->top_rated_candidates = ck_alloc(map_size * sizeof(u32));
|
||||
|
||||
}
|
||||
|
||||
@ -2352,7 +2307,11 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
u64 target_hash = get_binary_hash(afl->fsrv.target_path);
|
||||
#endif
|
||||
|
||||
if (!target_hash || prev_target_hash != target_hash) {
|
||||
if ((!target_hash || prev_target_hash != target_hash)
|
||||
#ifdef __linux__
|
||||
|| (afl->fsrv.nyx_mode && target_hash == 0)
|
||||
#endif
|
||||
) {
|
||||
|
||||
ACTF("Target binary is different, cannot perform FAST RESUME!");
|
||||
|
||||
@ -2543,15 +2502,35 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
if (afl->non_instrumented_mode || afl->fsrv.qemu_mode ||
|
||||
afl->fsrv.frida_mode || afl->fsrv.cs_mode || afl->unicorn_mode) {
|
||||
|
||||
u32 old_map_size = map_size;
|
||||
map_size = afl->fsrv.real_map_size = afl->fsrv.map_size = MAP_SIZE;
|
||||
afl_resize_map_buffers(afl, map_size, MAP_SIZE);
|
||||
afl->virgin_bits = ck_realloc(afl->virgin_bits, map_size);
|
||||
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, map_size);
|
||||
afl->virgin_crash = ck_realloc(afl->virgin_crash, map_size);
|
||||
afl->var_bytes = ck_realloc(afl->var_bytes, map_size);
|
||||
afl->top_rated = ck_realloc(afl->top_rated, map_size * sizeof(void *));
|
||||
afl->clean_trace = ck_realloc(afl->clean_trace, map_size);
|
||||
afl->clean_trace_custom = ck_realloc(afl->clean_trace_custom, map_size);
|
||||
afl->first_trace = ck_realloc(afl->first_trace, map_size);
|
||||
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, map_size);
|
||||
|
||||
if (old_map_size < map_size) {
|
||||
|
||||
memset(afl->var_bytes + old_map_size, 0, map_size - old_map_size);
|
||||
memset(afl->top_rated + old_map_size, 0, map_size - old_map_size);
|
||||
memset(afl->clean_trace + old_map_size, 0, map_size - old_map_size);
|
||||
memset(afl->clean_trace_custom + old_map_size, 0,
|
||||
map_size - old_map_size);
|
||||
memset(afl->first_trace + old_map_size, 0, map_size - old_map_size);
|
||||
memset(afl->map_tmp_buf + old_map_size, 0, map_size - old_map_size);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
afl->argv = use_argv;
|
||||
afl->fsrv.trace_bits =
|
||||
afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->non_instrumented_mode,
|
||||
afl->perm, afl->chown_needed ? afl->fsrv.gid : -1);
|
||||
afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->non_instrumented_mode);
|
||||
|
||||
if (!afl->non_instrumented_mode && !afl->fsrv.qemu_mode &&
|
||||
!afl->unicorn_mode && !afl->fsrv.frida_mode && !afl->fsrv.cs_mode &&
|
||||
@ -2573,14 +2552,37 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
if (map_size < new_map_size) {
|
||||
|
||||
OKF("Re-initializing maps to %u bytes", new_map_size);
|
||||
afl_resize_map_buffers(afl, map_size, new_map_size);
|
||||
|
||||
u32 old_map_size = map_size;
|
||||
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
|
||||
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
|
||||
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
|
||||
afl->var_bytes = ck_realloc(afl->var_bytes, new_map_size);
|
||||
afl->top_rated =
|
||||
ck_realloc(afl->top_rated, new_map_size * sizeof(void *));
|
||||
afl->clean_trace = ck_realloc(afl->clean_trace, new_map_size);
|
||||
afl->clean_trace_custom =
|
||||
ck_realloc(afl->clean_trace_custom, new_map_size);
|
||||
afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
|
||||
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
|
||||
|
||||
if (old_map_size < new_map_size) {
|
||||
|
||||
memset(afl->var_bytes + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->top_rated + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->clean_trace + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->clean_trace_custom + old_map_size, 0,
|
||||
new_map_size - old_map_size);
|
||||
memset(afl->first_trace + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->map_tmp_buf + old_map_size, 0, new_map_size - old_map_size);
|
||||
|
||||
}
|
||||
|
||||
afl_fsrv_kill(&afl->fsrv);
|
||||
afl_shm_deinit(&afl->shm);
|
||||
afl->fsrv.map_size = new_map_size;
|
||||
afl->fsrv.trace_bits =
|
||||
afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode,
|
||||
afl->perm, afl->chown_needed ? afl->fsrv.gid : -1);
|
||||
afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode);
|
||||
setenv("AFL_NO_AUTODICT", "1", 1); // loaded already
|
||||
afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
|
||||
afl->afl_env.afl_debug_child);
|
||||
@ -2635,6 +2637,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
*/
|
||||
afl->san_fsrvs[i].trace_bits = ck_alloc(
|
||||
afl->fsrv.map_size + 8); /* One more u64 according to afl_shm_init*/
|
||||
afl->san_fsrvs[i].map_size = afl->fsrv.map_size;
|
||||
afl->san_fsrvs[i].san_but_not_instrumented = 1;
|
||||
|
||||
afl->san_fsrvs[i].cs_mode = afl->fsrv.cs_mode;
|
||||
@ -2644,6 +2647,10 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
afl->san_fsrvs[i].target_path = afl->san_binary[i];
|
||||
afl->san_fsrvs[i].init_child_func = sanfuzz_exec_child;
|
||||
|
||||
afl->san_fsrvs[i].child_kill_signal =
|
||||
afl->fsrv.child_kill_signal; // I believe cmplog also needs this.
|
||||
afl->san_fsrvs[i].fsrv_kill_signal = afl->fsrv.fsrv_kill_signal;
|
||||
|
||||
if ((map_size <= DEFAULT_SHMEM_SIZE ||
|
||||
afl->san_fsrvs[i].map_size < map_size) &&
|
||||
!afl->non_instrumented_mode && !afl->fsrv.qemu_mode &&
|
||||
@ -2666,7 +2673,18 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
OKF("Re-initializing maps to %u bytes due to SAN instrumented binary",
|
||||
new_map_size);
|
||||
afl_resize_map_buffers(afl, map_size, new_map_size);
|
||||
|
||||
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
|
||||
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
|
||||
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
|
||||
afl->var_bytes = ck_realloc(afl->var_bytes, new_map_size);
|
||||
afl->top_rated =
|
||||
ck_realloc(afl->top_rated, new_map_size * sizeof(void *));
|
||||
afl->clean_trace = ck_realloc(afl->clean_trace, new_map_size);
|
||||
afl->clean_trace_custom =
|
||||
ck_realloc(afl->clean_trace_custom, new_map_size);
|
||||
afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
|
||||
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
|
||||
|
||||
afl_fsrv_kill(&afl->fsrv);
|
||||
afl_fsrv_kill(&afl->san_fsrvs[i]);
|
||||
@ -2677,8 +2695,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
setenv("AFL_NO_AUTODICT", "1", 1); // loaded already
|
||||
afl->fsrv.trace_bits =
|
||||
afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode,
|
||||
afl->perm, afl->chown_needed ? afl->fsrv.gid : -1);
|
||||
afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode);
|
||||
ck_free(afl->san_fsrvs[i].trace_bits);
|
||||
afl->san_fsrvs[i].trace_bits = ck_alloc(afl->fsrv.map_size + 8);
|
||||
afl->san_fsrvs[i].map_size = afl->fsrv.map_size;
|
||||
@ -2733,7 +2750,31 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
if (map_size < new_map_size) {
|
||||
|
||||
OKF("Re-initializing maps to %u bytes due cmplog", new_map_size);
|
||||
afl_resize_map_buffers(afl, map_size, new_map_size);
|
||||
|
||||
u32 old_map_size = map_size;
|
||||
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
|
||||
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
|
||||
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
|
||||
afl->var_bytes = ck_realloc(afl->var_bytes, new_map_size);
|
||||
afl->top_rated =
|
||||
ck_realloc(afl->top_rated, new_map_size * sizeof(void *));
|
||||
afl->clean_trace = ck_realloc(afl->clean_trace, new_map_size);
|
||||
afl->clean_trace_custom =
|
||||
ck_realloc(afl->clean_trace_custom, new_map_size);
|
||||
afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
|
||||
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
|
||||
|
||||
if (old_map_size < new_map_size) {
|
||||
|
||||
memset(afl->var_bytes + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->top_rated + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->clean_trace + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->clean_trace_custom + old_map_size, 0,
|
||||
new_map_size - old_map_size);
|
||||
memset(afl->first_trace + old_map_size, 0, new_map_size - old_map_size);
|
||||
memset(afl->map_tmp_buf + old_map_size, 0, new_map_size - old_map_size);
|
||||
|
||||
}
|
||||
|
||||
afl_fsrv_kill(&afl->fsrv);
|
||||
afl_fsrv_kill(&afl->cmplog_fsrv);
|
||||
@ -2744,8 +2785,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
setenv("AFL_NO_AUTODICT", "1", 1); // loaded already
|
||||
afl->fsrv.trace_bits =
|
||||
afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode,
|
||||
afl->perm, afl->chown_needed ? afl->fsrv.gid : -1);
|
||||
afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode);
|
||||
afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits;
|
||||
afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
|
||||
afl->afl_env.afl_debug_child);
|
||||
@ -2962,8 +3002,6 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
if (afl->stop_soon) { goto stop_fuzzing; }
|
||||
|
||||
if (!afl->in_place_resume) { check_sync_fuzzers(afl); }
|
||||
|
||||
/* Woop woop woop */
|
||||
|
||||
if (!afl->not_on_tty) {
|
||||
@ -3495,17 +3533,8 @@ stop_fuzzing:
|
||||
if ((fr_fd = ZLIBOPEN(fr, "wb9")) != NULL) {
|
||||
|
||||
#else
|
||||
if ((fr_fd = open(fr, O_WRONLY | O_TRUNC | O_CREAT, afl->perm)) >= 0) {
|
||||
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (fchown(fr_fd, -1, afl->fsrv.gid) == -1) {
|
||||
|
||||
PFATAL("fchown() failed");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if ((fr_fd = open(fr, O_WRONLY | O_TRUNC | O_CREAT, DEFAULT_PERMISSION)) >=
|
||||
0) {
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -71,7 +71,6 @@ void afl_shm_deinit(sharedmem_t *shm) {
|
||||
if (shm->shmemfuzz_mode) {
|
||||
|
||||
unsetenv(SHM_FUZZ_ENV_VAR);
|
||||
unsetenv(SHM_FUZZ_MAP_SIZE_ENV_VAR);
|
||||
|
||||
} else {
|
||||
|
||||
@ -142,8 +141,7 @@ void afl_shm_deinit(sharedmem_t *shm) {
|
||||
*/
|
||||
|
||||
u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
|
||||
unsigned char non_instrumented_mode, mode_t permission,
|
||||
int gid) {
|
||||
unsigned char non_instrumented_mode) {
|
||||
|
||||
shm->map_size = 0;
|
||||
|
||||
@ -182,13 +180,7 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
|
||||
|
||||
shm->g_shm_fd =
|
||||
shm_create_largepage(shm->g_shm_file_path, shmflags, i,
|
||||
SHM_LARGEPAGE_ALLOC_DEFAULT, permission);
|
||||
|
||||
if (gid != -1 && shm->g_shm_fd != -1) {
|
||||
|
||||
if (fchown(shm->g_shm_fd, -1, gid) == -1) { PFATAL("fchown() failed"); }
|
||||
|
||||
}
|
||||
SHM_LARGEPAGE_ALLOC_DEFAULT, DEFAULT_PERMISSION);
|
||||
|
||||
}
|
||||
|
||||
@ -200,13 +192,7 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
|
||||
if (shm->g_shm_fd == -1) {
|
||||
|
||||
shm->g_shm_fd =
|
||||
shm_open(shm->g_shm_file_path, shmflags | O_CREAT, permission);
|
||||
|
||||
if (gid != -1 && shm->g_shm_fd != -1) {
|
||||
|
||||
if (fchown(shm->g_shm_fd, -1, gid) == -1) { PFATAL("fchown() failed"); }
|
||||
|
||||
}
|
||||
shm_open(shm->g_shm_file_path, shmflags | O_CREAT, DEFAULT_PERMISSION);
|
||||
|
||||
}
|
||||
|
||||
@ -247,14 +233,10 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
|
||||
getpid(), random());
|
||||
|
||||
/* create the shared memory segment as if it was a file */
|
||||
shm->cmplog_g_shm_fd = shm_open(shm->cmplog_g_shm_file_path,
|
||||
O_CREAT | O_RDWR | O_EXCL, permission);
|
||||
shm->cmplog_g_shm_fd =
|
||||
shm_open(shm->cmplog_g_shm_file_path, O_CREAT | O_RDWR | O_EXCL,
|
||||
DEFAULT_PERMISSION);
|
||||
if (shm->cmplog_g_shm_fd == -1) { PFATAL("shm_open() failed"); }
|
||||
if (gid != -1) {
|
||||
|
||||
if (fchown(shm->g_shm_fd, -1, gid) == -1) { PFATAL("fchown() failed"); }
|
||||
|
||||
}
|
||||
|
||||
/* configure the size of the shared memory segment */
|
||||
if (ftruncate(shm->cmplog_g_shm_fd, sizeof(struct cmp_map))) {
|
||||
@ -290,41 +272,23 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
|
||||
}
|
||||
|
||||
#else
|
||||
u8 *shm_str;
|
||||
struct shmid_ds shmid_ds;
|
||||
u8 *shm_str;
|
||||
|
||||
// for qemu+unicorn we have to increase by 8 to account for potential
|
||||
// compcov map overwrite
|
||||
shm->shm_id =
|
||||
shmget(IPC_PRIVATE, map_size == MAP_SIZE ? map_size + 8 : map_size,
|
||||
IPC_CREAT | IPC_EXCL | permission);
|
||||
IPC_CREAT | IPC_EXCL | DEFAULT_PERMISSION);
|
||||
if (shm->shm_id < 0) {
|
||||
|
||||
PFATAL("shmget() failed, try running afl-system-config");
|
||||
|
||||
}
|
||||
|
||||
if (gid != -1) {
|
||||
|
||||
if (shmctl(shm->shm_id, IPC_STAT, &shmid_ds) == -1) {
|
||||
|
||||
PFATAL("shmctl(IPC_STAT) failed");
|
||||
|
||||
}
|
||||
|
||||
shmid_ds.shm_perm.gid = (gid_t)gid;
|
||||
if (shmctl(shm->shm_id, IPC_SET, &shmid_ds) == -1) {
|
||||
|
||||
PFATAL("shmctl(IPC_SET) failed");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (shm->cmplog_mode) {
|
||||
|
||||
shm->cmplog_shm_id = shmget(IPC_PRIVATE, sizeof(struct cmp_map),
|
||||
IPC_CREAT | IPC_EXCL | permission);
|
||||
IPC_CREAT | IPC_EXCL | DEFAULT_PERMISSION);
|
||||
|
||||
if (shm->cmplog_shm_id < 0) {
|
||||
|
||||
@ -333,23 +297,6 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
|
||||
|
||||
}
|
||||
|
||||
if (gid != -1) {
|
||||
|
||||
if (shmctl(shm->cmplog_shm_id, IPC_STAT, &shmid_ds) == -1) {
|
||||
|
||||
PFATAL("shmctl(IPC_STAT) failed");
|
||||
|
||||
}
|
||||
|
||||
shmid_ds.shm_perm.gid = (gid_t)gid;
|
||||
if (shmctl(shm->cmplog_shm_id, IPC_SET, &shmid_ds) == -1) {
|
||||
|
||||
PFATAL("shmctl(IPC_SET) failed");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!non_instrumented_mode) {
|
||||
|
@ -714,8 +714,61 @@ static void handle_stop_sig(int sig) {
|
||||
|
||||
static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
|
||||
|
||||
char *afl_preload;
|
||||
char *frida_afl_preload = NULL;
|
||||
|
||||
set_sanitizer_defaults();
|
||||
afl_fsrv_setup_preload(fsrv, argv[0]);
|
||||
|
||||
if (get_afl_env("AFL_PRELOAD")) {
|
||||
|
||||
if (fsrv->qemu_mode) {
|
||||
|
||||
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
|
||||
|
||||
} else if (fsrv->frida_mode) {
|
||||
|
||||
afl_preload = getenv("AFL_PRELOAD");
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
if (afl_preload) {
|
||||
|
||||
frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
|
||||
|
||||
} else {
|
||||
|
||||
frida_afl_preload = alloc_printf("%s", frida_binary);
|
||||
|
||||
}
|
||||
|
||||
ck_free(frida_binary);
|
||||
|
||||
setenv("LD_PRELOAD", frida_afl_preload, 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
|
||||
/* CoreSight mode uses the default behavior. */
|
||||
|
||||
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
} else if (fsrv->frida_mode) {
|
||||
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
setenv("LD_PRELOAD", frida_binary, 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
|
||||
#endif
|
||||
ck_free(frida_binary);
|
||||
|
||||
}
|
||||
|
||||
if (frida_afl_preload) { ck_free(frida_afl_preload); }
|
||||
|
||||
}
|
||||
|
||||
@ -1348,7 +1401,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
fsrv->target_path = find_binary(argv[optind]);
|
||||
#endif
|
||||
|
||||
fsrv->trace_bits = afl_shm_init(&shm, map_size, 0, DEFAULT_PERMISSION, -1);
|
||||
fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
|
||||
|
||||
if (!quiet_mode) {
|
||||
|
||||
@ -1487,16 +1540,9 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
shm_fuzz->cmplog_mode = 0;
|
||||
atexit(at_exit_handler);
|
||||
|
||||
size_t shm_fuzz_map_size = SHM_FUZZ_MAP_SIZE_DEFAULT;
|
||||
u8 *map = afl_shm_init(shm_fuzz, SHM_FUZZ_MAP_SIZE_DEFAULT, 1,
|
||||
DEFAULT_PERMISSION, -1);
|
||||
u8 *map = afl_shm_init(shm_fuzz, MAX_FILE + sizeof(u32), 1);
|
||||
shm_fuzz->shmemfuzz_mode = true;
|
||||
if (!map) { FATAL("BUG: Zero return from afl_shm_init."); }
|
||||
|
||||
u8 *shm_fuzz_map_size_str = alloc_printf("%zu", shm_fuzz_map_size);
|
||||
setenv(SHM_FUZZ_MAP_SIZE_ENV_VAR, shm_fuzz_map_size_str, 1);
|
||||
ck_free(shm_fuzz_map_size_str);
|
||||
|
||||
#ifdef USEMMAP
|
||||
setenv(SHM_FUZZ_ENV_VAR, shm_fuzz->g_shm_file_path, 1);
|
||||
#else
|
||||
@ -1543,7 +1589,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
// only reinitialize when it makes sense
|
||||
if (map_size < new_map_size ||
|
||||
(new_map_size < map_size && map_size - new_map_size > MAP_SIZE)) {
|
||||
(new_map_size > map_size && new_map_size - map_size > MAP_SIZE)) {
|
||||
|
||||
if (!be_quiet)
|
||||
ACTF("Acquired new map size for target: %u bytes\n", new_map_size);
|
||||
@ -1551,8 +1597,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
afl_shm_deinit(&shm);
|
||||
afl_fsrv_kill(fsrv);
|
||||
fsrv->map_size = new_map_size;
|
||||
fsrv->trace_bits =
|
||||
afl_shm_init(&shm, new_map_size, 0, DEFAULT_PERMISSION, -1);
|
||||
fsrv->trace_bits = afl_shm_init(&shm, new_map_size, 0);
|
||||
|
||||
}
|
||||
|
||||
|
@ -899,7 +899,9 @@ static void handle_stop_sig(int sig) {
|
||||
|
||||
static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
|
||||
|
||||
u8 *x;
|
||||
u8 *x;
|
||||
char *afl_preload;
|
||||
char *frida_afl_preload = NULL;
|
||||
|
||||
fsrv->dev_null_fd = open("/dev/null", O_RDWR);
|
||||
if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
|
||||
@ -943,7 +945,57 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
|
||||
}
|
||||
|
||||
set_sanitizer_defaults();
|
||||
afl_fsrv_setup_preload(fsrv, argv[0]);
|
||||
|
||||
if (get_afl_env("AFL_PRELOAD")) {
|
||||
|
||||
if (fsrv->qemu_mode) {
|
||||
|
||||
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
|
||||
|
||||
} else if (fsrv->frida_mode) {
|
||||
|
||||
afl_preload = getenv("AFL_PRELOAD");
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
if (afl_preload) {
|
||||
|
||||
frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
|
||||
|
||||
} else {
|
||||
|
||||
frida_afl_preload = alloc_printf("%s", frida_binary);
|
||||
|
||||
}
|
||||
|
||||
ck_free(frida_binary);
|
||||
|
||||
setenv("LD_PRELOAD", frida_afl_preload, 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
|
||||
/* CoreSight mode uses the default behavior. */
|
||||
|
||||
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
} else if (fsrv->frida_mode) {
|
||||
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
setenv("LD_PRELOAD", frida_binary, 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
|
||||
#endif
|
||||
ck_free(frida_binary);
|
||||
|
||||
}
|
||||
|
||||
if (frida_afl_preload) { ck_free(frida_afl_preload); }
|
||||
|
||||
}
|
||||
|
||||
@ -1332,7 +1384,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
fsrv->target_path = find_binary(argv[optind]);
|
||||
#endif
|
||||
|
||||
fsrv->trace_bits = afl_shm_init(&shm, map_size, 0, DEFAULT_PERMISSION, -1);
|
||||
fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
|
||||
detect_file_args(argv + optind, out_file, &fsrv->use_stdin);
|
||||
signal(SIGALRM, kill_child);
|
||||
|
||||
@ -1429,17 +1481,9 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
/* initialize cmplog_mode */
|
||||
shm_fuzz->cmplog_mode = 0;
|
||||
|
||||
size_t shm_fuzz_map_size = SHM_FUZZ_MAP_SIZE_DEFAULT;
|
||||
u8 *map = afl_shm_init(shm_fuzz, SHM_FUZZ_MAP_SIZE_DEFAULT, 1,
|
||||
DEFAULT_PERMISSION, -1);
|
||||
u8 *map = afl_shm_init(shm_fuzz, MAX_FILE + sizeof(u32), 1);
|
||||
shm_fuzz->shmemfuzz_mode = 1;
|
||||
if (!map) { FATAL("BUG: Zero return from afl_shm_init."); }
|
||||
|
||||
u8 *shm_fuzz_map_size_str = alloc_printf("%zu", shm_fuzz_map_size);
|
||||
setenv(SHM_FUZZ_MAP_SIZE_ENV_VAR, shm_fuzz_map_size_str, 1);
|
||||
ck_free(shm_fuzz_map_size_str);
|
||||
|
||||
#ifdef USEMMAP
|
||||
setenv(SHM_FUZZ_ENV_VAR, shm_fuzz->g_shm_file_path, 1);
|
||||
#else
|
||||
@ -1503,8 +1547,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
afl_shm_deinit(&shm);
|
||||
afl_fsrv_kill(fsrv);
|
||||
fsrv->map_size = new_map_size;
|
||||
fsrv->trace_bits =
|
||||
afl_shm_init(&shm, new_map_size, 0, DEFAULT_PERMISSION, -1);
|
||||
fsrv->trace_bits = afl_shm_init(&shm, new_map_size, 0);
|
||||
afl_fsrv_start(fsrv, use_argv, &stop_soon,
|
||||
(get_afl_env("AFL_DEBUG_CHILD") ||
|
||||
get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
|
||||
|
@ -49,11 +49,7 @@ int main(int argc, char **argv) {
|
||||
if ((cnt = read(fd, buf, sizeof(buf) - 1)) < 1) {
|
||||
|
||||
printf("Hum?\n");
|
||||
#ifdef EXIT_AT_END
|
||||
exit(1);
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@ -81,10 +77,6 @@ int main(int argc, char **argv) {
|
||||
|
||||
}
|
||||
|
||||
#ifdef EXIT_AT_END
|
||||
exit(0);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
@ -17,9 +17,9 @@ test -z "" 2>/dev/null || { echo Error: test command not found ; exit 1 ; }
|
||||
GREP=`type grep > /dev/null 2>&1 && echo OK`
|
||||
test "$GREP" = OK || { echo Error: grep command not found ; exit 1 ; }
|
||||
echo foobar | grep -qE 'asd|oob' 2>/dev/null || { echo Error: grep command does not support -q and/or -E option ; exit 1 ; }
|
||||
test -e ./test-all.sh || cd $(dirname "$0") || exit 1
|
||||
test -e ./test-all.sh || cd $(dirname $0) || exit 1
|
||||
test -e ./test-all.sh || { echo Error: you must be in the test/ directory ; exit 1 ; }
|
||||
export AFL_PATH="$(pwd)/.."
|
||||
export AFL_PATH=`pwd`/..
|
||||
export AFL_TRY_AFFINITY=1 # workaround for travis that fails for no avail cores
|
||||
|
||||
echo 1 > test.1
|
||||
@ -59,7 +59,7 @@ $ECHO \\101 2>&1 | grep -qE '^A' || {
|
||||
$ECHO "\\101" 2>&1 | grep -qE '^A' || ECHO=
|
||||
}
|
||||
}
|
||||
test -z "$ECHO" && { echo Error: printf command does not support octal character codes ; exit 1 ; }
|
||||
test -z "$ECHO" && { printf Error: printf command does not support octal character codes ; exit 1 ; }
|
||||
|
||||
export AFL_EXIT_WHEN_DONE=1
|
||||
export AFL_EXIT_ON_TIME=60
|
||||
@ -109,10 +109,12 @@ test -n "$TRAVIS_OS_NAME" && {
|
||||
|
||||
# on OpenBSD we need to work with llvm from /usr/local/bin
|
||||
test -e /usr/local/bin/opt && {
|
||||
test "$(uname -s)" = 'Darwin' || export PATH="/usr/local/bin:${PATH}"
|
||||
test `uname -s` = 'Darwin' || export PATH="/usr/local/bin:${PATH}"
|
||||
}
|
||||
AFL_COMPILER=afl-clang-fast
|
||||
|
||||
SYS=`uname -m`
|
||||
|
||||
GREY="\\033[1;90m"
|
||||
BLUE="\\033[1;94m"
|
||||
GREEN="\\033[0;32m"
|
||||
@ -120,13 +122,6 @@ RED="\\033[0;31m"
|
||||
YELLOW="\\033[1;93m"
|
||||
RESET="\\033[0m"
|
||||
|
||||
if test -n "$CPU_TARGET"; then
|
||||
$ECHO "${RESET}${GREY}[*] Using environment variable CPU_TARGET=$CPU_TARGET for SYS"
|
||||
SYS="$CPU_TARGET"
|
||||
else
|
||||
SYS=$(uname -m)
|
||||
fi
|
||||
|
||||
MEM_LIMIT=none
|
||||
|
||||
export PATH="${PATH}:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin"
|
||||
|
@ -13,17 +13,10 @@ test -z "$AFL_CC" && {
|
||||
fi
|
||||
}
|
||||
|
||||
if test -n "$CPU_TARGET_CC"; then
|
||||
$ECHO "$GREY[*] Using $CPU_TARGET_CC as compiler for target"
|
||||
else
|
||||
CPU_TARGET_CC=cc
|
||||
fi
|
||||
|
||||
test -e ../afl-qemu-trace && {
|
||||
${CPU_TARGET_CC} -pie -fPIE -o test-instr ../test-instr.c
|
||||
${CPU_TARGET_CC} -o test-compcov test-compcov.c
|
||||
${CPU_TARGET_CC} -pie -fPIE -o test-instr-exit-at-end -DEXIT_AT_END ../test-instr.c
|
||||
test -e test-instr -a -e test-compcov -a -e test-instr-exit-at-end && {
|
||||
cc -pie -fPIE -o test-instr ../test-instr.c
|
||||
cc -o test-compcov test-compcov.c
|
||||
test -e test-instr -a -e test-compcov && {
|
||||
{
|
||||
mkdir -p in
|
||||
echo 00000 > in/in
|
||||
@ -111,7 +104,7 @@ test -e ../afl-qemu-trace && {
|
||||
$ECHO "$YELLOW[-] not an intel or arm platform, cannot test qemu_mode cmplog"
|
||||
}
|
||||
|
||||
test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" -o "$SYS" = "mipsel" && {
|
||||
test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" && {
|
||||
$ECHO "$GREY[*] running afl-fuzz for persistent qemu_mode, this will take approx 10 seconds"
|
||||
{
|
||||
IS_STATIC=""
|
||||
@ -120,16 +113,11 @@ test -e ../afl-qemu-trace && {
|
||||
if file test-instr | grep -q "32-bit"; then
|
||||
# for 32-bit reduce 8 nibbles to the lower 7 nibbles
|
||||
ADDR_LOWER_PART=`nm test-instr | grep "T main" | awk '{print $1}' | sed 's/^.//'`
|
||||
export AFL_QEMU_PERSISTENT_ADDR=`expr 0x4${ADDR_LOWER_PART}`
|
||||
elif [ "$SYS" = "aarch64" ]; then
|
||||
# for aarch64 reduce 16 nibbles to the lower 8 nibbles
|
||||
ADDR_LOWER_PART=`nm test-instr | grep "T main" | awk '{print $1}' | sed 's/^........//'`
|
||||
export AFL_QEMU_PERSISTENT_ADDR=`expr 0x55${ADDR_LOWER_PART}`
|
||||
else
|
||||
# for x64 reduce 16 nibbles to the lower 9 nibbles
|
||||
# for 64-bit reduce 16 nibbles to the lower 9 nibbles
|
||||
ADDR_LOWER_PART=`nm test-instr | grep "T main" | awk '{print $1}' | sed 's/^.......//'`
|
||||
export AFL_QEMU_PERSISTENT_ADDR=`expr 0x4${ADDR_LOWER_PART}`
|
||||
fi
|
||||
export AFL_QEMU_PERSISTENT_ADDR=`expr 0x4${ADDR_LOWER_PART}`
|
||||
}
|
||||
test -n "$IS_STATIC" && {
|
||||
export AFL_QEMU_PERSISTENT_ADDR=0x`nm test-instr | grep "T main" | awk '{print $1}'`
|
||||
@ -161,66 +149,9 @@ test -e ../afl-qemu-trace && {
|
||||
$ECHO "$RED[!] afl-fuzz is not working correctly with persistent qemu_mode"
|
||||
CODE=1
|
||||
}
|
||||
rm -rf out errors
|
||||
} || {
|
||||
$ECHO "$YELLOW[-] not an intel or arm platform, cannot test persistent qemu_mode"
|
||||
}
|
||||
|
||||
test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" -o "$SYS" = "mipsel" && {
|
||||
$ECHO "$GREY[*] running afl-fuzz for persistent qemu_mode with AFL_QEMU_PERSISTENT_EXITS, this will take approx 10 seconds"
|
||||
{
|
||||
IS_STATIC=""
|
||||
file test-instr-exit-at-end | grep -q 'statically linked' && IS_STATIC=1
|
||||
test -z "$IS_STATIC" && {
|
||||
if file test-instr-exit-at-end | grep -q "32-bit"; then
|
||||
# for 32-bit reduce 8 nibbles to the lower 7 nibbles
|
||||
ADDR_LOWER_PART=`nm test-instr-exit-at-end | grep "T main" | awk '{print $1}' | sed 's/^.//'`
|
||||
export AFL_QEMU_PERSISTENT_ADDR=`expr 0x4${ADDR_LOWER_PART}`
|
||||
elif [ "$SYS" = "aarch64" ]; then
|
||||
# for aarch64 reduce 16 nibbles to the lower 8 nibbles
|
||||
ADDR_LOWER_PART=`nm test-instr-exit-at-end | grep "T main" | awk '{print $1}' | sed 's/^........//'`
|
||||
export AFL_QEMU_PERSISTENT_ADDR=`expr 0x55${ADDR_LOWER_PART}`
|
||||
else
|
||||
# for x64 reduce 16 nibbles to the lower 9 nibbles
|
||||
ADDR_LOWER_PART=`nm test-instr-exit-at-end | grep "T main" | awk '{print $1}' | sed 's/^.......//'`
|
||||
export AFL_QEMU_PERSISTENT_ADDR=`expr 0x4${ADDR_LOWER_PART}`
|
||||
fi
|
||||
}
|
||||
test -n "$IS_STATIC" && {
|
||||
export AFL_QEMU_PERSISTENT_ADDR=0x`nm test-instr-exit-at-end | grep "T main" | awk '{print $1}'`
|
||||
}
|
||||
export AFL_QEMU_PERSISTENT_GPR=1
|
||||
$ECHO "Info: AFL_QEMU_PERSISTENT_ADDR=$AFL_QEMU_PERSISTENT_ADDR <= $(nm test-instr-exit-at-end | grep "T main" | awk '{print $1}')"
|
||||
export AFL_QEMU_PERSISTENT_EXITS=1
|
||||
../afl-fuzz -m ${MEM_LIMIT} -V07 -Q -i in -o out -- ./test-instr-exit-at-end
|
||||
echo status "$?"
|
||||
unset AFL_QEMU_PERSISTENT_ADDR
|
||||
unset AFL_QEMU_PERSISTENT_GPR
|
||||
unset AFL_QEMU_PERSISTENT_EXITS
|
||||
} >>errors 2>&1
|
||||
test -n "$( ls out/default/queue/id:000000* 2>/dev/null )" && {
|
||||
$ECHO "$GREEN[+] afl-fuzz is working correctly with persistent qemu_mode and AFL_QEMU_PERSISTENT_EXITS"
|
||||
RUNTIMEP_EXIT=`grep execs_done out/default/fuzzer_stats | awk '{print$3}'`
|
||||
test -n "$RUNTIME" -a -n "$RUNTIMEP_EXIT" && {
|
||||
DIFF=`expr $RUNTIMEP_EXIT / $RUNTIME`
|
||||
test "$DIFF" -gt 1 && { # must be at least twice as fast
|
||||
$ECHO "$GREEN[+] persistent qemu_mode with AFL_QEMU_PERSISTENT_EXITS was noticeable faster than standard qemu_mode"
|
||||
} || {
|
||||
$ECHO "$YELLOW[-] persistent qemu_mode with AFL_QEMU_PERSISTENT_EXITS was not noticeable faster than standard qemu_mode"
|
||||
}
|
||||
} || {
|
||||
$ECHO "$YELLOW[-] we got no data on executions performed? weird!"
|
||||
}
|
||||
} || {
|
||||
echo CUT------------------------------------------------------------------CUT
|
||||
cat errors
|
||||
echo CUT------------------------------------------------------------------CUT
|
||||
$ECHO "$RED[!] afl-fuzz is not working correctly with persistent qemu_mode and AFL_QEMU_PERSISTENT_EXITS"
|
||||
CODE=1
|
||||
}
|
||||
rm -rf in out errors
|
||||
} || {
|
||||
$ECHO "$YELLOW[-] not an intel or arm platform, cannot test persistent qemu_mode with AFL_QEMU_PERSISTENT_EXITS"
|
||||
$ECHO "$YELLOW[-] not an intel or arm platform, cannot test persistent qemu_mode"
|
||||
}
|
||||
|
||||
test -e ../qemu_mode/unsigaction/unsigaction32.so && {
|
||||
@ -281,7 +212,7 @@ test -e ../afl-qemu-trace && {
|
||||
CODE=1
|
||||
}
|
||||
|
||||
rm -f test-instr test-compcov test-instr-exit-at-end
|
||||
rm -f test-instr test-compcov
|
||||
} || {
|
||||
$ECHO "$YELLOW[-] qemu_mode is not compiled, cannot test"
|
||||
INCOMPLETE=1
|
||||
|
@ -10,7 +10,7 @@ test -s ../unicorn_mode/unicornafl/build/libunicornafl.a && {
|
||||
export AFL_DEBUG_CHILD=1
|
||||
|
||||
# some python version should be available now
|
||||
PYTHONS="`command -v python3` `command -v python`"
|
||||
PYTHONS="`command -v python3` `command -v python` `command -v python2`"
|
||||
EASY_INSTALL_FOUND=0
|
||||
for PYTHON in $PYTHONS ; do
|
||||
|
||||
|
@ -65,7 +65,7 @@ if [ ! -f "../afl-showmap" ]; then
|
||||
|
||||
fi
|
||||
|
||||
PYTHONBIN=`command -v python3 || command -v python || echo python3`
|
||||
PYTHONBIN=`command -v python3 || command -v python || command -v python2 || echo python3`
|
||||
MAKECMD=make
|
||||
TARCMD=tar
|
||||
|
||||
@ -116,7 +116,7 @@ for i in $PYTHONBIN automake autoconf git $MAKECMD $TARCMD; do
|
||||
done
|
||||
|
||||
# some python version should be available now
|
||||
PYTHONS="`command -v python3` `command -v python`"
|
||||
PYTHONS="`command -v python3` `command -v python` `command -v python2`"
|
||||
PIP_FOUND=0
|
||||
for PYTHON in $PYTHONS ; do
|
||||
|
||||
|
@ -179,17 +179,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
|
||||
|
||||
unlink(out_file);
|
||||
|
||||
fsrv->out_fd = open(out_file, O_RDWR | O_CREAT | O_EXCL, fsrv->perm);
|
||||
|
||||
if (fsrv->chown_needed) {
|
||||
|
||||
if (fchown(fsrv->out_fd, -1, fsrv->gid) == -1) {
|
||||
|
||||
PFATAL("fchown() failed");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
fsrv->out_fd = open(out_file, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||
|
||||
if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); }
|
||||
|
||||
@ -536,8 +526,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
check_environment_vars(envp);
|
||||
|
||||
sharedmem_t shm = {0};
|
||||
fsrv->trace_bits = afl_shm_init(&shm, map_size, 0, fsrv->perm,
|
||||
fsrv->chown_needed ? fsrv->gid : -1);
|
||||
fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
|
||||
|
||||
in_data = afl_realloc((void **)&in_data, 65536);
|
||||
if (unlikely(!in_data)) { PFATAL("Alloc"); }
|
||||
|
@ -199,9 +199,9 @@ static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
|
||||
|
||||
}
|
||||
|
||||
static void __afl_end_testcase(int status) {
|
||||
static void __afl_end_testcase(void) {
|
||||
|
||||
if (!status) { status = -1; }
|
||||
int status = 0xffffff;
|
||||
|
||||
if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1);
|
||||
|
||||
@ -241,8 +241,7 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
/* report the test case is done and wait for the next */
|
||||
// set the value to XXX (need to check) to report a crash
|
||||
__afl_end_testcase(0);
|
||||
__afl_end_testcase();
|
||||
|
||||
}
|
||||
|
||||
|
@ -18,8 +18,7 @@ ifneq "" "$(LLVM_BINDIR)"
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS := -O3 -funroll-loops -g -fPIC -fno-lto
|
||||
AR ?= ar
|
||||
CFLAGS := -O3 -funroll-loops -g -fPIC
|
||||
|
||||
ifdef IOS_SDK_PATH
|
||||
CFLAGS += -isysroot $(IOS_SDK_PATH)
|
||||
@ -31,7 +30,7 @@ aflpp_driver.o: aflpp_driver.c
|
||||
-$(CC) -I. -I../../include $(CFLAGS) -c aflpp_driver.c
|
||||
|
||||
libAFLDriver.a: aflpp_driver.o
|
||||
@$(AR) rc libAFLDriver.a aflpp_driver.o
|
||||
@ar rc libAFLDriver.a aflpp_driver.o
|
||||
@cp -vf libAFLDriver.a ../../
|
||||
|
||||
debug:
|
||||
@ -39,13 +38,13 @@ debug:
|
||||
$(CC) -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c
|
||||
#$(CC) -S -emit-llvm -Wno-deprecated -I../../include $(CFLAGS) -D_DEBUG=\"1\" -c -o afl-performance.ll ../../src/afl-performance.c
|
||||
#$(CC) -S -emit-llvm -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c
|
||||
$(AR) rc libAFLDriver.a afl-performance.o aflpp_driver.o
|
||||
ar rc libAFLDriver.a afl-performance.o aflpp_driver.o
|
||||
|
||||
aflpp_qemu_driver.o: aflpp_qemu_driver.c
|
||||
-$(CC) $(CFLAGS) -O0 -funroll-loops -c aflpp_qemu_driver.c
|
||||
|
||||
libAFLQemuDriver.a: aflpp_qemu_driver.o
|
||||
@-$(AR) rc libAFLQemuDriver.a aflpp_qemu_driver.o
|
||||
@-ar rc libAFLQemuDriver.a aflpp_qemu_driver.o
|
||||
@-cp -vf libAFLQemuDriver.a ../../
|
||||
|
||||
aflpp_qemu_driver_hook.so: aflpp_qemu_driver_hook.o
|
||||
|
@ -64,15 +64,6 @@ extern "C" {
|
||||
#include "hash.h"
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
#define SECTION_RODATA \
|
||||
__attribute__((used, retain)) __attribute__((section("__RODATA,__" \
|
||||
"rodata")))
|
||||
#else
|
||||
#define SECTION_RODATA \
|
||||
__attribute__((used, retain)) __attribute__((section(".rodata")))
|
||||
#endif
|
||||
|
||||
// AFL++ shared memory fuzz cases
|
||||
int __afl_sharedmem_fuzzing = 1;
|
||||
extern unsigned int *__afl_fuzz_len;
|
||||
@ -115,11 +106,14 @@ __attribute__((weak)) void __asan_unpoison_memory_region(
|
||||
__attribute__((weak)) void *__asan_region_is_poisoned(void *beg, size_t size);
|
||||
|
||||
// Notify AFL about persistent mode.
|
||||
SECTION_RODATA static const char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
|
||||
int __afl_persistent_loop(unsigned int);
|
||||
__attribute__((section(".rodata"), used,
|
||||
retain)) static const char AFL_PERSISTENT[] =
|
||||
"##SIG_AFL_PERSISTENT##";
|
||||
int __afl_persistent_loop(unsigned int);
|
||||
|
||||
// Notify AFL about deferred forkserver.
|
||||
SECTION_RODATA static const char AFL_DEFER_FORKSVR[] =
|
||||
__attribute__((section(".rodata"), used,
|
||||
retain)) static const char AFL_DEFER_FORKSVR[] =
|
||||
"##SIG_AFL_DEFER_FORKSRV##";
|
||||
void __afl_manual_init();
|
||||
|
||||
|
@ -33,7 +33,7 @@ def ensure_dir(dir):
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(
|
||||
description=(
|
||||
"Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python3 thisfile.py outdir str.txt"
|
||||
"Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt"
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -17,7 +17,7 @@ from binascii import unhexlify
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(
|
||||
description=(
|
||||
"Helper - Specify input file to analysis and output folder to save corpdirus for constants in the overall project ------- Example usage : python3 thisfile.py outdir o.txt"
|
||||
"Helper - Specify input file to analysis and output folder to save corpdirus for constants in the overall project ------- Example usage : python2 thisfile.py outdir o.txt"
|
||||
)
|
||||
)
|
||||
parser.add_argument(
|
||||
@ -25,7 +25,7 @@ def parse_args():
|
||||
)
|
||||
parser.add_argument(
|
||||
"infile",
|
||||
help="Specify file output of codeql analysis - ex. ooo-hex.txt, analysis take place on this file, example : python3 thisfile.py outdir out.txt",
|
||||
help="Specify file output of codeql analysis - ex. ooo-hex.txt, analysis take place on this file, example : python2 thisfile.py outdir out.txt",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
@ -25,7 +25,7 @@ def ensure_dir(dir):
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(
|
||||
description=(
|
||||
"Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python3 thisfile.py outdir str.txt"
|
||||
"Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt"
|
||||
)
|
||||
)
|
||||
parser.add_argument(
|
||||
@ -33,7 +33,7 @@ def parse_args():
|
||||
)
|
||||
parser.add_argument(
|
||||
"infile",
|
||||
help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python3 thisfile.py outdir strings.txt",
|
||||
help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt",
|
||||
)
|
||||
|
||||
return parser.parse_args()
|
||||
|
@ -25,7 +25,7 @@ def ensure_dir(dir):
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(
|
||||
description=(
|
||||
"Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python3 thisfile.py outdir str.txt"
|
||||
"Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt"
|
||||
)
|
||||
)
|
||||
parser.add_argument(
|
||||
@ -33,7 +33,7 @@ def parse_args():
|
||||
)
|
||||
parser.add_argument(
|
||||
"infile",
|
||||
help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python3 thisfile.py outdir strings.txt",
|
||||
help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt",
|
||||
)
|
||||
|
||||
return parser.parse_args()
|
||||
|
@ -25,7 +25,7 @@ def ensure_dir(dir):
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(
|
||||
description=(
|
||||
"Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python3 thisfile.py outdir str.txt"
|
||||
"Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt"
|
||||
)
|
||||
)
|
||||
parser.add_argument(
|
||||
@ -33,7 +33,7 @@ def parse_args():
|
||||
)
|
||||
parser.add_argument(
|
||||
"infile",
|
||||
help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python3 thisfile.py outdir strings.txt",
|
||||
help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt",
|
||||
)
|
||||
|
||||
return parser.parse_args()
|
||||
|
@ -25,7 +25,7 @@ def ensure_dir(dir):
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(
|
||||
description=(
|
||||
"Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python3 thisfile.py outdir str.txt"
|
||||
"Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt"
|
||||
)
|
||||
)
|
||||
parser.add_argument(
|
||||
@ -33,7 +33,7 @@ def parse_args():
|
||||
)
|
||||
parser.add_argument(
|
||||
"infile",
|
||||
help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python3 thisfile.py outdir strings.txt",
|
||||
help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt",
|
||||
)
|
||||
|
||||
return parser.parse_args()
|
||||
|
@ -1,12 +0,0 @@
|
||||
|
||||
# For cross compilation modify this as needed
|
||||
#GLIBC_PATH := /path/to/glibc-2.xx/build/local_install
|
||||
#CROSS_CFLAGS := -mfloat-abi=soft -nostdlib -I$(GLIBC_PATH)/include -L$(GLIBC_PATH)/lib -Wl,-rpath=/lib -Wl,--dynamic-linker=/lib/ld-linux.so.3
|
||||
|
||||
all: libaflppdesock.so
|
||||
|
||||
libaflppdesock.so: libaflppdesock.c
|
||||
$(CC) $(CROSS_CFLAGS) -shared -fPIC -o libaflppdesock.so libaflppdesock.c
|
||||
|
||||
clean:
|
||||
rm -f libaflppdesock.so *~ core
|
@ -1,46 +0,0 @@
|
||||
# AFL++ TCP desocket library
|
||||
|
||||
Other desocketing solutions:
|
||||
* https://github.com/zardus/preeny (desock and desock2)
|
||||
* https://github.com/fkie-cad/libdesock
|
||||
* https://github.com/zyingp/desockmulti
|
||||
* https://github.com/vanhauser-thc/network-emulator
|
||||
|
||||
If these desocket solutions fail, then this one will likely easily work
|
||||
for you - alass with slightly lower performance.
|
||||
And it is easy to extend :-)
|
||||
|
||||
## Why might this solution work when others do not?
|
||||
|
||||
What makes this desocket library special is that only **only** intercepts
|
||||
`accept()` calls bound to a specified port. Hence any other network stuff
|
||||
the application does is still working as expected.
|
||||
|
||||
## How to use
|
||||
|
||||
`AFL_PRELOAD` this library and use the following environment variables:
|
||||
|
||||
* `DESOCK_PORT=8080` - required for intercepting incoming connections for fuzzing - sets the TCP port
|
||||
* `DESOCK_FORK=1` - intercept and prevent forking
|
||||
* `DESOCK_CLOSE_EXIT=1` - call _exit() when the desocketed file descriptor is `close`d or `shutdown`ed
|
||||
* `DESOCK_DEBUG=1` - print debug information to `stderr`
|
||||
|
||||
** Internals
|
||||
|
||||
Currently the library intercepts the following calls:
|
||||
|
||||
```
|
||||
shutdown
|
||||
close
|
||||
fork
|
||||
accept
|
||||
accept4
|
||||
listen
|
||||
bind
|
||||
setsockopt
|
||||
getsockopt
|
||||
getpeername
|
||||
getsockname
|
||||
```
|
||||
|
||||
`
|
@ -1,352 +0,0 @@
|
||||
/* desocket library by Marc "vanHauser" Heuse <vh@thc.org>
|
||||
*
|
||||
* Use this library for fuzzing if preeny's desock and desock2 solutions
|
||||
* do not work for you - these would provide faster performance.
|
||||
*
|
||||
*/
|
||||
|
||||
// default: file descriptor 0 for stdin
|
||||
#define FUZZ_INPUT_FD 0
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void *handle;
|
||||
static bool do_fork, do_close, debug, running;
|
||||
static int port = -1;
|
||||
static int listen_fd = -1;
|
||||
|
||||
struct myin_addr {
|
||||
|
||||
unsigned int s_addr; // IPv4 address in network byte order
|
||||
|
||||
};
|
||||
|
||||
struct mysockaddr {
|
||||
|
||||
unsigned short int sin_family; // Address family: AF_INET
|
||||
unsigned short int sin_port; // Port number (network byte order)
|
||||
struct myin_addr sin_addr; // Internet address
|
||||
char sin_zero[8]; // Padding (unused)
|
||||
|
||||
};
|
||||
|
||||
#define RTLD_LAZY 0x00001
|
||||
|
||||
unsigned short int htons(unsigned short int hostshort) {
|
||||
|
||||
return (hostshort << 8) | (hostshort >> 8);
|
||||
|
||||
}
|
||||
|
||||
static void __get_handle() {
|
||||
|
||||
if (!(handle = dlopen("libc.so", RTLD_NOW))) {
|
||||
|
||||
if (!(handle = dlopen("libc.so.6", RTLD_NOW))) {
|
||||
|
||||
if (!(handle = dlopen("libc-orig.so", RTLD_LAZY))) {
|
||||
|
||||
if (!(handle = dlopen("cygwin1.dll", RTLD_LAZY))) {
|
||||
|
||||
if (!(handle = dlopen("libc.so", RTLD_NOW))) {
|
||||
|
||||
fprintf(stderr, "DESOCK: can not find libc!\n");
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (getenv("DESOCK_DEBUG")) { debug = true; }
|
||||
if (getenv("DESOCK_PORT")) { port = atoi(getenv("DESOCK_PORT")); }
|
||||
if (getenv("DESOCK_FORK")) { do_fork = true; }
|
||||
if (getenv("DESOCK_CLOSE_EXIT")) { do_close = true; }
|
||||
if (debug) fprintf(stderr, "DESOCK: initialized!\n");
|
||||
|
||||
}
|
||||
|
||||
int (*o_shutdown)(int socket, int how);
|
||||
int shutdown(int socket, int how) {
|
||||
|
||||
if (port != -1 && socket == FUZZ_INPUT_FD && running) {
|
||||
|
||||
running = false;
|
||||
if (do_close) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: exiting\n");
|
||||
_exit(0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (port == -1 && do_close) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: exiting\n");
|
||||
_exit(0);
|
||||
|
||||
}
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_shutdown) { o_shutdown = dlsym(handle, "shutdown"); }
|
||||
return o_shutdown(socket, how);
|
||||
|
||||
}
|
||||
|
||||
int (*o_close)(int socket);
|
||||
int close(int socket) {
|
||||
|
||||
if (port != -1 && socket == FUZZ_INPUT_FD && running) {
|
||||
|
||||
running = false;
|
||||
if (do_close) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: exiting\n");
|
||||
_exit(0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (listen_fd != -1 && socket == listen_fd) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: close bind\n");
|
||||
listen_fd = -1;
|
||||
|
||||
}
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_close) { o_close = dlsym(handle, "close"); }
|
||||
return o_close(socket);
|
||||
|
||||
}
|
||||
|
||||
int (*o_fork)(void);
|
||||
int fork() {
|
||||
|
||||
if (do_fork) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: fake fork\n");
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_fork) { o_fork = dlsym(handle, "fork"); }
|
||||
return o_fork();
|
||||
|
||||
}
|
||||
|
||||
int (*o_accept)(int sockfd, struct mysockaddr *addr,
|
||||
unsigned long int *addrlen);
|
||||
int accept(int sockfd, struct mysockaddr *addr, unsigned long int *addrlen) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_accept) { o_accept = dlsym(handle, "accept"); }
|
||||
if (!running && sockfd == listen_fd) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: intercepted accept on %d\n", sockfd);
|
||||
if (addr && addrlen) {
|
||||
|
||||
// we need to fill this!
|
||||
memset(addr, 0, *addrlen);
|
||||
addr->sin_family = 2; // AF_INET
|
||||
addr->sin_port = htons(1023); // Port 1023 in network byte order
|
||||
addr->sin_addr.s_addr = 0x0100007f;
|
||||
|
||||
}
|
||||
|
||||
running = true;
|
||||
return FUZZ_INPUT_FD;
|
||||
|
||||
}
|
||||
|
||||
return o_accept(sockfd, addr, addrlen);
|
||||
|
||||
}
|
||||
|
||||
int accept4(int sockfd, struct mysockaddr *addr, unsigned long int *addrlen,
|
||||
int flags) {
|
||||
|
||||
return accept(sockfd, addr, addrlen); // ignore flags
|
||||
|
||||
}
|
||||
|
||||
int (*o_listen)(int sockfd, int backlog);
|
||||
int listen(int sockfd, int backlog) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_listen) { o_listen = dlsym(handle, "listen"); }
|
||||
if (sockfd == listen_fd) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: intercepted listen on %d\n", sockfd);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return o_listen(sockfd, backlog);
|
||||
|
||||
}
|
||||
|
||||
int (*o_bind)(int sockfd, const struct mysockaddr *addr,
|
||||
unsigned long int addrlen);
|
||||
int bind(int sockfd, const struct mysockaddr *addr, unsigned long int addrlen) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_bind) { o_bind = dlsym(handle, "bind"); }
|
||||
if (addr->sin_port == htons(port)) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: intercepted bind on %d\n", sockfd);
|
||||
listen_fd = sockfd;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return o_bind(sockfd, addr, addrlen);
|
||||
|
||||
}
|
||||
|
||||
int (*o_setsockopt)(int sockfd, int level, int optname, const void *optval,
|
||||
unsigned long int optlen);
|
||||
int setsockopt(int sockfd, int level, int optname, const void *optval,
|
||||
unsigned long int optlen) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_setsockopt) { o_setsockopt = dlsym(handle, "setsockopt"); }
|
||||
if (listen_fd == sockfd) {
|
||||
|
||||
if (debug)
|
||||
fprintf(stderr, "DESOCK: intercepted setsockopt on %d for %d\n", sockfd,
|
||||
optname);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return o_setsockopt(sockfd, level, optname, optval, optlen);
|
||||
|
||||
}
|
||||
|
||||
int (*o_getsockopt)(int sockfd, int level, int optname, void *optval,
|
||||
unsigned long int *optlen);
|
||||
int getsockopt(int sockfd, int level, int optname, void *optval,
|
||||
unsigned long int *optlen) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_getsockopt) { o_getsockopt = dlsym(handle, "getsockopt"); }
|
||||
if (listen_fd == sockfd) {
|
||||
|
||||
if (debug)
|
||||
fprintf(stderr, "DESOCK: intercepted getsockopt on %d for %d\n", sockfd,
|
||||
optname);
|
||||
int *o = (int *)optval;
|
||||
if (o != NULL) {
|
||||
|
||||
*o = 1; // let's hope this is fine
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return o_getsockopt(sockfd, level, optname, optval, optlen);
|
||||
|
||||
}
|
||||
|
||||
int (*o_getpeername)(int sockfd, struct mysockaddr *addr,
|
||||
unsigned long int *addrlen);
|
||||
int getpeername(int sockfd, struct mysockaddr *addr,
|
||||
unsigned long int *addrlen) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_getpeername) { o_getpeername = dlsym(handle, "getpeername"); }
|
||||
if (port != -1 && sockfd == FUZZ_INPUT_FD) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: getpeername\n");
|
||||
if (addr && addrlen) {
|
||||
|
||||
// we need to fill this!
|
||||
memset(addr, 0, *addrlen);
|
||||
addr->sin_family = 2; // AF_INET
|
||||
addr->sin_port = htons(1023); // Port 1023 in network byte order
|
||||
addr->sin_addr.s_addr = 0x0100007f;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return o_getpeername(sockfd, addr, addrlen);
|
||||
|
||||
}
|
||||
|
||||
int (*o_getsockname)(int sockfd, struct mysockaddr *addr,
|
||||
unsigned long int *addrlen);
|
||||
int getsockname(int sockfd, struct mysockaddr *addr,
|
||||
unsigned long int *addrlen) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
if (!o_getsockname) { o_getsockname = dlsym(handle, "getsockname"); }
|
||||
if (port != -1 && sockfd == FUZZ_INPUT_FD) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: getsockname\n");
|
||||
if (addr && addrlen) {
|
||||
|
||||
// we need to fill this!
|
||||
memset(addr, 0, *addrlen);
|
||||
addr->sin_family = 2; // AF_INET
|
||||
addr->sin_port = htons(port);
|
||||
addr->sin_addr.s_addr = 0x0100007f;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return o_getsockname(sockfd, addr, addrlen);
|
||||
|
||||
}
|
||||
|
||||
static FILE *(*o_fdopen)(int fd, const char *mode);
|
||||
FILE *fdopen(int fd, const char *mode) {
|
||||
|
||||
if (!o_fdopen) {
|
||||
|
||||
if (!handle) { __get_handle(); }
|
||||
|
||||
o_fdopen = dlsym(handle, "fdopen");
|
||||
if (!o_fdopen) {
|
||||
|
||||
fprintf(stderr, "%s(): can not find fdopen\n", dlerror());
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (fd == FUZZ_INPUT_FD && strcmp(mode, "r") != 0) {
|
||||
|
||||
if (debug) fprintf(stderr, "DESOCK: intercepted fdopen(r+) for %d\n", fd);
|
||||
return o_fdopen(fd, "r");
|
||||
|
||||
}
|
||||
|
||||
return o_fdopen(fd, mode);
|
||||
|
||||
}
|
||||
|
||||
/* TARGET SPECIFIC HOOKS - put extra needed code for your target here */
|
||||
|
@ -19,11 +19,11 @@ HELPER_PATH = $(PREFIX)/lib/afl
|
||||
VERSION = $(shell grep '^\#define VERSION ' ../../config.h | cut -d '"' -f2)
|
||||
|
||||
CFLAGS ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2
|
||||
override CFLAGS += -I ../../include/ -Wall -g -Wno-pointer-sign
|
||||
CFLAGS += -I ../../include/ -Wall -g -Wno-pointer-sign
|
||||
|
||||
CFLAGS_ADD=$(USEHUGEPAGE:1=-DUSEHUGEPAGE)
|
||||
CFLAGS_ADD += $(USENAMEDPAGE:1=-DUSENAMEDPAGE)
|
||||
override CFLAGS += $(CFLAGS_ADD)
|
||||
CFLAGS += $(CFLAGS_ADD)
|
||||
|
||||
all: libdislocator.so
|
||||
|
||||
@ -41,3 +41,4 @@ install: all
|
||||
install -m 755 -d $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 755 ../../libdislocator.so $${DESTDIR}$(HELPER_PATH)
|
||||
install -m 644 -T README.md $${DESTDIR}$(HELPER_PATH)/README.dislocator.md
|
||||
|
||||
|
@ -2,9 +2,5 @@ all:
|
||||
$(CC) -no-pie test.c -o test
|
||||
$(CC) -fPIC -shared read_into_rdi.c -o read_into_rdi.so
|
||||
|
||||
all_mipsel: test.c mipsel_read_into_a0.c
|
||||
$(CPU_TARGET_CC) -no-pie test.c -o mipsel_test
|
||||
$(CC) -fPIC -shared mipsel_read_into_a0.c -o mipsel_read_into_a0.so
|
||||
|
||||
clean:
|
||||
rm -rf in out test read_into_rdi.so mipsel_test mipsel_read_into_a0.so
|
||||
rm -rf in out test read_into_rdi.so
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user