From 5d6d52daf3be8f49ff6a0699f565b20e4f1b63e9 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Thu, 14 Nov 2019 21:55:35 -0500 Subject: [PATCH] Port AFL stuff from zcash upstream --- zcutil/afl/afl-build.sh | 19 ++++++++++++++ zcutil/afl/afl-get.sh | 33 ++++++++++++++++++++++++ zcutil/afl/afl-getbuildrun.sh | 20 +++++++++++++++ zcutil/afl/afl-run.sh | 9 +++++++ zcutil/afl/hush-wrapper | 48 +++++++++++++++++++++++++++++++++++ zcutil/afl/hush-wrapper-g++ | 1 + zcutil/afl/hush-wrapper-gcc | 1 + 7 files changed, 131 insertions(+) create mode 100755 zcutil/afl/afl-build.sh create mode 100755 zcutil/afl/afl-get.sh create mode 100755 zcutil/afl/afl-getbuildrun.sh create mode 100755 zcutil/afl/afl-run.sh create mode 100755 zcutil/afl/hush-wrapper create mode 120000 zcutil/afl/hush-wrapper-g++ create mode 120000 zcutil/afl/hush-wrapper-gcc diff --git a/zcutil/afl/afl-build.sh b/zcutil/afl/afl-build.sh new file mode 100755 index 000000000..912d285b5 --- /dev/null +++ b/zcutil/afl/afl-build.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +# A wrapper around ./zcutil/build.sh for instrumenting the build with AFL: +# ./zcutil/afl/afl-build.sh +# You may obtain a copy of AFL using ./zcutil/afl/afl-get.sh. + +set -eu -o pipefail + +export AFL_INSTALL_DIR=$(realpath "$1") +FUZZ_CASE="$2" +shift 2 +export AFL_LOG_DIR="$(pwd)" +export ZCUTIL=$(realpath "./zcutil") + +cp "./src/fuzzing/$FUZZ_CASE/fuzz.cpp" src/fuzz.cpp + +CONFIGURE_FLAGS="--enable-tests=no --enable-fuzz-main" "$ZCUTIL/build.sh" "CC=$ZCUTIL/afl/zcash-wrapper-gcc" "CXX=$ZCUTIL/afl/zcash-wrapper-g++" AFL_HARDEN=1 "$@" + +echo "You can now run AFL as follows:" +echo "$ ./zcutil/afl/afl-run.sh '$AFL_INSTALL_DIR' '$FUZZ_CASE'" diff --git a/zcutil/afl/afl-get.sh b/zcutil/afl/afl-get.sh new file mode 100755 index 000000000..641536f07 --- /dev/null +++ b/zcutil/afl/afl-get.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# Obtains and builds a copy of AFL from source. +# ./zcutil/afl/afl-get.sh + +set -eu -o pipefail + +mkdir -p "$1" +cd "$1" + +if [ ! -z "$(ls -A .)" ]; then + echo "$1 is not empty. This script will only attempt to build AFL in an empty directory." + exit 1 +fi + +# Get the AFL source +rm -f afl-latest.tgz +wget http://lcamtuf.coredump.cx/afl/releases/afl-latest.tgz +sha256sum afl-latest.tgz | grep '43614b4b91c014d39ef086c5cc84ff5f068010c264c2c05bf199df60898ce045' +if [ "$?" != "0" ] +then + echo "Wrong SHA256 hash for afl" + exit +fi +tar xvf afl-latest.tgz +mv afl-*/* . + +# Build AFL +make + +echo "You can now build zcashd with AFL instrumentation as follows:" +echo "$ make clean # if you've already built zcashd without AFL instrumentation" +echo "$ ./zcutil/afl/afl-build.sh '$(pwd)' -j\$(nproc)" +echo "...where is the name of a directory in src/fuzzing." diff --git a/zcutil/afl/afl-getbuildrun.sh b/zcutil/afl/afl-getbuildrun.sh new file mode 100755 index 000000000..1af352fce --- /dev/null +++ b/zcutil/afl/afl-getbuildrun.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# Builds AFL and an instrumented zcashd, then begins fuzzing. +# This script must be run from within the top level directory of a zcash clone. +# Pass it the name of a directory in ./src/fuzzing. +# Additional arguments are passed-through to AFL. + +set -eu -o pipefail + +FUZZ_CASE="$1" +shift 1 + +export AFL_INSTALL_DIR=$(realpath "./afl-temp") + +if [ ! -d "$AFL_INSTALL_DIR" ]; then + mkdir "$AFL_INSTALL_DIR" + ./zcutil/afl/afl-get.sh "$AFL_INSTALL_DIR" +fi + +./zcutil/afl/afl-build.sh "$AFL_INSTALL_DIR" "$FUZZ_CASE" -j$(nproc) +./zcutil/afl/afl-run.sh "$AFL_INSTALL_DIR" "$FUZZ_CASE" "$@" diff --git a/zcutil/afl/afl-run.sh b/zcutil/afl/afl-run.sh new file mode 100755 index 000000000..245997563 --- /dev/null +++ b/zcutil/afl/afl-run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +set -eu -o pipefail + +AFL_INSTALL_DIR="$1" +FUZZ_CASE="$2" +shift 2 + +"$AFL_INSTALL_DIR/afl-fuzz" -i "./src/fuzzing/$FUZZ_CASE/input" -o "./src/fuzzing/$FUZZ_CASE/output" "$@" ./src/zcashd @@ diff --git a/zcutil/afl/hush-wrapper b/zcutil/afl/hush-wrapper new file mode 100755 index 000000000..d316cae74 --- /dev/null +++ b/zcutil/afl/hush-wrapper @@ -0,0 +1,48 @@ +#!/usr/bin/env bash + +set -ex -o pipefail + +export ARGS=$@ + +instrument=( +"\/src$" + +) + +if [ "$override_instrument" != "" ] +then + instrument = $override_instrument +fi + +# Store the command line we were given to a file + +(echo "$ARGS" ; pwd) >> "$AFL_LOG_DIR/hush-build-wrapper.log" + +# Work out which compiler we were called as + +case $0 in +*hush-wrapper-g++) + COMPILER="g++" + ;; +*hush-wrapper-gcc) + COMPILER="gcc" + ;; +*hush-wrapper) + echo "Call this script instead of your regular compiler, and if the absolute path of the CWD the wrapper was called from matches a regex in the array 'instrument', it will call AFL to instrument the resulting binary. Otherwise it will call either g++ or gcc depending on how it was invoked. \$AFL_INSTALL_DIR must be set to the path where AFL is installed." + exit + ;; +esac + +# Check if we should instrument + +for i in "${instrument[@]}" +do + if echo -- "`pwd`" | grep "$i"; then + # We found a match, let's instrument this one. + echo "Matched directory `pwd` to instrument element $i. Instrumenting this call." >> "$AFL_LOG_DIR/hush-build-wrapper.log" + exec -- "$AFL_INSTALL_DIR/afl-$COMPILER" "$@" + fi +done + +# No match, just pass-through. +exec -- "$COMPILER" "$@" diff --git a/zcutil/afl/hush-wrapper-g++ b/zcutil/afl/hush-wrapper-g++ new file mode 120000 index 000000000..4a7bb9c2e --- /dev/null +++ b/zcutil/afl/hush-wrapper-g++ @@ -0,0 +1 @@ +hush-wrapper \ No newline at end of file diff --git a/zcutil/afl/hush-wrapper-gcc b/zcutil/afl/hush-wrapper-gcc new file mode 120000 index 000000000..4a7bb9c2e --- /dev/null +++ b/zcutil/afl/hush-wrapper-gcc @@ -0,0 +1 @@ +hush-wrapper \ No newline at end of file