Merge #9172: Resurrect pstratem's "Simple fuzzing framework"

8b15434 doc: Add bare-bones documentation for fuzzing (Wladimir J. van der Laan)
a4153e2 Simple fuzzing framework (Patrick Strateman)
pull/308/head
Wladimir J. van der Laan 8 years ago
commit 5bc209c73f
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6

1
.gitignore vendored

@ -6,6 +6,7 @@ src/bitcoind
src/bitcoin-cli src/bitcoin-cli
src/bitcoin-tx src/bitcoin-tx
src/test/test_bitcoin src/test/test_bitcoin
src/test/test_bitcoin_fuzzy
src/qt/test/test_bitcoin-qt src/qt/test/test_bitcoin-qt
# autoreconf # autoreconf

@ -68,6 +68,7 @@ The Bitcoin repo's [root README](/README.md) contains relevant information on th
### Miscellaneous ### Miscellaneous
- [Assets Attribution](assets-attribution.md) - [Assets Attribution](assets-attribution.md)
- [Files](files.md) - [Files](files.md)
- [Fuzz-testing](fuzzing.md)
- [Reduce Traffic](reduce-traffic.md) - [Reduce Traffic](reduce-traffic.md)
- [Tor Support](tor.md) - [Tor Support](tor.md)
- [Init Scripts (systemd/upstart/openrc)](init.md) - [Init Scripts (systemd/upstart/openrc)](init.md)

@ -0,0 +1,66 @@
Fuzz-testing Bitcoin Core
==========================
A special test harness `test_bitcoin_fuzzy` is provided to provide an easy
entry point for fuzzers and the like. In this document we'll describe how to
use it with AFL.
Building AFL
-------------
It is recommended to always use the latest version of afl:
```
wget http://lcamtuf.coredump.cx/afl/releases/afl-latest.tgz
tar -zxvf afl-latest.tgz
cd afl-<version>
make
export AFLPATH=$PWD
```
Instrumentation
----------------
To build Bitcoin Core using AFL instrumentation (this assumes that the
`AFLPATH` was set as above):
```
./configure --disable-ccache --disable-shared --enable-tests CC=${AFLPATH}/afl-gcc CXX=${AFLPATH}/afl-g++
export AFL_HARDEN=1
cd src/
make test/test_bitcoin_fuzzy
```
We disable ccache because we don't want to pollute the ccache with instrumented
objects, and similarly don't want to use non-instrumented cached objects linked
in.
Preparing fuzzing
------------------
AFL needs an input directory with examples, and an output directory where it
will place examples that it found. These can be anywhere in the file system,
we'll define environment variables to make it easy to reference them.
```
mkdir inputs
AFLIN=$PWD/inputs
mkdir outputs
AFLOUT=$PWD/outputs
```
Example inputs are available from:
- https://download.visucore.com/bitcoin/bitcoin_fuzzy_in.tar.xz
- http://strateman.ninja/fuzzing.tar.xz
Extract these (or other starting inputs) into the `inputs` directory before starting fuzzing.
Fuzzing
--------
To start the actual fuzzing use:
```
$AFLPATH/afl-fuzz -i ${AFLIN} -o ${AFLOUT} -m52 -- test/test_bitcoin_fuzzy
```
You may have to change a few kernel parameters to test optimally - `afl-fuzz`
will print an error and suggestion if so.

@ -61,6 +61,7 @@ EXTRA_LIBRARIES += \
lib_LTLIBRARIES = $(LIBBITCOINCONSENSUS) lib_LTLIBRARIES = $(LIBBITCOINCONSENSUS)
bin_PROGRAMS = bin_PROGRAMS =
noinst_PROGRAMS =
TESTS = TESTS =
BENCHMARKS = BENCHMARKS =

@ -4,6 +4,7 @@
TESTS += test/test_bitcoin TESTS += test/test_bitcoin
bin_PROGRAMS += test/test_bitcoin bin_PROGRAMS += test/test_bitcoin
noinst_PROGRAMS += test/test_bitcoin_fuzzy
TEST_SRCDIR = test TEST_SRCDIR = test
TEST_BINARY=test/test_bitcoin$(EXEEXT) TEST_BINARY=test/test_bitcoin$(EXEEXT)
@ -38,6 +39,7 @@ RAW_TEST_FILES =
GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h) GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h)
# test_bitcoin binary #
BITCOIN_TESTS =\ BITCOIN_TESTS =\
test/arith_uint256_tests.cpp \ test/arith_uint256_tests.cpp \
test/scriptnum10.h \ test/scriptnum10.h \
@ -120,6 +122,25 @@ test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -s
if ENABLE_ZMQ if ENABLE_ZMQ
test_test_bitcoin_LDADD += $(ZMQ_LIBS) test_test_bitcoin_LDADD += $(ZMQ_LIBS)
endif endif
#
# test_bitcoin_fuzzy binary #
test_test_bitcoin_fuzzy_SOURCES = test/test_bitcoin_fuzzy.cpp
test_test_bitcoin_fuzzy_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_test_bitcoin_fuzzy_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_test_bitcoin_fuzzy_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
test_test_bitcoin_fuzzy_LDADD = \
$(LIBUNIVALUE) \
$(LIBBITCOIN_SERVER) \
$(LIBBITCOIN_COMMON) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CONSENSUS) \
$(LIBBITCOIN_CRYPTO) \
$(LIBSECP256K1)
test_test_bitcoin_fuzzy_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
#
nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES) nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES)

@ -0,0 +1,256 @@
// Copyright (c) 2009-2015 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 <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,
TEST_ID_END
};
bool read_stdin(std::vector<char> &data) {
char 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 main(int argc, char **argv)
{
std::vector<char> buffer;
if (!read_stdin(buffer)) return 0;
if (buffer.size() < sizeof(uint32_t)) return 0;
uint32_t test_id = 0xffffffff;
memcpy(&test_id, &buffer[0], 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
{
CCoins block;
ds >> block;
} 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;
try
{
ds >> to;
} catch (const std::ios_base::failure& e) {return 0;}
CTxOutCompressor toc(to);
break;
}
default:
return 0;
}
return 0;
}
Loading…
Cancel
Save