Changeset View
Changeset View
Standalone View
Standalone View
src/test/test_bitcoin_fuzzy.cpp
// Copyright (c) 2009-2016 The Bitcoin Core developers | // Copyright (c) 2009-2018 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#if defined(HAVE_CONFIG_H) | |||||
#include <config/bitcoin-config.h> | |||||
#endif | |||||
#include <addrman.h> | #include <addrman.h> | ||||
#include <blockencodings.h> | #include <blockencodings.h> | ||||
#include <chain.h> | #include <chain.h> | ||||
#include <coins.h> | #include <coins.h> | ||||
#include <compressor.h> | #include <compressor.h> | ||||
#include <consensus/merkle.h> | #include <consensus/merkle.h> | ||||
#include <net.h> | #include <net.h> | ||||
#include <primitives/block.h> | #include <primitives/block.h> | ||||
#include <protocol.h> | #include <protocol.h> | ||||
#include <pubkey.h> | #include <pubkey.h> | ||||
#include <script/script.h> | #include <script/script.h> | ||||
#include <streams.h> | #include <streams.h> | ||||
#include <undo.h> | #include <undo.h> | ||||
#include <version.h> | #include <version.h> | ||||
#include <test/fuzz/fuzz.h> | |||||
#include <algorithm> | #include <algorithm> | ||||
#include <cstdint> | #include <cstdint> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include <vector> | #include <vector> | ||||
const std::function<std::string(const char *)> G_TRANSLATION_FUN = nullptr; | void test_one_input(std::vector<uint8_t> buffer) { | ||||
enum TEST_ID { | |||||
CBLOCK_DESERIALIZE = 0, | |||||
CTRANSACTION_DESERIALIZE, | |||||
CBLOCKLOCATOR_DESERIALIZE, | |||||
CBLOCKMERKLEROOT, | |||||
CADDRMAN_DESERIALIZE, | |||||
CBLOCKHEADER_DESERIALIZE, | |||||
CBANENTRY_DESERIALIZE, | |||||
CTXUNDO_DESERIALIZE, | |||||
CBLOCKUNDO_DESERIALIZE, | |||||
COIN_DESERIALIZE, | |||||
CNETADDR_DESERIALIZE, | |||||
CSERVICE_DESERIALIZE, | |||||
CMESSAGEHEADER_DESERIALIZE, | |||||
CADDRESS_DESERIALIZE, | |||||
CINV_DESERIALIZE, | |||||
CBLOOMFILTER_DESERIALIZE, | |||||
CDISKBLOCKINDEX_DESERIALIZE, | |||||
CTXOUTCOMPRESSOR_DESERIALIZE, | |||||
BLOCKTRANSACTIONS_DESERIALIZE, | |||||
BLOCKTRANSACTIONSREQUEST_DESERIALIZE, | |||||
TEST_ID_END | |||||
}; | |||||
static 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; | |||||
} | |||||
static 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); | CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION); | ||||
try { | try { | ||||
int nVersion; | int nVersion; | ||||
ds >> nVersion; | ds >> nVersion; | ||||
ds.SetVersion(nVersion); | ds.SetVersion(nVersion); | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
return 0; | return; | ||||
} | } | ||||
switch (test_id) { | #if BLOCK_DESERIALIZE | ||||
case CBLOCK_DESERIALIZE: { | |||||
try { | try { | ||||
CBlock block; | CBlock block; | ||||
ds >> block; | ds >> block; | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
return 0; | return; | ||||
} | |||||
break; | |||||
} | } | ||||
case CTRANSACTION_DESERIALIZE: { | #elif TRANSACTION_DESERIALIZE | ||||
try { | try { | ||||
CTransaction tx(deserialize, ds); | CTransaction tx(deserialize, ds); | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
return 0; | return; | ||||
} | } | ||||
break; | #elif BLOCKLOCATOR_DESERIALIZE | ||||
} | |||||
case CBLOCKLOCATOR_DESERIALIZE: { | |||||
try { | try { | ||||
CBlockLocator bl; | CBlockLocator bl; | ||||
ds >> bl; | ds >> bl; | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
return 0; | return; | ||||
} | |||||
break; | |||||
} | } | ||||
case CBLOCKMERKLEROOT: { | #elif BLOCKMERKLEROOT | ||||
try { | try { | ||||
CBlock block; | CBlock block; | ||||
ds >> block; | ds >> block; | ||||
bool mutated; | bool mutated; | ||||
BlockMerkleRoot(block, &mutated); | BlockMerkleRoot(block, &mutated); | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
return 0; | return; | ||||
} | |||||
break; | |||||
} | } | ||||
case CADDRMAN_DESERIALIZE: { | #elif ADDRMAN_DESERIALIZE | ||||
try { | try { | ||||
CAddrMan am; | CAddrMan am; | ||||
ds >> am; | ds >> am; | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
return 0; | return; | ||||
} | } | ||||
break; | #elif BLOCKHEADER_DESERIALIZE | ||||
} | |||||
case CBLOCKHEADER_DESERIALIZE: { | |||||
try { | try { | ||||
CBlockHeader bh; | CBlockHeader bh; | ||||
ds >> bh; | ds >> bh; | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
return 0; | return; | ||||
} | |||||
break; | |||||
} | } | ||||
case CBANENTRY_DESERIALIZE: { | #elif BANENTRY_DESERIALIZE | ||||
try { | try { | ||||
CBanEntry be; | CBanEntry be; | ||||
ds >> be; | ds >> be; | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
return 0; | return; | ||||
} | |||||
break; | |||||
} | } | ||||
case CTXUNDO_DESERIALIZE: { | #elif TXUNDO_DESERIALIZE | ||||
try { | try { | ||||
CTxUndo tu; | CTxUndo tu; | ||||
ds >> tu; | ds >> tu; | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
return 0; | return; | ||||
} | } | ||||
break; | #elif BLOCKUNDO_DESERIALIZE | ||||
} | |||||
case CBLOCKUNDO_DESERIALIZE: { | |||||
try { | try { | ||||
CBlockUndo bu; | CBlockUndo bu; | ||||
ds >> bu; | ds >> bu; | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
return 0; | return; | ||||
} | |||||
break; | |||||
} | } | ||||
case COIN_DESERIALIZE: { | #elif COINS_DESERIALIZE | ||||
try { | try { | ||||
Coin coin; | Coin coin; | ||||
ds >> coin; | ds >> coin; | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
return 0; | return; | ||||
} | |||||
break; | |||||
} | } | ||||
case CNETADDR_DESERIALIZE: { | #elif NETADDR_DESERIALIZE | ||||
try { | try { | ||||
CNetAddr na; | CNetAddr na; | ||||
ds >> na; | ds >> na; | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
return 0; | return; | ||||
} | } | ||||
break; | #elif SERVICE_DESERIALIZE | ||||
} | |||||
case CSERVICE_DESERIALIZE: { | |||||
try { | try { | ||||
CService s; | CService s; | ||||
ds >> s; | ds >> s; | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
return 0; | return; | ||||
} | |||||
break; | |||||
} | } | ||||
case CMESSAGEHEADER_DESERIALIZE: { | #elif MESSAGEHEADER_DESERIALIZE | ||||
CMessageHeader::MessageMagic pchMessageStart = { | CMessageHeader::MessageMagic pchMessageStart = {{0x00, 0x00, 0x00, 0x00}}; | ||||
{0x00, 0x00, 0x00, 0x00}}; | |||||
try { | try { | ||||
CMessageHeader mh(pchMessageStart); | CMessageHeader mh(pchMessageStart); | ||||
ds >> mh; | ds >> mh; | ||||
if (!mh.IsValidWithoutConfig(pchMessageStart)) { | if (!mh.IsValidWithoutConfig(pchMessageStart)) { | ||||
return 0; | return; | ||||
} | } | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
return 0; | return; | ||||
} | |||||
break; | |||||
} | } | ||||
case CADDRESS_DESERIALIZE: { | #elif ADDRESS_DESERIALIZE | ||||
try { | try { | ||||
CAddress a; | CAddress a; | ||||
ds >> a; | ds >> a; | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
return 0; | return; | ||||
} | } | ||||
break; | #elif INV_DESERIALIZE | ||||
} | |||||
case CINV_DESERIALIZE: { | |||||
try { | try { | ||||
CInv i; | CInv i; | ||||
ds >> i; | ds >> i; | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
return 0; | return; | ||||
} | |||||
break; | |||||
} | } | ||||
case CBLOOMFILTER_DESERIALIZE: { | #elif BLOOMFILTER_DESERIALIZE | ||||
try { | try { | ||||
CBloomFilter bf; | CBloomFilter bf; | ||||
ds >> bf; | ds >> bf; | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
return 0; | return; | ||||
} | } | ||||
break; | #elif DISKBLOCKINDEX_DESERIALIZE | ||||
} | |||||
case CDISKBLOCKINDEX_DESERIALIZE: { | |||||
try { | try { | ||||
CDiskBlockIndex dbi; | CDiskBlockIndex dbi; | ||||
ds >> dbi; | ds >> dbi; | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
return 0; | return; | ||||
} | |||||
break; | |||||
} | } | ||||
case CTXOUTCOMPRESSOR_DESERIALIZE: { | #elif TXOUTCOMPRESSOR_DESERIALIZE | ||||
CTxOut to; | CTxOut to; | ||||
CTxOutCompressor toc(to); | CTxOutCompressor toc(to); | ||||
try { | try { | ||||
ds >> toc; | ds >> toc; | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
return 0; | return; | ||||
} | } | ||||
#elif BLOCKTRANSACTIONS_DESERIALIZE | |||||
break; | |||||
} | |||||
case BLOCKTRANSACTIONS_DESERIALIZE: { | |||||
try { | try { | ||||
BlockTransactions bt; | BlockTransactions bt; | ||||
ds >> bt; | ds >> bt; | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
return 0; | return; | ||||
} | } | ||||
#elif BLOCKTRANSACTIONSREQUEST_DESERIALIZE | |||||
break; | |||||
} | |||||
case BLOCKTRANSACTIONSREQUEST_DESERIALIZE: { | |||||
try { | try { | ||||
BlockTransactionsRequest btr; | BlockTransactionsRequest btr; | ||||
ds >> btr; | ds >> btr; | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
return 0; | return; | ||||
} | |||||
break; | |||||
} | } | ||||
default: | |||||
return 0; | |||||
} | |||||
return 0; | |||||
} | |||||
static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle; | |||||
void initialize() { | |||||
globalVerifyHandle = std::make_unique<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 | #else | ||||
std::vector<uint8_t> buffer; | #error Need at least one fuzz target to compile | ||||
if (!read_stdin(buffer)) { | |||||
return 0; | |||||
} | |||||
return test_one_input(buffer); | |||||
#endif | #endif | ||||
} | } |