2020-04-10 10:28:45 +02:00
|
|
|
# Fuzzing
|
|
|
|
|
2024-11-06 14:27:26 +01:00
|
|
|
Fuzz tests generate a ton of random parameter arguments to the program and then validate that none
|
2023-11-03 01:45:38 +01:00
|
|
|
cause it to crash.
|
2020-04-10 10:28:45 +02:00
|
|
|
|
|
|
|
## How does it work?
|
|
|
|
|
2023-11-03 01:45:38 +01:00
|
|
|
Typically, CI will run `ci-fuzz.sh` on one of the environments the automated tests are
|
2024-11-06 14:27:26 +01:00
|
|
|
configured for. Fuzzing is further only effective with a lot of CPU time, indicating that if crash
|
2023-11-03 01:45:38 +01:00
|
|
|
scenarios are discovered on CI with its low runtime constraints, the crash is caused relatively
|
|
|
|
easily.
|
2020-04-10 10:28:45 +02:00
|
|
|
|
|
|
|
## How do I run fuzz tests locally?
|
|
|
|
|
2024-11-06 14:27:26 +01:00
|
|
|
We support multiple fuzzing engines such as `honggfuzz`, `libFuzzer` and `AFL`. You typically won't
|
|
|
|
need to run the entire suite of different fuzzing tools. For local execution, `honggfuzz`should be
|
|
|
|
more than sufficient.
|
2020-04-10 10:28:45 +02:00
|
|
|
|
|
|
|
### Setup
|
2023-11-03 01:45:38 +01:00
|
|
|
#### Honggfuzz
|
2020-04-10 10:28:45 +02:00
|
|
|
To install `honggfuzz`, simply run
|
|
|
|
|
|
|
|
```shell
|
2020-04-10 20:22:46 +02:00
|
|
|
cargo update
|
2020-04-11 02:15:12 +02:00
|
|
|
cargo install --force honggfuzz
|
2020-04-10 10:28:45 +02:00
|
|
|
```
|
|
|
|
|
2022-05-05 02:34:35 +02:00
|
|
|
In some environments, you may want to pin the honggfuzz version to `0.5.52`:
|
|
|
|
|
|
|
|
```shell
|
|
|
|
cargo update -p honggfuzz --precise "0.5.52"
|
|
|
|
cargo install --force honggfuzz --version "0.5.52"
|
|
|
|
```
|
|
|
|
|
2023-11-03 01:45:38 +01:00
|
|
|
#### cargo-fuzz / libFuzzer
|
|
|
|
To install `cargo-fuzz`, simply run
|
|
|
|
|
|
|
|
```shell
|
|
|
|
cargo update
|
|
|
|
cargo install --force cargo-fuzz
|
|
|
|
```
|
|
|
|
|
2020-04-10 10:28:45 +02:00
|
|
|
### Execution
|
|
|
|
|
2023-11-03 01:45:38 +01:00
|
|
|
#### Honggfuzz
|
|
|
|
To run fuzzing using `honggfuzz`, do
|
2020-04-10 10:28:45 +02:00
|
|
|
|
|
|
|
```shell
|
|
|
|
export CPU_COUNT=1 # replace as needed
|
2020-04-10 20:22:46 +02:00
|
|
|
export HFUZZ_BUILD_ARGS="--features honggfuzz_fuzz"
|
2020-04-10 10:28:45 +02:00
|
|
|
export HFUZZ_RUN_ARGS="-n $CPU_COUNT --exit_upon_crash"
|
|
|
|
|
2020-04-10 20:22:46 +02:00
|
|
|
export TARGET="msg_ping_target" # replace with the target to be fuzzed
|
2022-05-05 02:34:35 +02:00
|
|
|
cargo hfuzz run $TARGET
|
2020-04-10 10:28:45 +02:00
|
|
|
```
|
|
|
|
|
2022-05-05 02:34:35 +02:00
|
|
|
(Or, for a prettier output, replace the last line with `cargo --color always hfuzz run $TARGET`.)
|
|
|
|
|
2023-11-03 01:45:38 +01:00
|
|
|
#### cargo-fuzz / libFuzzer
|
|
|
|
To run fuzzing using `cargo-fuzz / libFuzzer`, run
|
|
|
|
|
|
|
|
```shell
|
|
|
|
rustup install nightly # Note: libFuzzer requires a nightly version of rust.
|
|
|
|
cargo +nightly fuzz run --features "libfuzzer_fuzz" msg_ping_target
|
|
|
|
```
|
2024-11-06 14:27:26 +01:00
|
|
|
Note: If you encounter a `SIGKILL` during run/build check for OOM in kernel logs and consider
|
2023-11-03 01:45:38 +01:00
|
|
|
increasing RAM size for VM.
|
|
|
|
|
|
|
|
If you wish to just generate fuzzing binary executables for `libFuzzer` and not run them:
|
2024-11-06 14:27:26 +01:00
|
|
|
```shell
|
|
|
|
cargo +nightly fuzz build --features "libfuzzer_fuzz" msg_ping_target
|
2023-11-03 01:45:38 +01:00
|
|
|
# Generates binary artifact in path ./target/aarch64-unknown-linux-gnu/release/msg_ping_target
|
|
|
|
# Exact path depends on your system architecture.
|
|
|
|
```
|
|
|
|
You can upload the build artifact generated above to `ClusterFuzz` for distributed fuzzing.
|
|
|
|
|
|
|
|
### List Fuzzing Targets
|
2020-04-10 20:22:46 +02:00
|
|
|
To see a list of available fuzzing targets, run:
|
|
|
|
|
|
|
|
```shell
|
|
|
|
ls ./src/bin/
|
|
|
|
```
|
|
|
|
|
2023-11-03 01:45:38 +01:00
|
|
|
## A fuzz test failed, what do I do?
|
2020-04-10 10:28:45 +02:00
|
|
|
|
2024-11-06 14:27:26 +01:00
|
|
|
You're trying to create a PR, but need to find the underlying cause of that pesky fuzz failure
|
2023-11-03 01:45:38 +01:00
|
|
|
blocking the merge?
|
2020-04-10 10:28:45 +02:00
|
|
|
|
|
|
|
Worry not, for this is easily traced.
|
|
|
|
|
2023-11-03 01:45:38 +01:00
|
|
|
If your output log looks like this:
|
2020-04-10 10:28:45 +02:00
|
|
|
|
|
|
|
```
|
|
|
|
Size:639 (i,b,hw,ed,ip,cmp): 0/0/0/0/0/1, Tot:0/0/0/2036/5/28604
|
|
|
|
Seen a crash. Terminating all fuzzing threads
|
|
|
|
|
|
|
|
… # a lot of lines in between
|
|
|
|
|
2023-11-03 01:45:38 +01:00
|
|
|
<0x0000555555565559> [func:UNKNOWN file: line:0 module:./rust-lightning/fuzz/hfuzz_target/x86_64-unknown-linux-gnu/release/full_stack_target]
|
2020-04-10 10:28:45 +02:00
|
|
|
<0x0000000000000000> [func:UNKNOWN file: line:0 module:UNKNOWN]
|
|
|
|
=====================================================================
|
|
|
|
2d3136383734090101010101010101010101010101010101010101010101
|
|
|
|
010101010100040101010101010101010101010103010101010100010101
|
|
|
|
0069d07c319a4961
|
2023-11-03 01:45:38 +01:00
|
|
|
The command "if [ "$(rustup show | grep default | grep stable)" != "" ]; then cd fuzz && cargo test --verbose && ./ci-fuzz.sh; fi" exited with 1.
|
2020-04-10 10:28:45 +02:00
|
|
|
```
|
|
|
|
|
2020-04-11 02:15:12 +02:00
|
|
|
Note that the penultimate stack trace line ends in `release/full_stack_target]`. That indicates that
|
2024-11-06 14:27:26 +01:00
|
|
|
the failing target was `full_stack`. To reproduce the error locally, simply copy the hex,
|
2020-04-11 02:15:12 +02:00
|
|
|
and run the following from the `fuzz` directory:
|
2020-04-10 10:28:45 +02:00
|
|
|
|
|
|
|
```shell
|
2020-04-11 02:15:12 +02:00
|
|
|
export TARGET="full_stack" # adjust for your output
|
2020-04-10 10:28:45 +02:00
|
|
|
export HEX="2d3136383734090101010101010101010101010101010101010101010101\
|
|
|
|
010101010100040101010101010101010101010103010101010100010101\
|
|
|
|
0069d07c319a4961" # adjust for your output
|
2020-04-11 02:15:12 +02:00
|
|
|
|
|
|
|
mkdir -p ./test_cases/$TARGET
|
|
|
|
echo $HEX | xxd -r -p > ./test_cases/$TARGET/any_filename_works
|
2020-04-10 10:28:45 +02:00
|
|
|
|
|
|
|
export RUST_BACKTRACE=1
|
2024-11-06 14:27:26 +01:00
|
|
|
export RUSTFLAGS="--cfg=fuzzing --cfg=secp256k1_fuzz --cfg=hashes_fuzz"
|
2020-04-10 10:28:45 +02:00
|
|
|
cargo test
|
|
|
|
```
|
|
|
|
|
2024-11-06 14:27:26 +01:00
|
|
|
Note that if the fuzz test failed locally, moving the offending run's trace
|
2022-05-05 02:34:35 +02:00
|
|
|
to the `test_cases` folder should also do the trick; simply replace the `echo $HEX |` line above
|
|
|
|
with (the trace file name is of course a bit longer than in the example):
|
|
|
|
|
|
|
|
```shell
|
|
|
|
mv hfuzz_workspace/fuzz_target/SIGABRT.PC.7ffff7e21ce1.STACK.[…].fuzz ./test_cases/$TARGET/
|
|
|
|
```
|
|
|
|
|
2020-04-11 20:33:07 +02:00
|
|
|
This will reproduce the failing fuzz input and yield a usable stack trace.
|
2022-05-05 02:34:35 +02:00
|
|
|
|
|
|
|
|
|
|
|
## How do I add a new fuzz test?
|
|
|
|
|
2024-11-06 14:27:26 +01:00
|
|
|
1. The easiest approach is to take one of the files in `fuzz/src/`, such as
|
|
|
|
`process_network_graph.rs`, and duplicate it, renaming the new file to something more
|
|
|
|
suitable. For the sake of example, let's call the new fuzz target we're creating
|
2022-05-05 02:34:35 +02:00
|
|
|
`my_fuzzy_experiment`.
|
|
|
|
|
|
|
|
2. In the newly created file `fuzz/src/my_fuzzy_experiment.rs`, run a string substitution
|
|
|
|
of `process_network_graph` to `my_fuzzy_experiment`, such that the three methods in the
|
|
|
|
file are `do_test`, `my_fuzzy_experiment_test`, and `my_fuzzy_experiment_run`.
|
|
|
|
|
|
|
|
3. Adjust the body (not the signature!) of `do_test` as necessary for the new fuzz test.
|
|
|
|
|
2024-11-06 14:27:26 +01:00
|
|
|
4. In `fuzz/src/bin/gen_target.sh`, add a line reading `GEN_TEST my_fuzzy_experiment` to the
|
2022-05-05 02:34:35 +02:00
|
|
|
first group of `GEN_TEST` lines (starting in line 9).
|
|
|
|
|
|
|
|
5. If your test relies on a new local crate, add that crate as a dependency to `fuzz/Cargo.toml`.
|
|
|
|
|
2024-11-06 14:27:26 +01:00
|
|
|
6. In `fuzz/src/lib.rs`, add the line `pub mod my_fuzzy_experiment`. Additionally, if
|
2022-05-05 02:34:35 +02:00
|
|
|
you added a new crate dependency, add the `extern crate […]` import line.
|
|
|
|
|
|
|
|
7. Run `fuzz/src/bin/gen_target.sh`.
|
|
|
|
|
|
|
|
8. There is no step eight: happy fuzzing!
|