|
|
|
// Copyright (c) 2009-2016 The Bitcoin Core developers
|
|
|
|
// Distributed under the MIT software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
|
|
|
#if defined(HAVE_CONFIG_H)
|
|
|
|
#include "config/bitcoin-config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "consensus/merkle.h"
|
|
|
|
#include "primitives/block.h"
|
|
|
|
#include "script/script.h"
|
|
|
|
#include "addrman.h"
|
|
|
|
#include "chain.h"
|
|
|
|
#include "coins.h"
|
|
|
|
#include "compressor.h"
|
|
|
|
#include "net.h"
|
|
|
|
#include "protocol.h"
|
|
|
|
#include "streams.h"
|
|
|
|
#include "undo.h"
|
|
|
|
#include "version.h"
|
|
|
|
#include "pubkey.h"
|
|
|
|
#include "blockencodings.h"
|
|
|
|
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
enum TEST_ID {
|
|
|
|
CBLOCK_DESERIALIZE=0,
|
|
|
|
CTRANSACTION_DESERIALIZE,
|
|
|
|
CBLOCKLOCATOR_DESERIALIZE,
|
|
|
|
CBLOCKMERKLEROOT,
|
|
|
|
CADDRMAN_DESERIALIZE,
|
|
|
|
CBLOCKHEADER_DESERIALIZE,
|
|
|
|
CBANENTRY_DESERIALIZE,
|
|
|
|
CTXUNDO_DESERIALIZE,
|
|
|
|
CBLOCKUNDO_DESERIALIZE,
|
|
|
|
CCOINS_DESERIALIZE,
|
|
|
|
CNETADDR_DESERIALIZE,
|
|
|
|
CSERVICE_DESERIALIZE,
|
|
|
|
CMESSAGEHEADER_DESERIALIZE,
|
|
|
|
CADDRESS_DESERIALIZE,
|
|
|
|
CINV_DESERIALIZE,
|
|
|
|
CBLOOMFILTER_DESERIALIZE,
|
|
|
|
CDISKBLOCKINDEX_DESERIALIZE,
|
|
|
|
CTXOUTCOMPRESSOR_DESERIALIZE,
|
|
|
|
BLOCKTRANSACTIONS_DESERIALIZE,
|
|
|
|
BLOCKTRANSACTIONSREQUEST_DESERIALIZE,
|
|
|
|
TEST_ID_END
|
|
|
|
};
|
|
|
|
|
|
|
|
bool read_stdin(std::vector<uint8_t> &data) {
|
|
|
|
uint8_t buffer[1024];
|
|
|
|
ssize_t length=0;
|
|
|
|
while((length = read(STDIN_FILENO, buffer, 1024)) > 0) {
|
|
|
|
data.insert(data.end(), buffer, buffer+length);
|
|
|
|
|
|
|
|
if (data.size() > (1<<20)) return false;
|
|
|
|
}
|
|
|
|
return length==0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int test_one_input(std::vector<uint8_t> buffer) {
|
|
|
|
if (buffer.size() < sizeof(uint32_t)) return 0;
|
|
|
|
|
|
|
|
uint32_t test_id = 0xffffffff;
|
|
|
|
memcpy(&test_id, buffer.data(), sizeof(uint32_t));
|
|
|
|
buffer.erase(buffer.begin(), buffer.begin() + sizeof(uint32_t));
|
|
|
|
|
|
|
|
if (test_id >= TEST_ID_END) return 0;
|
|
|
|
|
|
|
|
CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION);
|
|
|
|
try {
|
|
|
|
int nVersion;
|
|
|
|
ds >> nVersion;
|
|
|
|
ds.SetVersion(nVersion);
|
|
|
|
} catch (const std::ios_base::failure& e) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(test_id) {
|
|
|
|
case CBLOCK_DESERIALIZE:
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
CBlock block;
|
|
|
|
ds >> block;
|
|
|
|
} catch (const std::ios_base::failure& e) {return 0;}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CTRANSACTION_DESERIALIZE:
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
CTransaction tx(deserialize, ds);
|
|
|
|
} catch (const std::ios_base::failure& e) {return 0;}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CBLOCKLOCATOR_DESERIALIZE:
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
CBlockLocator bl;
|
|
|
|
ds >> bl;
|
|
|
|
} catch (const std::ios_base::failure& e) {return 0;}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CBLOCKMERKLEROOT:
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
CBlock block;
|
|
|
|
ds >> block;
|
|
|
|
bool mutated;
|
|
|
|
BlockMerkleRoot(block, &mutated);
|
|
|
|
} catch (const std::ios_base::failure& e) {return 0;}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CADDRMAN_DESERIALIZE:
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
CAddrMan am;
|
|
|
|
ds >> am;
|
|
|
|
} catch (const std::ios_base::failure& e) {return 0;}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CBLOCKHEADER_DESERIALIZE:
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
CBlockHeader bh;
|
|
|
|
ds >> bh;
|
|
|
|
} catch (const std::ios_base::failure& e) {return 0;}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CBANENTRY_DESERIALIZE:
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
CBanEntry be;
|
|
|
|
ds >> be;
|
|
|
|
} catch (const std::ios_base::failure& e) {return 0;}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CTXUNDO_DESERIALIZE:
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
CTxUndo tu;
|
|
|
|
ds >> tu;
|
|
|
|
} catch (const std::ios_base::failure& e) {return 0;}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CBLOCKUNDO_DESERIALIZE:
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
CBlockUndo bu;
|
|
|
|
ds >> bu;
|
|
|
|
} catch (const std::ios_base::failure& e) {return 0;}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CCOINS_DESERIALIZE:
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
Coin coin;
|
|
|
|
ds >> coin;
|
|
|
|
} catch (const std::ios_base::failure& e) {return 0;}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CNETADDR_DESERIALIZE:
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
CNetAddr na;
|
|
|
|
ds >> na;
|
|
|
|
} catch (const std::ios_base::failure& e) {return 0;}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CSERVICE_DESERIALIZE:
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
CService s;
|
|
|
|
ds >> s;
|
|
|
|
} catch (const std::ios_base::failure& e) {return 0;}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CMESSAGEHEADER_DESERIALIZE:
|
|
|
|
{
|
|
|
|
CMessageHeader::MessageStartChars pchMessageStart = {0x00, 0x00, 0x00, 0x00};
|
|
|
|
try
|
|
|
|
{
|
|
|
|
CMessageHeader mh(pchMessageStart);
|
|
|
|
ds >> mh;
|
|
|
|
if (!mh.IsValid(pchMessageStart)) {return 0;}
|
|
|
|
} catch (const std::ios_base::failure& e) {return 0;}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CADDRESS_DESERIALIZE:
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
CAddress a;
|
|
|
|
ds >> a;
|
|
|
|
} catch (const std::ios_base::failure& e) {return 0;}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CINV_DESERIALIZE:
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
CInv i;
|
|
|
|
ds >> i;
|
|
|
|
} catch (const std::ios_base::failure& e) {return 0;}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CBLOOMFILTER_DESERIALIZE:
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
CBloomFilter bf;
|
|
|
|
ds >> bf;
|
|
|
|
} catch (const std::ios_base::failure& e) {return 0;}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CDISKBLOCKINDEX_DESERIALIZE:
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
CDiskBlockIndex dbi;
|
|
|
|
ds >> dbi;
|
|
|
|
} catch (const std::ios_base::failure& e) {return 0;}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CTXOUTCOMPRESSOR_DESERIALIZE:
|
|
|
|
{
|
|
|
|
CTxOut to;
|
|
|
|
CTxOutCompressor toc(to);
|
|
|
|
try
|
|
|
|
{
|
|
|
|
ds >> toc;
|
|
|
|
} catch (const std::ios_base::failure& e) {return 0;}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case BLOCKTRANSACTIONS_DESERIALIZE:
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
BlockTransactions bt;
|
|
|
|
ds >> bt;
|
|
|
|
} catch (const std::ios_base::failure& e) {return 0;}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case BLOCKTRANSACTIONSREQUEST_DESERIALIZE:
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
BlockTransactionsRequest btr;
|
|
|
|
ds >> btr;
|
|
|
|
} catch (const std::ios_base::failure& e) {return 0;}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle;
|
|
|
|
void initialize() {
|
|
|
|
globalVerifyHandle = std::unique_ptr<ECCVerifyHandle>(new ECCVerifyHandle());
|
|
|
|
}
|
|
|
|
|
|
|
|
// This function is used by libFuzzer
|
|
|
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|
|
|
test_one_input(std::vector<uint8_t>(data, data + size));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This function is used by libFuzzer
|
|
|
|
extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
|
|
|
|
initialize();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Disabled under WIN32 due to clash with Cygwin's WinMain.
|
|
|
|
#ifndef WIN32
|
|
|
|
// Declare main(...) "weak" to allow for libFuzzer linking. libFuzzer provides
|
|
|
|
// the main(...) function.
|
|
|
|
__attribute__((weak))
|
|
|
|
#endif
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
initialize();
|
|
|
|
#ifdef __AFL_INIT
|
|
|
|
// Enable AFL deferred forkserver mode. Requires compilation using
|
|
|
|
// afl-clang-fast++. See fuzzing.md for details.
|
|
|
|
__AFL_INIT();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef __AFL_LOOP
|
|
|
|
// Enable AFL persistent mode. Requires compilation using afl-clang-fast++.
|
|
|
|
// See fuzzing.md for details.
|
|
|
|
int ret = 0;
|
|
|
|
while (__AFL_LOOP(1000)) {
|
|
|
|
std::vector<uint8_t> buffer;
|
|
|
|
if (!read_stdin(buffer)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ret = test_one_input(buffer);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
#else
|
|
|
|
std::vector<uint8_t> buffer;
|
|
|
|
if (!read_stdin(buffer)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return test_one_input(buffer);
|
|
|
|
#endif
|
|
|
|
}
|