diff --git a/src/main.cpp b/src/main.cpp index f1beaa2c7..7e98bfb62 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1774,8 +1774,9 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa return error("AcceptToMemoryPool: CheckTransaction failed"); } // DoS level set to 10 to be more forgiving. + // Check transaction contextually against the set of consensus rules which apply in the next block to be mined. - if (!fSkipExpiry && !ContextualCheckTransaction(0,0,0,tx, state, nextBlockHeight, (dosLevel == -1) ? 10 : dosLevel,0)) + if (!fSkipExpiry && !ContextualCheckTransaction(0,0,0,tx, state, nextBlockHeight, (dosLevel == -1) ? 10 : dosLevel)) { return error("AcceptToMemoryPool: ContextualCheckTransaction failed"); } diff --git a/src/netbase.cpp b/src/netbase.cpp index 5ad6353e9..b118446b9 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -267,7 +267,7 @@ struct timeval MillisToTimeval(int64_t nTimeout) * * @note This function requires that hSocket is in non-blocking mode. */ -bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSocket) +bool static InterruptibleRecv(uint8_t* data, size_t len, int timeout, SOCKET& hSocket) { int64_t curTime = GetTimeMillis(); int64_t endTime = curTime + timeout; @@ -335,7 +335,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials CloseSocket(hSocket); return error("Error sending to proxy"); } - char pchRet1[2]; + uint8_t pchRet1[2]; if (!InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) { CloseSocket(hSocket); return error("Error reading proxy response"); @@ -360,7 +360,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials return error("Error sending authentication to proxy"); } LogPrint("proxy", "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password); - char pchRetA[2]; + uint8_t pchRetA[2]; if (!InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) { CloseSocket(hSocket); return error("Error reading proxy authentication response"); @@ -389,7 +389,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials CloseSocket(hSocket); return error("Error sending to proxy"); } - char pchRet2[4]; + uint8_t pchRet2[4]; if (!InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) { CloseSocket(hSocket); return error("Error reading proxy response"); @@ -417,7 +417,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials CloseSocket(hSocket); return error("Error: malformed proxy response"); } - char pchRet3[256]; + uint8_t pchRet3[256]; switch (pchRet2[3]) { case 0x01: ret = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break; @@ -429,7 +429,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials CloseSocket(hSocket); return error("Error reading from proxy"); } - int nRecv = pchRet3[0]; + size_t nRecv = pchRet3[0]; ret = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, hSocket); break; } 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