Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
5c3b550
Simple fuzzing framework
pstratem Mar 16, 2021
d6f6a85
doc: Add bare-bones documentation for fuzzing
laanwj Nov 16, 2016
11150df
Make fuzzer actually test CTxOutCompressor
sipa Dec 15, 2016
faf2be6
Init ECC context for test_bitcoin_fuzzy.
gmaxwell Feb 5, 2017
84f72da
[test] Speed up fuzzing by ~200x when using afl-fuzz
practicalswift May 18, 2017
08d8ebe
[tests] Add libFuzzer support.
practicalswift May 22, 2017
2e4ec58
[fuzzing] initialize chain params by default.
furszy Mar 18, 2021
d5dddde
[test] fuzz: make test_one_input return void
Jan 25, 2019
a568df5
test: Build fuzz targets into separate executables
furszy Mar 18, 2021
393a126
fuzz: Move deserialize tests to test/fuzz/deserialize.cpp
Feb 13, 2019
58dbe79
add fuzzing binaries to gitignore.
furszy Mar 19, 2021
89fe5b2
Add missing LIBBITCOIN_ZMQ to test target
furszy Mar 22, 2021
541f442
qa: Add test/fuzz/test_runner.py
Jan 16, 2019
425742c
fuzz: test_runner: Better error message when built with afl
Feb 14, 2019
f28ac9a
build: Allow to configure --with-sanitizers=fuzzer
Dec 27, 2018
1266d3e
Disable other targets when enable-fuzz is set
qmma70 Jul 4, 2019
c3447b5
Update doc and CI config
qmma70 Jul 9, 2019
d642b67
[Build] Do not disable wallet when fuzz is enabled.
furszy Mar 22, 2021
48cd0c8
doc: Improve fuzzing docs for macOS users
fjahr Jan 13, 2020
cd6134f
test: Log output even if fuzzer failed
Jun 18, 2019
b54b1d6
tests: Improve test runner output in case of target errors
practicalswift Feb 19, 2020
2b4f8aa
doc: Remove --disable-ccache from docs
Mar 9, 2020
52693ee
fuzz: Add option to merge input dir to test runner
Feb 19, 2019
3205871
fuzz: Remove option --export_coverage from test_runner
Mar 10, 2020
b5f291c
tests: Add fuzzing harness for CheckTransaction(...), IsStandardTx(..…
furszy Mar 24, 2021
e1f666c
tests: Remove TRANSACTION_DESERIALIZE (replaced by transaction fuzzer)
practicalswift Mar 24, 2021
d058d8c
tests: Add deserialization fuzzing harnesses
furszy Mar 24, 2021
e1b92b6
ignore new fuzz targets gitignore
furszy Mar 26, 2021
70a0ace
tests: Test serialisation as part of deserialisation fuzzing. Test ro…
practicalswift Oct 23, 2019
9631f46
[doc] add sanitizers documentation in developer-notes.md
furszy Mar 26, 2021
f0887a0
Fuzzing documentation "PIVX-fication"
furszy Apr 20, 2021
2396e6b
[fuzz] Add ContextualCheckTransaction call to transaction target.
furszy Apr 20, 2021
d059544
[Build] fuzz target, change LIBBITCOIN_ZEROCOIN link order.
furszy May 26, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,29 @@ src/pivx-cli
src/pivx-tx
src/bench/bench_pivx
src/test/test_pivx
src/test/test_pivx_fuzzy
src/qt/test/test_pivx-qt
src/test/fuzz/address_deserialize
src/test/fuzz/addrman_deserialize
src/test/fuzz/banentry_deserialize
src/test/fuzz/block_deserialize
src/test/fuzz/blockheader_deserialize
src/test/fuzz/blocklocator_deserialize
src/test/fuzz/blockmerkleroot
src/test/fuzz/blockundo_deserialize
src/test/fuzz/bloomfilter_deserialize
src/test/fuzz/coins_deserialize
src/test/fuzz/diskblockindex_deserialize
src/test/fuzz/inv_deserialize
src/test/fuzz/messageheader_deserialize
src/test/fuzz/netaddr_deserialize
src/test/fuzz/service_deserialize
src/test/fuzz/transaction_deserialize
src/test/fuzz/txoutcompressor_deserialize
src/test/fuzz/txundo_deserialize
src/test/fuzz/transaction
src/test/fuzz/*deserialize


# autoreconf
Makefile.in
Expand Down
5 changes: 5 additions & 0 deletions .travis/test_04_install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
export LC_ALL=C.UTF-8

travis_retry docker pull "$DOCKER_NAME_TAG"

export DIR_FUZZ_IN=${TRAVIS_BUILD_DIR}/qa-assets
git clone https://github.com/bitcoin-core/qa-assets ${DIR_FUZZ_IN}
export DIR_FUZZ_IN=${DIR_FUZZ_IN}/fuzz_seed_corpus/

env | grep -E '^(BITCOIN_CONFIG|CCACHE_|WINEDEBUG|LC_ALL|BOOST_TEST_RANDOM|CONFIG_SHELL)' | tee /tmp/env
if [[ $HOST = *-mingw32 ]]; then
DOCKER_ADMIN="--cap-add SYS_ADMIN"
Expand Down
6 changes: 6 additions & 0 deletions .travis/test_06_script_b.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,10 @@ if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then
END_FOLD
fi

if [ "$RUN_FUZZ_TESTS" = "true" ]; then
BEGIN_FOLD fuzz-tests
DOCKER_EXEC test/fuzz/test_runner.py -l DEBUG ${DIR_FUZZ_IN}
END_FOLD
fi
Comment on lines 29 to 33
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are no longer using Travis, it would be awesome to have the same thing for GA in the future.


cd ${TRAVIS_BUILD_DIR} || (echo "could not enter travis build dir $TRAVIS_BUILD_DIR"; exit 1)
3 changes: 2 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,8 @@ dist_noinst_SCRIPTS = autogen.sh
EXTRA_DIST = $(DIST_SHARE) $(DIST_CONTRIB) $(DIST_DOCS) $(DIST_CARGO) $(WINDOWS_PACKAGING) $(LINUX_PACKAGING) $(OSX_PACKAGING) $(BIN_CHECKS)

EXTRA_DIST += \
test/functional
test/functional \
test/fuzz

EXTRA_DIST += \
test/util/bitcoin-util-test.py \
Expand Down
47 changes: 40 additions & 7 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ AC_ARG_WITH([params-dir],
],
[params_path=""])

# Enable wallet
AC_ARG_ENABLE([wallet],
[AS_HELP_STRING([--disable-wallet],
[disable wallet (enabled by default)])],
Expand Down Expand Up @@ -167,6 +166,12 @@ AC_ARG_ENABLE([extended-functional-tests],
[use_extended_functional_tests=$enableval],
[use_extended_functional_tests=no])

AC_ARG_ENABLE([fuzz],
AS_HELP_STRING([--enable-fuzz],
[enable building of fuzz targets (default no). enabling this will disable all other targets]),
[enable_fuzz=$enableval],
[enable_fuzz=no])

AC_ARG_WITH([qtcharts],
[AS_HELP_STRING([--with-qtcharts],
[enable qtcharts support (default is yes if qt is enabled and qtchartview is found)])],
Expand Down Expand Up @@ -314,7 +319,14 @@ if test x$use_sanitizers != x; then
AX_CHECK_LINK_FLAG(
[[-fsanitize=$use_sanitizers]],
[[SANITIZER_LDFLAGS=-fsanitize=$use_sanitizers]],
[AC_MSG_ERROR([linker did not accept requested flags, you are missing required libraries])])
[AC_MSG_ERROR([linker did not accept requested flags, you are missing required libraries])],
[],
[AC_LANG_PROGRAM([[
#include <cstdint>
#include <cstddef>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { return 0; }
__attribute__((weak)) // allow for libFuzzer linking
]],[[]])])
fi

ERROR_CXXFLAGS=
Expand Down Expand Up @@ -996,6 +1008,28 @@ AC_SUBST(LEVELDB_CPPFLAGS)
AC_SUBST(LIBLEVELDB)
AC_SUBST(LIBMEMENV)

dnl enable-fuzz should disable all other targets
if test "x$enable_fuzz" = "xyes"; then
AC_MSG_WARN(enable-fuzz will disable other targets)
build_bitcoin_utils=no
build_bitcoin_cli=no
build_bitcoin_tx=no
build_bitcoind=no
build_bitcoin_libs=no
bitcoin_enable_qt=no
bitcoin_enable_qt_test=no
bitcoin_enable_qt_dbus=no
enable_wallet=yes # needs to be built for now.
use_bench=no
use_upnp=no
use_zmq=no
else
BITCOIN_QT_INIT

dnl sets $bitcoin_enable_qt, $bitcoin_enable_qt_test, $bitcoin_enable_qt_dbus
BITCOIN_QT_CONFIGURE([$use_pkgconfig])
fi

if test x$enable_wallet != xno; then
dnl Check for libdb_cxx only if wallet enabled
BITCOIN_FIND_BDB48
Expand Down Expand Up @@ -1030,11 +1064,6 @@ if test x$have_miniupnpc != xno; then
fi
fi

BITCOIN_QT_INIT

dnl sets $bitcoin_enable_qt, $bitcoin_enable_qt_test, $bitcoin_enable_qt_dbus
BITCOIN_QT_CONFIGURE([$use_pkgconfig])

if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnonononono; then
use_boost=no
else
Expand Down Expand Up @@ -1409,6 +1438,7 @@ AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows])
AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet = xyes])
AM_CONDITIONAL([ENABLE_MINING_RPC],[test x$enable_mining_rpc = xyes])
AM_CONDITIONAL([ENABLE_TESTS],[test x$BUILD_TEST = xyes])
AM_CONDITIONAL([ENABLE_FUZZ],[test x$enable_fuzz = xyes])
AM_CONDITIONAL([ENABLE_QT],[test x$bitcoin_enable_qt = xyes])
AM_CONDITIONAL([ENABLE_QT_TESTS],[test x$BUILD_TEST_QT = xyes])
AM_CONDITIONAL([ENABLE_BENCH],[test x$use_bench = xyes])
Expand Down Expand Up @@ -1556,6 +1586,9 @@ if test x$bitcoin_enable_qt != xno; then
fi
echo " with zmq = $use_zmq"
echo " with test = $use_tests"
if test x$use_tests != xno; then
echo " with fuzz = $enable_fuzz"
fi
echo " with bench = $use_bench"
echo " with upnp = $use_upnp"
echo " with params = $params_path"
Expand Down
1 change: 1 addition & 0 deletions doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ The PIVX repo's [root README](/README.md) contains relevant information on the d
### Miscellaneous
- [Assets Attribution](assets-attribution.md)
- [Files](files.md)
- [Fuzz-testing](fuzzing.md)
- [Reduce Memory](reduce-memory.md)
- [Tor Support](tor.md)
- [Init Scripts (systemd/upstart/openrc)](init.md)
Expand Down
42 changes: 42 additions & 0 deletions doc/developer-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,48 @@ make cov
# A coverage report will now be accessible at `./test_pivx.coverage/index.html`.
```

**Sanitizers**
PIVX can be compiled with various "sanitizers" enabled, which add
instrumentation for issues regarding things like memory safety, thread race
conditions, or undefined behavior. This is controlled with the
`--with-sanitizers` configure flag, which should be a comma separated list of
sanitizers to enable. The sanitizer list should correspond to supported
`-fsanitize=` options in your compiler. These sanitizers have runtime overhead,
so they are most useful when testing changes or producing debugging builds.
Some examples:
```bash
# Enable both the address sanitizer and the undefined behavior sanitizer
./configure --with-sanitizers=address,undefined
# Enable the thread sanitizer
./configure --with-sanitizers=thread
```
If you are compiling with GCC you will typically need to install corresponding
"san" libraries to actually compile with these flags, e.g. libasan for the
address sanitizer, libtsan for the thread sanitizer, and libubsan for the
undefined sanitizer. If you are missing required libraries, the configure script
will fail with a linker error when testing the sanitizer flags.
The test suite should pass cleanly with the `thread` and `undefined` sanitizers,
but there are a number of known problems when using the `address` sanitizer. The
address sanitizer is known to fail in
[sha256_sse4::Transform](/src/crypto/sha256_sse4.cpp) which makes it unusable
unless you also use `--disable-asm` when running configure. We would like to fix
sanitizer issues, so please send pull requests if you can fix any errors found
by the address sanitizer (or any other sanitizer).
Not all sanitizer options can be enabled at the same time, e.g. trying to build
with `--with-sanitizers=address,thread` will fail in the configure script as
these sanitizers are mutually incompatible. Refer to your compiler manual to
learn more about these options and which sanitizers are supported by your
compiler.
Additional resources:
* [AddressSanitizer](https://clang.llvm.org/docs/AddressSanitizer.html)
* [LeakSanitizer](https://clang.llvm.org/docs/LeakSanitizer.html)
* [MemorySanitizer](https://clang.llvm.org/docs/MemorySanitizer.html)
* [ThreadSanitizer](https://clang.llvm.org/docs/ThreadSanitizer.html)
* [UndefinedBehaviorSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html)
* [GCC Instrumentation Options](https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html)
* [Google Sanitizers Wiki](https://github.com/google/sanitizers/wiki)
* [Issue #12691: Enable -fsanitize flags in Travis](https://github.com/bitcoin/bitcoin/issues/12691)

Locking/mutex usage notes
-------------------------

Expand Down
138 changes: 138 additions & 0 deletions doc/fuzzing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
Fuzz-testing PIVX Core
==========================

A special test harness in `src/test/fuzz/` is provided for each fuzz target to
provide an easy entry point for fuzzers and the like. In this document we'll
describe how to use it with AFL and libFuzzer.

## Preparing fuzzing

The fuzzer needs some inputs to work on, but the inputs or seeds can be used
interchangeably between libFuzzer and AFL.

Extract the example seeds (or other starting inputs) into the inputs
directory before starting fuzzing.

```
git clone https://github.com/bitcoin-core/qa-assets
export DIR_FUZZ_IN=$PWD/qa-assets/fuzz_seed_corpus
```

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.

So, only for AFL you need to configure the outputs path:

```
mkdir outputs
export AFLOUT=$PWD/outputs
```

libFuzzer will use the input directory as output directory.

## 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
```

For macOS you may need to ignore x86 compilation checks when running `make`:
`AFL_NO_X86=1 make`.

### Instrumentation

To build PIVX Core using AFL instrumentation (this assumes that the
`AFLPATH` was set as above):
```
./configure --disable-shared --enable-tests --enable-fuzz CC=${AFLPATH}/afl-gcc CXX=${AFLPATH}/afl-g++
export AFL_HARDEN=1
make
```

If you are using clang you will need to substitute `afl-gcc` with `afl-clang`
and `afl-g++` with `afl-clang++`, so the first line above becomes:
```
./configure --disable-shared --enable-tests --enable-fuzz CC=${AFLPATH}/afl-clang CXX=${AFLPATH}/afl-clang++
```

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.

The fuzzing can be sped up significantly (~200x) by using `afl-clang-fast` and
`afl-clang-fast++` in place of `afl-gcc` and `afl-g++` when compiling. When
compiling using `afl-clang-fast`/`afl-clang-fast++` the resulting
binary will be instrumented in such a way that the AFL
features "persistent mode" and "deferred forkserver" can be used. See
https://github.com/google/AFL/tree/master/llvm_mode for details.

### Fuzzing

To start the actual fuzzing use:

```
export FUZZ_TARGET=bech32 # Pick a fuzz_target
mkdir ${AFLOUT}/${FUZZ_TARGET}
$AFLPATH/afl-fuzz -i ${DIR_FUZZ_IN}/${FUZZ_TARGET} -o ${AFLOUT}/${FUZZ_TARGET} -m52 -- src/test/fuzz/${FUZZ_TARGET}
```

You may have to change a few kernel parameters to test optimally - `afl-fuzz`
will print an error and suggestion if so.

On macOS you may need to set `AFL_NO_FORKSRV=1` to get the target to run.
```
export FUZZ_TARGET=bech32 # Pick a fuzz_target
mkdir ${AFLOUT}/${FUZZ_TARGET}
AFL_NO_FORKSRV=1 $AFLPATH/afl-fuzz -i ${DIR_FUZZ_IN}/${FUZZ_TARGET} -o ${AFLOUT}/${FUZZ_TARGET} -m52 -- src/test/fuzz/${FUZZ_TARGET}
```

## libFuzzer

A recent version of `clang`, the address sanitizer and libFuzzer is needed (all
found in the `compiler-rt` runtime libraries package).

To build all fuzz targets with libFuzzer, run

```
./configure --enable-fuzz --with-sanitizers=fuzzer,address CC=clang CXX=clang++
make
```

See https://llvm.org/docs/LibFuzzer.html#running on how to run the libFuzzer
instrumented executable.

Alternatively, you can run the script through the fuzzing test harness (only
libFuzzer supported so far). You need to pass it the inputs directory and
the specific test target you want to run.

```
./test/fuzz/test_runner.py ${DIR_FUZZ_IN} bech32
```

### macOS hints for libFuzzer

The default clang/llvm version supplied by Apple on macOS does not include
fuzzing libraries, so macOS users will need to install a full version, for
example using `brew install llvm`.

Should you run into problems with the address sanitizer, it is possible you
may need to run `./configure` with `--disable-asm` to avoid errors
with certain assembly code from PIVX Core's code. See [developer notes on sanitizers](https://github.com/PIVX-Project/PIVX/blob/master/doc/developer-notes.md#sanitizers)
for more information.

You may also need to take care of giving the correct path for clang and
clang++, like `CC=/path/to/clang CXX=/path/to/clang++` if the non-systems
clang does not come first in your path.

Full configure that was tested on macOS Catalina with `brew` installed `llvm`:
```
./configure --enable-fuzz --with-sanitizers=fuzzer,address,undefined CC=/usr/local/opt/llvm/bin/clang CXX=/usr/local/opt/llvm/bin/clang++ --disable-asm
```
Loading