Fuzzing support for Aptos
This crate contains support for fuzzing Aptos targets. This support sincludes:
- corpus generation with
proptest
- automatically running failing examples with
cargo test
Prerequisites
Install cargo-fuzz
if not already available: cargo install cargo-fuzz
.
Fuzzing a target
First, switch to the directory this README is in: cd testsuite/aptos-fuzzer
.
To list out known fuzz targets, run cargo run --bin aptos-fuzzer list
.
To be effective, fuzzing requires a corpus of existing inputs. This
crate contains support for generating corpuses with proptest
. Generate
a corpus with cargo run --bin aptos-fuzzer generate <target>
.
Once a corpus has been generated, the fuzzer is ready to use, simply run:
RUSTC_BOOTSTRAP=1 cargo run --bin aptos-fuzzer --release fuzz <target>
For more options, run cargo run --bin aptos-fuzzer -- --help
. Note that RUSTC_BOOTSTRAP=1
is
required as cargo fuzz
uses unstable compiler flags.
Adding a new target
Fuzz targets go in src/fuzz_targets/
. Adding a new target involves
creating a new type and implementing FuzzTargetImpl
for it.
For examples, see the existing implementations in src/fuzz_targets/
.
Remember to add your target to ALL_TARGETS
in src/fuzz_targets.rs
.
Once that has been done, cargo run --bin aptos-fuzzer list
should list your new target.
Debugging and testing artifacts
If the fuzzer finds a failing artifact, it will save the artifact to a
file inside the fuzz
directory and print its path. To add this
artifact to the test suite, copy it to a file inside
artifacts/<target>/
.
cargo test
will now test the deserializer against the new artifact.
The test will likely fail at first use.
Note that cargo test
runs each test in a separate process by default
to isolate failures and memory usage; if you're attaching a debugger and
are running a single test, set NO_FORK=1
to disable forking.
Once the deserializer has been fixed, check the artifact into the
artifacts/<target>/
directory. The artifact will then act as a
regression test in cargo test
runs.
There are two ways to reproduce an issue to investigate a finding:
- run the harness test (the code the fuzzer runs) directly
- run the fuzzer code
The following command (with your own artifact contained in a similar path) will run the harness test with your input:
cargo run --bin investigate -- -i artifacts/compiled_module/crash-5d7f403f
The following command will run libfuzzer on the relevant target with your input:
# build single fuzzer for target using instruction in the 'google oss-fuzz integration' section
./fuzzer input
Note that this should work out of the box for crashes,
but timeouts might need a -timeout 25
argument to libfuzzer,
and out of memory might need a -rss_limit_mb=2560
argumnent to libfuzzer.
See Google OSS-Fuzz's documentation on reproducing bugs as well.
Flamegraph
To obtain a flamegraph of a harness test, run the following command:
FUZZ_TARGET=compiled_module
It is good to first generate some corpus and run the fuzzer over it for a bit (to find new corpus). The larger corpus, the better flamegraph you will obtain.
Fuzzing Coverage
To test coverage of our fuzzers you can run the following command with grcov:
RUSTFLAGS='--cfg feature="fuzzing"' CORPUS_PATH=fuzz/corpus
Building a single fuzzer
To integrate our fuzzers with Google OSS-Fuzz project, we need to have one binary per fuzzer. This can also be handy when you want to analyze a fuzzer with tools like Instruments. For this, build.rs can create a fuzzer binary based on an environement variable. Use it as such:
Troubleshooting
My backtrace does not contain file names and line numbers
You need to use llvm-symbolizer
, see https://github.com/rust-fuzz/cargo-fuzz/issues/160
macOS: Linking with cc
failed
Make sure Xcode is updated to the latest version. Remeber to actually
xcode-select
the new app folder and cargo clean
before rebuilding again.
If you get a linker error like
# ...
|
= =
)
)
This is probably due to an issue in core-foundation-rs (https://github.com/servo/core-foundation-rs/pull/357)
that was fixed in the latest version, but one of our transitive dependencies
native-tls
only has the update in its master
branch. To fix this problem, add
the following to the end of aptos-core/Cargo.toml
:
[]
= { = "https://github.com/sfackler/rust-native-tls" }