Auto merge of #4547 - zebambam:add_libfuzzer_support, r=str4d
Add libfuzzer support - Added libfuzzer support to the build system in zcutil. - Added UniValue::Read fuzzer, dict, corpus. I made a slight change to the build.sh script so as to separate dependency building vs src building, just so that I can layer the docker containers for building over in another repo to speed up the continuous build processes that will want to build multiple fuzzers from the same commit. Closes #4548
This commit is contained in:
commit
9e117fdebe
|
@ -2,11 +2,43 @@
|
||||||
#include "chainparams.h"
|
#include "chainparams.h"
|
||||||
#include "proof_verifier.h"
|
#include "proof_verifier.h"
|
||||||
|
|
||||||
int main (int argc, char *argv[]) {
|
extern bool CheckBlock(
|
||||||
|
const CBlock& block,
|
||||||
|
CValidationState& state,
|
||||||
|
const CChainParams& chainparams,
|
||||||
|
libzcash::ProofVerifier& verifier,
|
||||||
|
bool fCheckPOW = true,
|
||||||
|
bool fCheckMerkleRoot = true);
|
||||||
|
|
||||||
|
bool init_done = false;
|
||||||
|
|
||||||
|
const CChainParams& chainparams = NULL;
|
||||||
|
auto verifier = libzcash::ProofVerifier::Strict();
|
||||||
|
|
||||||
|
|
||||||
|
int fuzz_CheckBlock(CBlock block) {
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
|
if (!init_done) {
|
||||||
SelectParams(CBaseChainParams::MAIN);
|
SelectParams(CBaseChainParams::MAIN);
|
||||||
|
chainparams = Params()
|
||||||
|
init_done = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CValidationState state;
|
||||||
|
|
||||||
|
// We don't check the PoW or Merkle tree root in order to reach more code.
|
||||||
|
|
||||||
|
if (!CheckBlock(block, state, chainparams, verifier, false, false)) {
|
||||||
|
retval = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef FUZZ_WITH_AFL
|
||||||
|
|
||||||
|
int main (int argc, char *argv[]) {
|
||||||
CBlock block;
|
CBlock block;
|
||||||
CAutoFile filein(fopen(argv[1], "rb"), SER_DISK, CLIENT_VERSION);
|
CAutoFile filein(fopen(argv[1], "rb"), SER_DISK, CLIENT_VERSION);
|
||||||
try {
|
try {
|
||||||
|
@ -14,17 +46,22 @@ int main (int argc, char *argv[]) {
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
return fuzz_CheckBlock(block);
|
||||||
// We don't load the SNARK parameters because it's too slow. This means that
|
|
||||||
// valid blocks with shielded transactions will generate a crash.
|
|
||||||
|
|
||||||
const CChainParams& chainparams = Params();
|
|
||||||
auto verifier = ProofVerifier::Disabled();
|
|
||||||
CValidationState state;
|
|
||||||
// We don't check the PoW or Merkle tree root in order to reach more code.
|
|
||||||
if (!CheckBlock(block, state, chainparams, verifier, false, false)) {
|
|
||||||
retval = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // FUZZ_WITH_AFL
|
||||||
|
#ifdef FUZZ_WITH_LIBFUZZER
|
||||||
|
|
||||||
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||||
|
CBlock block;
|
||||||
|
CDataStream ds((const char *)Data, (const char *)Data+Size, SER_NETWORK, PROTOCOL_VERSION);
|
||||||
|
try {
|
||||||
|
ds >> block;
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fuzz_CheckBlock(block);
|
||||||
|
return 0; // Non-zero return values are reserved for future use.
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,10 +1,18 @@
|
||||||
|
#include <bits/stdc++.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
extern bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx);
|
extern bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx);
|
||||||
|
|
||||||
|
// actual fuzzer
|
||||||
|
|
||||||
bool fuzz_DecodeHexTxFunction (const std::string& strHexTx) {
|
bool fuzz_DecodeHexTxFunction (const std::string& strHexTx) {
|
||||||
CTransaction tx;
|
CTransaction tx;
|
||||||
return DecodeHexTx(tx, strHexTx);
|
return DecodeHexTx(tx, strHexTx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef FUZZ_WITH_AFL
|
||||||
|
|
||||||
|
// AFL
|
||||||
|
|
||||||
int fuzz_DecodeHexTx (int argc, char *argv[]) {
|
int fuzz_DecodeHexTx (int argc, char *argv[]) {
|
||||||
std::ifstream t(argv[1]);
|
std::ifstream t(argv[1]);
|
||||||
|
@ -15,3 +23,17 @@ int fuzz_DecodeHexTx (int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int main (int argc, char *argv[]) { return fuzz_DecodeHexTx(argc, argv); }
|
int main (int argc, char *argv[]) { return fuzz_DecodeHexTx(argc, argv); }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#ifdef FUZZ_WITH_LIBFUZZER
|
||||||
|
|
||||||
|
// libfuzzer
|
||||||
|
|
||||||
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||||
|
std::string s;
|
||||||
|
s.assign((const char *)Data, Size);
|
||||||
|
fuzz_DecodeHexTxFunction (s);
|
||||||
|
return 0; // Non-zero return values are reserved for future use.
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
#include "addrman.h"
|
#include "addrman.h"
|
||||||
#include "streams.h"
|
#include "streams.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef FUZZ_WITH_AFL
|
||||||
|
|
||||||
int main (int argc, char *argv[]) {
|
int main (int argc, char *argv[]) {
|
||||||
CAddrMan addrman;
|
CAddrMan addrman;
|
||||||
CAutoFile filein(fopen(argv[1], "rb"), SER_DISK, CLIENT_VERSION);
|
CAutoFile filein(fopen(argv[1], "rb"), SER_DISK, CLIENT_VERSION);
|
||||||
|
@ -11,3 +14,20 @@ int main (int argc, char *argv[]) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef FUZZ_WITH_LIBFUZZER
|
||||||
|
|
||||||
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||||
|
CAddrMan addrman;
|
||||||
|
CDataStream ds(Data, Data+Size, SER_DISK, CLIENT_VERSION);
|
||||||
|
try {
|
||||||
|
ds >> addrman;
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 0; // Non-zero return values are reserved for future use.
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
#include <bits/stdc++.h>
|
||||||
|
|
||||||
|
// actual fuzzer
|
||||||
|
|
||||||
bool fuzz_TxDeserializeFunction (const std::vector<unsigned char> txData) {
|
bool fuzz_TxDeserializeFunction (const std::vector<unsigned char> txData) {
|
||||||
CTransaction tx;
|
CTransaction tx;
|
||||||
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
|
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
|
||||||
|
@ -9,6 +13,9 @@ bool fuzz_TxDeserializeFunction (const std::vector<unsigned char> txData) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef FUZZ_WITH_AFL
|
||||||
|
|
||||||
|
// AFL
|
||||||
|
|
||||||
int fuzz_TxDeserialize (int argc, char *argv[]) {
|
int fuzz_TxDeserialize (int argc, char *argv[]) {
|
||||||
std::ifstream t(argv[1]);
|
std::ifstream t(argv[1]);
|
||||||
|
@ -19,3 +26,18 @@ int fuzz_TxDeserialize (int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int main (int argc, char *argv[]) { return fuzz_TxDeserialize(argc, argv); }
|
int main (int argc, char *argv[]) { return fuzz_TxDeserialize(argc, argv); }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef FUZZ_WITH_LIBFUZZER
|
||||||
|
|
||||||
|
// libFuzzer
|
||||||
|
|
||||||
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||||
|
std::vector<unsigned char> vect(Size);
|
||||||
|
memcpy(vect.data(), Data, Size);
|
||||||
|
fuzz_TxDeserializeFunction(vect);
|
||||||
|
return 0; // Non-zero return values are reserved for future use.
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "txmempool.h"
|
#include "txmempool.h"
|
||||||
|
|
||||||
|
#ifdef FUZZ_WITH_AFL
|
||||||
|
|
||||||
int main (int argc, char *argv[]) {
|
int main (int argc, char *argv[]) {
|
||||||
CFeeRate rate;
|
CFeeRate rate;
|
||||||
CTxMemPool mempool(rate);
|
CTxMemPool mempool(rate);
|
||||||
|
@ -11,3 +13,22 @@ int main (int argc, char *argv[]) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef FUZZ_WITH_LIBFUZZER
|
||||||
|
|
||||||
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||||
|
CFeeRate rate;
|
||||||
|
CTxMemPool mempool(rate);
|
||||||
|
CAutoFile est_filein(fmemopen(Data, Size, "rb"), SER_DISK, CLIENT_VERSION);
|
||||||
|
|
||||||
|
if (mempool.ReadFeeEstimates(est_filein)) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
kw1="{"
|
||||||
|
kw2="}"
|
||||||
|
kw5="["
|
||||||
|
kw6="]"
|
||||||
|
kw7=":"
|
||||||
|
kw8=","
|
||||||
|
kw9="\""
|
|
@ -0,0 +1,29 @@
|
||||||
|
#include "univalue.h"
|
||||||
|
|
||||||
|
int fuzz_UniValue_Read(std::string notquitejson) {
|
||||||
|
UniValue valRequest;
|
||||||
|
if (!valRequest.read(notquitejson)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef FUZZ_WITH_AFL
|
||||||
|
|
||||||
|
#error "The AFL version of this fuzzer has not yet been implemented."
|
||||||
|
|
||||||
|
int main (int argc, char *argv[]) {
|
||||||
|
// not implemented
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FUZZ_WITH_AFL
|
||||||
|
#ifdef FUZZ_WITH_LIBFUZZER
|
||||||
|
|
||||||
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||||
|
std::string s;
|
||||||
|
s.assign((const char *)Data, Size);
|
||||||
|
return fuzz_UniValue_Read(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1 @@
|
||||||
|
"This is a string that never ends, yes it goes on and on, my friends.
|
|
@ -0,0 +1 @@
|
||||||
|
{"Extra value after close": true} "misplaced quoted value"
|
|
@ -0,0 +1 @@
|
||||||
|
{"Illegal expression": 1 + 2}
|
|
@ -0,0 +1 @@
|
||||||
|
{"Illegal invocation": alert()}
|
|
@ -0,0 +1 @@
|
||||||
|
{"Numbers cannot have leading zeroes": 013}
|
|
@ -0,0 +1 @@
|
||||||
|
{"Numbers cannot be hex": 0x14}
|
|
@ -0,0 +1 @@
|
||||||
|
["Illegal backslash escape: \x15"]
|
|
@ -0,0 +1 @@
|
||||||
|
[\naked]
|
|
@ -0,0 +1 @@
|
||||||
|
["Illegal backslash escape: \017"]
|
|
@ -0,0 +1 @@
|
||||||
|
[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]
|
|
@ -0,0 +1 @@
|
||||||
|
{"Missing colon" null}
|
|
@ -0,0 +1 @@
|
||||||
|
["Unclosed array"
|
|
@ -0,0 +1 @@
|
||||||
|
{"Double colon":: null}
|
|
@ -0,0 +1 @@
|
||||||
|
{"Comma instead of colon", null}
|
|
@ -0,0 +1 @@
|
||||||
|
["Colon instead of comma": false]
|
|
@ -0,0 +1 @@
|
||||||
|
["Bad value", truth]
|
|
@ -0,0 +1 @@
|
||||||
|
['single quote']
|
|
@ -0,0 +1 @@
|
||||||
|
[" tab character in string "]
|
|
@ -0,0 +1 @@
|
||||||
|
["tab\ character\ in\ string\ "]
|
|
@ -0,0 +1,2 @@
|
||||||
|
["line
|
||||||
|
break"]
|
|
@ -0,0 +1,2 @@
|
||||||
|
["line\
|
||||||
|
break"]
|
|
@ -0,0 +1 @@
|
||||||
|
[0e]
|
|
@ -0,0 +1 @@
|
||||||
|
{unquoted_key: "keys must be quoted"}
|
|
@ -0,0 +1 @@
|
||||||
|
[0e+]
|
|
@ -0,0 +1 @@
|
||||||
|
[0e+-1]
|
|
@ -0,0 +1 @@
|
||||||
|
{"Comma instead if closing brace": true,
|
|
@ -0,0 +1 @@
|
||||||
|
["mismatch"}
|
|
@ -0,0 +1 @@
|
||||||
|
{} garbage
|
|
@ -0,0 +1 @@
|
||||||
|
[ true true true [] [] [] ]
|
|
@ -0,0 +1 @@
|
||||||
|
{"a":}
|
|
@ -0,0 +1 @@
|
||||||
|
{"a":1 "b":2}
|
|
@ -0,0 +1 @@
|
||||||
|
["\ud834"]
|
|
@ -0,0 +1 @@
|
||||||
|
["\udd61"]
|
|
@ -0,0 +1 @@
|
||||||
|
["extra comma",]
|
|
@ -0,0 +1 @@
|
||||||
|
["揣。"]
|
|
@ -0,0 +1 @@
|
||||||
|
["<22><><EFBFBD>"]
|
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
["double extra comma",,]
|
|
@ -0,0 +1 @@
|
||||||
|
[ , "<-- missing value"]
|
|
@ -0,0 +1 @@
|
||||||
|
["Comma after the close"],
|
|
@ -0,0 +1 @@
|
||||||
|
["Extra close"]]
|
|
@ -0,0 +1 @@
|
||||||
|
{"Extra comma": true,}
|
|
@ -0,0 +1,58 @@
|
||||||
|
[
|
||||||
|
"JSON Test Pattern pass1",
|
||||||
|
{"object with 1 member":["array with 1 element"]},
|
||||||
|
{},
|
||||||
|
[],
|
||||||
|
-42,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
{
|
||||||
|
"integer": 1234567890,
|
||||||
|
"real": -9876.543210,
|
||||||
|
"e": 0.123456789e-12,
|
||||||
|
"E": 1.234567890E+34,
|
||||||
|
"": 23456789012E66,
|
||||||
|
"zero": 0,
|
||||||
|
"one": 1,
|
||||||
|
"space": " ",
|
||||||
|
"quote": "\"",
|
||||||
|
"backslash": "\\",
|
||||||
|
"controls": "\b\f\n\r\t",
|
||||||
|
"slash": "/ & \/",
|
||||||
|
"alpha": "abcdefghijklmnopqrstuvwyz",
|
||||||
|
"ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
|
||||||
|
"digit": "0123456789",
|
||||||
|
"0123456789": "digit",
|
||||||
|
"special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
|
||||||
|
"hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
|
||||||
|
"true": true,
|
||||||
|
"false": false,
|
||||||
|
"null": null,
|
||||||
|
"array":[ ],
|
||||||
|
"object":{ },
|
||||||
|
"address": "50 St. James Street",
|
||||||
|
"url": "http://www.JSON.org/",
|
||||||
|
"comment": "// /* <!-- --",
|
||||||
|
"# -- --> */": " ",
|
||||||
|
" s p a c e d " :[1,2 , 3
|
||||||
|
|
||||||
|
,
|
||||||
|
|
||||||
|
4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7],
|
||||||
|
"jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
|
||||||
|
"quotes": "" \u0022 %22 0x22 034 "",
|
||||||
|
"\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
|
||||||
|
: "A key can be any string"
|
||||||
|
},
|
||||||
|
0.5 ,98.6
|
||||||
|
,
|
||||||
|
99.44
|
||||||
|
,
|
||||||
|
|
||||||
|
1066,
|
||||||
|
1e1,
|
||||||
|
0.1e1,
|
||||||
|
1e-1,
|
||||||
|
1e00,2e+00,2e-00
|
||||||
|
,"rosebud"]
|
|
@ -0,0 +1 @@
|
||||||
|
[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"JSON Test Pattern pass3": {
|
||||||
|
"The outermost value": "must be an object or array.",
|
||||||
|
"In this test": "It is an object."
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
["\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f"]
|
|
@ -0,0 +1 @@
|
||||||
|
["a§■𐎒𝅘𝅥𝅯"]
|
|
@ -0,0 +1 @@
|
||||||
|
"abcdefghijklmnopqrstuvwxyz"
|
|
@ -0,0 +1 @@
|
||||||
|
7
|
|
@ -0,0 +1 @@
|
||||||
|
true
|
|
@ -0,0 +1 @@
|
||||||
|
false
|
|
@ -0,0 +1 @@
|
||||||
|
null
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
set -eu -o pipefail
|
set -exu -o pipefail
|
||||||
|
|
||||||
for d in src/fuzzing/*/ ; do
|
for d in src/fuzzing/*/ ; do
|
||||||
fuzz_cases+="$(basename "$d"), "
|
fuzz_cases+="$(basename "$d"), "
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
set -ex -o pipefail
|
set -ex -o pipefail
|
||||||
|
|
||||||
export ARGS=$@
|
|
||||||
|
|
||||||
instrument=(
|
instrument=(
|
||||||
"\/src$"
|
"\/src$"
|
||||||
|
@ -22,10 +21,22 @@ fi
|
||||||
|
|
||||||
case $0 in
|
case $0 in
|
||||||
*zcash-wrapper-g++)
|
*zcash-wrapper-g++)
|
||||||
COMPILER="g++"
|
OCOMPILER="g++"
|
||||||
|
ACOMPILER=$OCOMPILER
|
||||||
;;
|
;;
|
||||||
*zcash-wrapper-gcc)
|
*zcash-wrapper-gcc)
|
||||||
COMPILER="gcc"
|
OCOMPILER="gcc"
|
||||||
|
ACOMPILER=$OCOMPILER
|
||||||
|
;;
|
||||||
|
*zcash-wrapper-clang)
|
||||||
|
OCOMPILER="clang-6.0"
|
||||||
|
ACOMPILER="clang-fast"
|
||||||
|
CFLAGS="-fsanitize=address -static"
|
||||||
|
;;
|
||||||
|
*zcash-wrapper-clang++)
|
||||||
|
OCOMPILER="clang++-6.0"
|
||||||
|
ACOMPILER="clang-fast++"
|
||||||
|
CPPFLAGS="-fsanitize=address -static"
|
||||||
;;
|
;;
|
||||||
*zcash-wrapper)
|
*zcash-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."
|
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."
|
||||||
|
@ -40,9 +51,9 @@ do
|
||||||
if echo -- "`pwd`" | grep "$i"; then
|
if echo -- "`pwd`" | grep "$i"; then
|
||||||
# We found a match, let's instrument this one.
|
# We found a match, let's instrument this one.
|
||||||
echo "Matched directory `pwd` to instrument element $i. Instrumenting this call." >> "$AFL_LOG_DIR/zcash-build-wrapper.log"
|
echo "Matched directory `pwd` to instrument element $i. Instrumenting this call." >> "$AFL_LOG_DIR/zcash-build-wrapper.log"
|
||||||
exec -- "$AFL_INSTALL_DIR/afl-$COMPILER" "$@"
|
exec -- "$AFL_INSTALL_DIR/afl-$ACOMPILER" "$@"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# No match, just pass-through.
|
# No match, just pass-through.
|
||||||
exec -- "$COMPILER" "$@"
|
exec -- "$OCOMPILER" "$@"
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
zcash-wrapper
|
|
@ -0,0 +1 @@
|
||||||
|
zcash-wrapper
|
|
@ -1,6 +1,7 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
set -eu -o pipefail
|
set -eu -o pipefail
|
||||||
|
set +x
|
||||||
|
|
||||||
function cmd_pref() {
|
function cmd_pref() {
|
||||||
if type -p "$2" > /dev/null; then
|
if type -p "$2" > /dev/null; then
|
||||||
|
@ -69,6 +70,12 @@ as --version
|
||||||
ld -v
|
ld -v
|
||||||
|
|
||||||
HOST="$HOST" BUILD="$BUILD" "$MAKE" "$@" -C ./depends/
|
HOST="$HOST" BUILD="$BUILD" "$MAKE" "$@" -C ./depends/
|
||||||
|
|
||||||
|
if [ "${BUILD_STAGE:-all}" = "depends" ]
|
||||||
|
then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
./autogen.sh
|
./autogen.sh
|
||||||
CONFIG_SITE="$PWD/depends/$HOST/share/config.site" ./configure $CONFIGURE_FLAGS
|
CONFIG_SITE="$PWD/depends/$HOST/share/config.site" ./configure $CONFIGURE_FLAGS
|
||||||
"$MAKE" "$@"
|
"$MAKE" "$@"
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -eu -o pipefail
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo ""
|
||||||
|
echo "$0 <build stage> <options> <passthrough build arguments>"
|
||||||
|
echo ""
|
||||||
|
echo "Build a fuzzer in the local repo using the following options:"
|
||||||
|
echo ""
|
||||||
|
echo "<build stage>:"
|
||||||
|
echo " either \"depends\" or \"fuzzer\""
|
||||||
|
echo ""
|
||||||
|
echo "<options>:"
|
||||||
|
echo " -f,--fuzzer <fuzzername> (ignored if building \"depends\")"
|
||||||
|
echo " [-s,--sanitizers <sanitizers>]"
|
||||||
|
echo " [-i,--instrument <instrument>]"
|
||||||
|
echo " [-l,--logfile <logfile>] # default is ./zcash-build-wrapper.log"
|
||||||
|
echo " [-h,--help]"
|
||||||
|
echo ""
|
||||||
|
echo "Where fuzzer is an entry in ./src/fuzzing/*, the default sanitizer"
|
||||||
|
echo "is \"address\" and default instrument is ( \"^.*/src/$\" )."
|
||||||
|
echo ""
|
||||||
|
exit -1
|
||||||
|
}
|
||||||
|
|
||||||
|
die() {
|
||||||
|
echo $1
|
||||||
|
exit -1
|
||||||
|
}
|
||||||
|
|
||||||
|
# parse command line options
|
||||||
|
|
||||||
|
POSITIONAL=()
|
||||||
|
while [[ $# -gt 0 ]]
|
||||||
|
do
|
||||||
|
key="$1"
|
||||||
|
|
||||||
|
case $key in
|
||||||
|
-f|--fuzzer)
|
||||||
|
FUZZER_NAME="$2"
|
||||||
|
if [ ! -f "./src/fuzzing/$FUZZER_NAME/fuzz.cpp" ]
|
||||||
|
then
|
||||||
|
die "Cannot find source code for fuzzer."
|
||||||
|
fi
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-s|--sanitizers)
|
||||||
|
LLVM_SANITIZERS="$2"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-i|--instrument)
|
||||||
|
INSTRUMENT_CODE="$2"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-l|--logfile)
|
||||||
|
LOGFILE="$2"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
POSITIONAL+=("$1")
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# positional arguments
|
||||||
|
|
||||||
|
if [ ${#POSITIONAL[@]} -lt 1 ]
|
||||||
|
then
|
||||||
|
usage
|
||||||
|
else
|
||||||
|
BUILD_STAGE=${POSITIONAL[0]}
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "${BUILD_STAGE:-undefined}" in
|
||||||
|
depends)
|
||||||
|
FUZZER_NAME=notused
|
||||||
|
# fine
|
||||||
|
;;
|
||||||
|
fuzzer)
|
||||||
|
# fine
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# not fine
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# required arguments
|
||||||
|
|
||||||
|
if [ "${FUZZER_NAME:-undefined}" = "undefined" ]
|
||||||
|
then
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
# default values
|
||||||
|
|
||||||
|
if [ "${LLVM_SANITIZERS:-undefined}" = "undefined" ]
|
||||||
|
then
|
||||||
|
export LLVM_SANITIZERS="address"
|
||||||
|
fi
|
||||||
|
if [ "${INSTRUMENT_CODE:-undefined}" = "undefined" ]
|
||||||
|
then
|
||||||
|
export INSTRUMENT_CODE=("^.*\/src")
|
||||||
|
fi
|
||||||
|
if [ "${LOGFILE:-undefined}" = "undefined" ]
|
||||||
|
then
|
||||||
|
export LOGFILE=./zcash-build-wrapper.log
|
||||||
|
fi
|
||||||
|
|
||||||
|
set -x
|
||||||
|
|
||||||
|
export ZCUTIL=$(realpath "./zcutil")
|
||||||
|
|
||||||
|
# overwrite the Linux make profile to use clang instead of GCC:
|
||||||
|
|
||||||
|
cat $ZCUTIL/../depends/hosts/linux.mk | sed -e 's/=gcc/=clang/g' | sed -e 's/=g++/=clang++/g' > x
|
||||||
|
mv x $ZCUTIL/../depends/hosts/linux.mk
|
||||||
|
|
||||||
|
# the build_stage distinction helps to layer an intermediate docker
|
||||||
|
# container for the built dependencies, so we can resume building
|
||||||
|
# from there assuming no other build arguments have changed
|
||||||
|
|
||||||
|
if [ "$BUILD_STAGE" = "depends" ]
|
||||||
|
then
|
||||||
|
# make an empty fuzz file just so we can build dependencies
|
||||||
|
> src/fuzz.cpp
|
||||||
|
else
|
||||||
|
cp "./src/fuzzing/$FUZZER_NAME/fuzz.cpp" src/fuzz.cpp || die "Can't copy fuzz.cpp for that fuzzer"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# sneak the variable into zcashd's build.sh
|
||||||
|
|
||||||
|
export BUILD_STAGE
|
||||||
|
|
||||||
|
# run build.sh with our compiler wrapper, and BUILD_STAGE environment set:
|
||||||
|
|
||||||
|
CONFIGURE_FLAGS="--enable-tests=no --disable-bench" \
|
||||||
|
"$ZCUTIL/build.sh" \
|
||||||
|
-j$(nproc) \
|
||||||
|
"CC=$ZCUTIL/libfuzzer/zcash-wrapper-clang" \
|
||||||
|
"CXX=$ZCUTIL/libfuzzer/zcash-wrapper-clang++" "${POSITIONAL[@]:1}" || die "Build failed at stage $BUILD_STAGE."
|
|
@ -0,0 +1,123 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# you shouldn't normally be calling this script directly, it should be called
|
||||||
|
# by build.sh, but only when build.sh is invoked from libfuzzer-build.sh.
|
||||||
|
|
||||||
|
set -ex -o pipefail
|
||||||
|
|
||||||
|
# logging functions
|
||||||
|
|
||||||
|
export green="\e[92m"
|
||||||
|
export red="\e[95m"
|
||||||
|
export normal="\e[0m"
|
||||||
|
|
||||||
|
export color=$normal
|
||||||
|
|
||||||
|
function log {
|
||||||
|
while read line
|
||||||
|
do
|
||||||
|
(echo ; echo -e "${color}${line}${normal}") >> "$LOGFILE" ;
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# command-line parsing
|
||||||
|
|
||||||
|
export FINAL_LINK=0 # by default we using -fsanitize=fuzzer-no-link
|
||||||
|
|
||||||
|
for arg do
|
||||||
|
shift
|
||||||
|
if [ "$arg" = "-fPIE" ] # no more pie
|
||||||
|
then
|
||||||
|
set -- "$@" "-fPIC" "-fno-pie"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$arg" = "-pie" ]
|
||||||
|
then
|
||||||
|
set -- "$@" "-no-pie"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$arg" = "-o" ] # here an output file is being specified
|
||||||
|
then
|
||||||
|
if [ "$1" = "zcashd" ] # here zcashd is the output file
|
||||||
|
then
|
||||||
|
export FINAL_LINK=1 # we should use -fsanitize=fuzzer because that links libfuzzer
|
||||||
|
fi
|
||||||
|
# note no continue, we fall through to default set
|
||||||
|
fi
|
||||||
|
set -- "$@" "$arg"
|
||||||
|
done
|
||||||
|
|
||||||
|
# which source dirs to instrument
|
||||||
|
|
||||||
|
if [ "$dirs_to_instrument" = "" ]
|
||||||
|
then
|
||||||
|
export dirs_to_instrument=("^.*\/src$")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Store the command line we were given to a file
|
||||||
|
|
||||||
|
echo "`hostname`:`pwd` \$" | log
|
||||||
|
echo -- "original command: $0 $@" | log
|
||||||
|
|
||||||
|
# decide on a sanitizer option beyond just fuzzing:
|
||||||
|
# to link nor not to link libfuzzer we only link on
|
||||||
|
# the final call, to the linker.
|
||||||
|
|
||||||
|
if [ "$LLVM_SANITIZE" = "" ]
|
||||||
|
then
|
||||||
|
export LLVM_SANITIZE="address" # you can override this behavior by setting this environment variable first
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$FINAL_LINK" = "1" ]
|
||||||
|
then
|
||||||
|
export LLVM_SANITIZE="-fsanitize=fuzzer,$LLVM_SANITIZE"
|
||||||
|
else
|
||||||
|
export LLVM_SANITIZE="-fsanitize=fuzzer-no-link,$LLVM_SANITIZE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Work out which compiler we were called as
|
||||||
|
|
||||||
|
case $0 in
|
||||||
|
*zcash-wrapper-clang)
|
||||||
|
COMPILER="clang"
|
||||||
|
export DEFINES_FLAGS="${CFLAGS} -DZCASH_FUZZ=1 -DFUZZ_WITH_LIBFUZZER=1 -fPIC"
|
||||||
|
export INSTRUMENT_FLAGS="${DEFINES_FLAGS} ${LLVM_SANITIZE}"
|
||||||
|
;;
|
||||||
|
*zcash-wrapper-clang++)
|
||||||
|
COMPILER="clang++"
|
||||||
|
export DEFINES_FLAGS="${CXXFLAGS} -DZCASH_FUZZ=1 -DFUZZ_WITH_LIBFUZZER=1 -fPIC"
|
||||||
|
export INSTRUMENT_FLAGS="${DEFINES_FLAGS} ${LLVM_SANITIZE}"
|
||||||
|
;;
|
||||||
|
*zcash-wrapper)
|
||||||
|
echo -n "Call this script instead of your regular compiler, and if the absolute "
|
||||||
|
echo -n "path of the CWD the wrapper was called from matches a regex in the "
|
||||||
|
echo -n "array 'dirs_to_instrument', it will instrument the resulting object. "
|
||||||
|
echo -n "Otherwise it will exec directly to the original compiler without "
|
||||||
|
echo "changing arguments."
|
||||||
|
echo -n "You can also set LLVM_SANITIZE to whatever sanitizers you'd like to use."
|
||||||
|
echo -n "the default is 'address'. You don't need the -fsanitize=fuzzer part, "
|
||||||
|
echo "this script handles that"
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Check if we should instrument
|
||||||
|
|
||||||
|
for i in "${dirs_to_instrument[@]}"
|
||||||
|
do
|
||||||
|
if echo -- "`pwd`" | grep "$i"; then
|
||||||
|
# We found a match, let's instrument this one.
|
||||||
|
echo "pwd (`pwd`) matches dirs_to_instrument array element ($i). Adding instrumentation flags..." | log
|
||||||
|
echo "command with defines and instrumentation added:" | color=$green log
|
||||||
|
echo -- "$COMPILER" $INSTRUMENT_FLAGS "$@" | log
|
||||||
|
exec -- "$COMPILER" $INSTRUMENT_FLAGS "$@"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# No match, just pass-through.
|
||||||
|
|
||||||
|
echo -e -- "${red}command with defines added:${normal}" | color=$red log
|
||||||
|
echo -- "$COMPILER" $DEFINES_FLAGS "$@" | log
|
||||||
|
exec -- "$COMPILER" $DEFINES_FLAGS "$@"
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
zcash-wrapper
|
|
@ -0,0 +1 @@
|
||||||
|
zcash-wrapper
|
Loading…
Reference in New Issue