Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resurrect pstratem's "Simple fuzzing framework" #9172

Merged
merged 2 commits into from Dec 15, 2016

Conversation

laanwj
Copy link
Member

@laanwj laanwj commented Nov 16, 2016

Because I feel strongly that we should have it, this brings back #7940, with some minor changes to make it ready for merge:

  • Rebase for removal of CDataStream::GetVersion
  • Move to src/tests, rename to test_bitcoin_fuzzy to make it clear it is part of the tests, not a user entry point
  • Make sure that it doesn't get installed on make install nor shipped as part of the distribution (it is kind of useless without instrumentation). I opted to make it build by default with --enable-tests because if it is a specific option, no one will ever bother to enable it (which means it doesn't get built and runs out of date), and we don't want too many --enable-X anyway.

@laanwj laanwj added the Tests label Nov 16, 2016
@jonasschnelli
Copy link
Contributor

Concept ACK.
Agree that a simple documentation would be useful.
I guess right now you have to pipe in some data that will be used for the fuzz tests?

@laanwj
Copy link
Member Author

laanwj commented Nov 16, 2016

I guess right now you have to pipe in some data that will be used for the fuzz tests?

Piping in data is the part that the fuzzer should do :)

@laanwj
Copy link
Member Author

laanwj commented Nov 16, 2016

I've added some bare-bones instructions on how to use AFL with Bitcoin Core. What I don't have are example inputs, so this doesn't do anything yet at the moment.

@pstratem Would you mind sharing some of your example inputs?

@maflcko
Copy link
Member

maflcko commented Nov 16, 2016

Concept ACK. Would prefer to see at least one MWE.

@laanwj laanwj added this to the 0.14.0 milestone Nov 16, 2016
@laanwj
Copy link
Member Author

laanwj commented Nov 16, 2016

What's an MWE?

@maflcko
Copy link
Member

maflcko commented Nov 16, 2016

Minimal working example: Just a code bit that is of the smallest size, but still demonstrates how the framework is used.

@laanwj
Copy link
Member Author

laanwj commented Nov 16, 2016

Minimal working example: Just a code bit that is of the smallest size, but still demonstrates how the framework is used.

Agreed. I demonstrate how to use the framework in the documentation I added, but there need to be some example inputs to put in inputs/ or it croaks. I could make a few but I'd rather wait for Patrick a bit whether he already has some as it's quite time-consuming.

@pstratem
Copy link
Contributor

pstratem commented Nov 19, 2016

@laanwj suggestion for where examples should go?

(which directory)

@laanwj
Copy link
Member Author

laanwj commented Nov 19, 2016 via email

@gmaxwell
Copy link
Contributor

FWIW, I have a 24 core host grinding on this in AFL for most of a day on this... I guess I'll leave it running all weekend and spin up some more cores. if someone wants the resulting vectors after I cmin them, I'd be glad to hand them out.

(I just started from some particularly dumb /dev/urandom starting points... a future improvement I would suggest (not this PR!) might be a command-line argument that makes it serialize a dummy object or few for each of the modes and write out a set of files.)

@laanwj
Copy link
Member Author

laanwj commented Nov 21, 2016

a future improvement I would suggest (not this PR!) might be a command-line argument that makes it serialize a dummy object or few for each of the modes and write out a set of files.

Yes that would be useful. Should ideally have realistic examples that come up in bitcoind itself (just grabbed from the wire randomly and saved) along with synthetic ones.

if someone wants the resulting vectors after I cmin them, I'd be glad to hand them out.

Yes please!

`AFLPATH` was set as above):
```
./configure --disable-ccache --disable-shared --enable-tests CC=${AFLPATH}/afl-gcc CXX=${AFLPATH}/afl-g++
export AFL_HARDEN=1
Copy link
Member

Choose a reason for hiding this comment

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

For anyone wondering what AFL_HARDEN does. From the afl README.

Setting AFL_HARDEN=1 when calling 'make' will cause the CC wrapper to
automatically enable code hardening options that make it easier to detect
simple memory bugs. Libdislocator, a helper library included with AFL (see
libdislocator/README.dislocator) can help uncover heap corruption issues, too.

Copy link
Member Author

Choose a reason for hiding this comment

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

It may actually be unnecessary with bitcoin core which already enables a lot of hardening options. Then again, it can't hurt either I think.

@fanquake
Copy link
Member

fanquake commented Nov 24, 2016

Started testing this on OS X 10.12.
afl compiles fine, and bitcoin configure completes (using afl-clang and afl-clang++ instead of afl-gcc and afl-gcc++):

Options used to compile and link:
  with wallet   = yes
  with gui / qt = yes
    qt version  = 5
    with qr     = yes
  with zmq      = yes
  with test     = yes
  with bench    = yes
  with upnp     = yes
  debug enabled = no

  target os     = darwin
  build os      = darwin

  CC            = /Users/xxx/github/bitcoin/afl-2.35b/afl-clang
  CFLAGS        = -g -O2
  CPPFLAGS      =  -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS -I/usr/local/opt/berkeley-db4/include -DMAC_OSX
  CXX           = /Users/xxx/github/bitcoin/afl-2.35b/afl-clang++ -std=c++11
  CXXFLAGS      = -g -O2 -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter -Wno-self-assign -Wno-unused-local-typedef -Wno-deprecated-register
  LDFLAGS       =  -Wl,-headerpad_max_install_names -Wl,-dead_strip

test_bitcoin_fuzzy compiles with one warning

bash-3.2$ make test/test_bitcoin_fuzzy
  CXX      test/test_test_bitcoin_fuzzy-test_bitcoin_fuzzy.o
afl-cc 2.35b by <lcamtuf@google.com>
afl-as 2.35b by <lcamtuf@google.com>
[+] Instrumented 2777 locations (64-bit, hardened mode, ratio 100%).
  CXX      lib/libunivalue_la-univalue.lo
... SNIP ...
afl-cc 2.35b by <lcamtuf@google.com>
afl-as 2.35b by <lcamtuf@google.com>
[!] WARNING: No instrumentation targets found.
  CXX      libbitcoin_util_a-random.o
... SNIP ...
afl-cc 2.35b by <lcamtuf@google.com>
afl-as 2.35b by <lcamtuf@google.com>
[+] Instrumented 48 locations (64-bit, hardened mode, ratio 100%).
  AR       crypto/libbitcoin_crypto.a
  CC       src/libsecp256k1_la-secp256k1.lo
afl-cc 2.35b by <lcamtuf@google.com>
afl-as 2.35b by <lcamtuf@google.com>
[+] Instrumented 903 locations (64-bit, hardened mode, ratio 100%).
  CCLD     libsecp256k1.la
  CXXLD    test/test_bitcoin_fuzzy

However, running gave:

bash-3.2$ $AFLPATH/afl-fuzz -i ${AFLIN} -o ${AFLOUT} -- test/test_bitcoin_fuzzy
afl-fuzz 2.35b by <lcamtuf@google.com>
[+] You have 8 CPU cores and 3 runnable tasks (utilization: 38%).
[+] Try parallel jobs - see /usr/local/share/doc/afl/parallel_fuzzing.txt.
[*] Setting up output directories...
[+] Output directory exists but deemed OK to reuse.
[*] Deleting old session data...
[+] Output dir cleanup successful.
[*] Scanning '/Users/xxx/github/bitcoin/src/inputs'...
[+] No auto-generated dictionary tokens to reuse.
[*] Creating hard links for all input files...
[*] Validating target binary...
[*] Attempting dry run with 'id:000000,orig:auto_000000'...
[*] Spinning up the fork server...

[-] Hmm, looks like the target binary terminated before we could complete a
    handshake with the injected code. There are two probable explanations:

    - The current memory limit (50.0 MB) is too restrictive, causing an OOM
      fault in the dynamic linker. This can be fixed with the -m option. A
      simple way to confirm the diagnosis may be:

[-] PROGRAM ABORT : Fork server handshake failed
         Location : init_forkserver(), afl-fuzz.c:2247

Same result even after upping the memory limit to 4GB (-m4096) which should be more than enough.

Setting AFL_NO_FORKSRV=1 seems to have made it run. From the readme:

Setting AFL_NO_FORKSRV disables the forkserver optimization, reverting to
    fork + execve() call for every tested input. This is useful mostly when
    working with unruly libraries that create threads or do other crazy
    things when initializing (before the instrumentation has a chance to run).

So for now it's running:
screen shot 1

Also testing on Ubuntu 16.04 running in VirtualBox.

Options used to compile and link:
  with wallet   = yes
  with gui / qt = yes
    qt version  = 5
    with qr     = auto
  with zmq      = yes
  with test     = yes
  with bench    = yes
  with upnp     = yes
  debug enabled = no

  target os     = linux
  build os      = 

  CC            = /home/ubuntu/bitcoin/afl-2.35b/afl-gcc
  CFLAGS        = -g -O2
  CPPFLAGS      =  -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS
  CXX           = /home/ubuntu/bitcoin/afl-2.35b/afl-g++ -std=c++11
  CXXFLAGS      = -g -O2 -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter
  LDFLAGS       = 

screen shot

@fanquake
Copy link
Member

fanquake commented Nov 24, 2016

Given that one was working alright, I've moved to running five in parallel. Will leave them running for a while. You can use the afl-whatsup tool to watch the progress, sample output below:

$AFLPATH/afl-whatsup sync_dir
status check tool for afl-fuzz by <lcamtuf@google.com>

Individual fuzzers
==================

>>> fuzzer01 (1 days, 0 hrs) <<<

  cycle 1, lifetime speed 159 execs/sec, path 744/1201 (61%)
  pending 52/1043, coverage 6.22%, no crashes yet

>>> fuzzer02 (1 days, 0 hrs) <<<

  cycle 80, lifetime speed 179 execs/sec, path 346/1199 (28%)
  pending 0/0, coverage 6.22%, no crashes yet

>>> fuzzer03 (1 days, 0 hrs) <<<

  cycle 80, lifetime speed 181 execs/sec, path 504/1190 (42%)
  pending 0/0, coverage 6.22%, no crashes yet

>>> fuzzer04 (1 days, 0 hrs) <<<

  cycle 83, lifetime speed 181 execs/sec, path 1180/1190 (99%)
  pending 0/0, coverage 6.22%, no crashes yet

>>> fuzzer05 (0 days, 1 hrs) <<<

  cycle 3, lifetime speed 146 execs/sec, path 621/1206 (51%)
  pending 0/687, coverage 6.22%, no crashes yet

Summary stats
=============

       Fuzzers alive : 5
      Total run time : 4 days, 4 hours
         Total execs : 63 million
    Cumulative speed : 846 execs/sec
       Pending paths : 52 faves, 1730 total
  Pending per fuzzer : 10 faves, 346 total (on average)
       Crashes found : 0 locally unique

examples that it found.

```
mkdir inputs
Copy link
Member

Choose a reason for hiding this comment

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

µnit:

mkdir test/afl-inputs
AFLIN=$PWD/test/afl-inputs
...

Copy link
Member

Choose a reason for hiding this comment

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

nit: we could also add .gitignore entries for test/inputs, test/outputs and test/sync_dir

Copy link
Member Author

Choose a reason for hiding this comment

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

Well, this is just an example. There's no strong reason to make these directories inside the bitcoin repository.

@maflcko
Copy link
Member

maflcko commented Nov 25, 2016

Concept ACK 18b4c6c


To start the actual fuzzing use:
```
$AFLPATH/afl-fuzz -i ${AFLIN} -o ${AFLOUT} -- test/test_bitcoin_fuzzy
Copy link
Member

Choose a reason for hiding this comment

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

I think the default memory needs to be increased to prevent OOM?

Copy link
Member

@fanquake fanquake Nov 25, 2016

Choose a reason for hiding this comment

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

Which OS did you see out of memory errors on?
What did you need to increase it to to make it run?

Copy link
Member

Choose a reason for hiding this comment

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

I used the inputs by @laanwj (bitcoin_fuzzy_in.tar.xz) and the default of -m50 caused a failure in the dry run.

Copy link
Member

@maflcko maflcko Nov 25, 2016

Choose a reason for hiding this comment

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

Setting -m52 seems to be enough in this case. (OS: fedora 24)

@laanwj
Copy link
Member Author

laanwj commented Nov 25, 2016 via email

@fanquake
Copy link
Member

fanquake commented Nov 25, 2016

Some results. The "Master" instance is yet to complete a cycle (~62%), and the exec speed seems to have dropped off in the last few hours. Current stats:
screen shot 4
The other instances all have similar output, and have run through ~80cycles:
screen shot 5

@theuni
Copy link
Member

theuni commented Nov 25, 2016

tested ACK. Works well on OSX with AFL_NO_FORKSRV set (probably worth documenting that it's necessary there).

Also, feel free to take this as a simplification: theuni@88b8f92

@laanwj
Copy link
Member Author

laanwj commented Nov 26, 2016 via email

@pstratem
Copy link
Contributor

pstratem commented Nov 27, 2016

@fanquake if you completely remove the memory limit there are a few tests which can use nearly unbounded amounts of memory

I suggest running with:

export AFL_SKIP_CRASHES=1;
export AFL_PARAMETERS="-t 1000+ -m 1024";

afl-fuzz $AFL_PARAMETERS -i fuzzing/input -o fuzzing/output ./bitcoin/src/test/test_bitcoin_fuzzy

@fanquake
Copy link
Member

fanquake commented Nov 27, 2016

@pstratem Thanks for the suggestions. I've restarted some of the fuzzers with the new vars.

@fanquake
Copy link
Member

Wrapping up my testing of this. Results from individual fuzzers are below, and the sync_dir (outputs) as well as the inputs used are available for download.
inputs.zip
sync_dir.zip
Fuzzer 01 (deterministic tests):
fuzzer01
Fuzzer 02:
fuzzer02
Fuzzer 03:
fuzzer03
Fuzzer 04:
fuzzer04
Fuzzer 05 (restarted to up allocated memory and pass -t 1000):
fuzzer05
Total Output:

$AFLPATH/afl-whatsup sync_dir
status check tool for afl-fuzz by <lcamtuf@google.com>

Individual fuzzers
==================

>>> fuzzer01 (4 days, 23 hrs) <<<

  cycle 2, lifetime speed 114 execs/sec, path 297/1222 (24%)
  pending 0/935, coverage 6.22%, no crashes yet

>>> fuzzer02 (4 days, 23 hrs) <<<

  cycle 376, lifetime speed 165 execs/sec, path 87/1220 (7%)
  pending 0/0, coverage 6.22%, no crashes yet

>>> fuzzer03 (4 days, 23 hrs) <<<

  cycle 379, lifetime speed 166 execs/sec, path 114/1211 (9%)
  pending 0/0, coverage 6.22%, no crashes yet

>>> fuzzer04 (4 days, 23 hrs) <<<

  cycle 388, lifetime speed 166 execs/sec, path 1030/1211 (85%)
  pending 0/0, coverage 6.22%, no crashes yet

>>> fuzzer05 (2 days, 4 hrs) <<<

  cycle 161, lifetime speed 162 execs/sec, path 62/1227 (5%)
  pending 0/0, coverage 6.22%, no crashes yet

Summary stats
=============

       Fuzzers alive : 5
      Total run time : 22 days, 1 hours
         Total execs : 294 million
    Cumulative speed : 773 execs/sec
       Pending paths : 0 faves, 935 total
  Pending per fuzzer : 0 faves, 187 total (on average)
       Crashes found : 0 locally unique

@sipa
Copy link
Member

sipa commented Dec 1, 2016

Concept ACK

@maflcko
Copy link
Member

maflcko commented Dec 2, 2016

I think this ready for merge and we should select and add appropriate afl-inputs in another pull.

(Maybe fix the doc nits before merge?)

@laanwj
Copy link
Member Author

laanwj commented Dec 3, 2016

I think this ready for merge and we should select and add appropriate afl-inputs in another pull.

I don't think we should put the inputs in the repository. But I'll just add a link where they can be downloaded. Will fix the doc nits.

@pstratem
Copy link
Contributor

pstratem commented Dec 4, 2016

My current test cases are here http://strateman.ninja/fuzzing.tar.xz

@laanwj laanwj force-pushed the 2016_11_fuzzing_framework branch 2 times, most recently from 0152939 to 8e0550f Compare December 5, 2016 07:46
try
{
CTransaction tx;
ds >> tx;
Copy link
Member

Choose a reason for hiding this comment

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

error: ‘class CTransaction’ has no member named ‘Unserialize’

Copy link
Member Author

Choose a reason for hiding this comment

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

right, this should probably be converted to CMutableTransaction

@laanwj
Copy link
Member Author

laanwj commented Dec 15, 2016

Switched to the new way of transaction deserialization. This should be ready for merge now.

@laanwj laanwj merged commit 8b15434 into bitcoin:master Dec 15, 2016
laanwj added a commit that referenced this pull request Dec 15, 2016
8b15434 doc: Add bare-bones documentation for fuzzing (Wladimir J. van der Laan)
a4153e2 Simple fuzzing framework (Patrick Strateman)
@sipa
Copy link
Member

sipa commented Dec 15, 2016

utACK 8b15434 (apart from #9354).

PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request Aug 24, 2019
8b15434 doc: Add bare-bones documentation for fuzzing (Wladimir J. van der Laan)
a4153e2 Simple fuzzing framework (Patrick Strateman)
barrystyle pushed a commit to PACGlobalOfficial/PAC that referenced this pull request Jan 22, 2020
8b15434 doc: Add bare-bones documentation for fuzzing (Wladimir J. van der Laan)
a4153e2 Simple fuzzing framework (Patrick Strateman)
random-zebra added a commit to PIVX-Project/PIVX that referenced this pull request May 28, 2021
d059544 [Build] fuzz target, change LIBBITCOIN_ZEROCOIN link order. (furszy)
2396e6b [fuzz] Add ContextualCheckTransaction call to transaction target. (furszy)
f0887a0 Fuzzing documentation "PIVX-fication" (furszy)
9631f46 [doc] add sanitizers documentation in developer-notes.md (furszy)
70a0ace tests: Test serialisation as part of deserialisation fuzzing. Test round-trip equality where possible. Avoid code repetition. (practicalswift)
e1b92b6 ignore new fuzz targets gitignore (furszy)
d058d8c tests: Add deserialization fuzzing harnesses (furszy)
e1f666c tests: Remove TRANSACTION_DESERIALIZE (replaced by transaction fuzzer) (practicalswift)
b5f291c tests: Add fuzzing harness for CheckTransaction(...), IsStandardTx(...) and other CTransaction related functions (furszy)
3205871 fuzz: Remove option --export_coverage from test_runner (MarcoFalke)
52693ee fuzz: Add option to merge input dir to test runner (MarcoFalke)
2b4f8aa doc: Remove --disable-ccache from docs (MarcoFalke)
b54b1d6 tests: Improve test runner output in case of target errors (practicalswift)
cd6134f test: Log output even if fuzzer failed (MarcoFalke)
48cd0c8 doc: Improve fuzzing docs for macOS users (Fabian Jahr)
d642b67 [Build] Do not disable wallet when fuzz is enabled. (furszy)
c3447b5 Update doc and CI config (qmma)
1266d3e Disable other targets when enable-fuzz is set (qmma)
f28ac9a build: Allow to configure --with-sanitizers=fuzzer (MarcoFalke)
425742c fuzz: test_runner: Better error message when built with afl (MarcoFalke)
541f442 qa: Add test/fuzz/test_runner.py (MarcoFalke)
89fe5b2 Add missing LIBBITCOIN_ZMQ to test target (furszy)
58dbe79 add fuzzing binaries to gitignore. (furszy)
393a126 fuzz: Move deserialize tests to test/fuzz/deserialize.cpp (MarcoFalke)
a568df5 test: Build fuzz targets into separate executables (furszy)
d5dddde [test] fuzz: make test_one_input return void (MarcoFalke)
2e4ec58 [fuzzing] initialize chain params by default. (furszy)
08d8ebe [tests] Add libFuzzer support. (practicalswift)
84f72da [test] Speed up fuzzing by ~200x when using afl-fuzz (practicalswift)
faf2be6 Init ECC context for test_bitcoin_fuzzy. (Gregory Maxwell)
11150df Make fuzzer actually test CTxOutCompressor (Pieter Wuille)
d6f6a85 doc: Add bare-bones documentation for fuzzing (Wladimir J. van der Laan)
5c3b550 Simple fuzzing framework (pstratem)

Pull request description:

  As the title says, adding fuzzing framework support so we can start getting serious on this area as well.

  Adapted the following PRs:

  * bitcoin#9172.
  * bitcoin#9354.
  * bitcoin#9691.
  * bitcoin#10415.
  * bitcoin#10440.
  * bitcoin#15043.
  * bitcoin#15047.
  * bitcoin#15295.
  * bitcoin#15399 (fabcfa5 only).
  * bitcoin#16338.
  * bitcoin#17051.
  * bitcoin#17076.
  * bitcoin#17225.
  * bitcoin#17942.
  * bitcoin#16236 (only fa35c42).
  * bitcoin#18166 (only f2472f6).
  * bitcoin#18300.
  * And.. probably will go further and continue adapting more PRs..

ACKs for top commit:
  random-zebra:
    utACK d059544 and merging...

Tree-SHA512: c0b05bca47bf99bafd8abf1453c5636fe05df75f16d0e9c750368ea2aed8142f0b28d28af1d23468b8829188412a80fd3b7bdbbda294b940d78aec80c1c7d03a
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Sep 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants