-
Notifications
You must be signed in to change notification settings - Fork 37
fuzz: copy some more files from rust-bitcoin #285
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
Merged
apoelstra
merged 3 commits into
ElementsProject:master
from
apoelstra:2026-06/fix-fuzzing
Jun 29, 2026
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,7 @@ Cargo.lock | |
| *~ | ||
|
|
||
| #fuzz | ||
| fuzz/hfuzz_target | ||
| fuzz/hfuzz_workspace | ||
| fuzz/corpus | ||
| fuzz/artifacts | ||
| fuzz/*.log | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,161 @@ | ||
| # Fuzzing | ||
|
|
||
| `rust-bitcoin` has fuzzing harnesses setup for use with | ||
| `cargo-fuzz`. | ||
|
|
||
| To run the fuzz-tests as in CI -- briefly fuzzing every target -- simply | ||
| run | ||
|
|
||
| ```bash | ||
| ./fuzz.sh | ||
| ``` | ||
|
|
||
| in this directory. | ||
|
|
||
| By default, `fuzz.sh` runs each target for 100 seconds. Pass | ||
| `-max_total_time` to run for longer or shorter: | ||
|
|
||
| ```bash | ||
| ./fuzz.sh -max_total_time=300 | ||
| ``` | ||
|
|
||
| ## Fuzzing with weak cryptography | ||
|
|
||
| You may wish to replace the hashing and signing code with broken crypto, | ||
| which will be faster and enable the fuzzer to do otherwise impossible | ||
| things such as forging signatures or finding preimages to hashes. | ||
|
|
||
| Doing so may result in spurious bug reports since the broken crypto does | ||
| not respect the encoding or algebraic invariants upheld by the real crypto. We | ||
| would like to improve this, but it's a nontrivial problem -- though not | ||
| beyond the abilities of a motivated student with a few months of time. | ||
| Please let us know if you are interested in taking this on! | ||
|
|
||
| Meanwhile, to use the broken crypto, simply compile (and run the fuzzing | ||
| scripts) with | ||
|
|
||
| ```bash | ||
| RUSTFLAGS="--cfg=hashes_fuzz --cfg=secp256k1_fuzz" | ||
| ``` | ||
|
|
||
| which will replace the hashing library with broken hashes, and the | ||
| `secp256k1` library with broken cryptography. | ||
|
|
||
| Needless to say, NEVER COMPILE REAL CODE WITH THESE FLAGS because if a | ||
| fuzzer can break your crypto, so can anybody. | ||
|
|
||
| ## Long-term fuzzing | ||
|
|
||
| To see the full list of targets, the most straightforward way is to run | ||
|
|
||
| ```bash | ||
| cargo fuzz list | ||
| ``` | ||
|
|
||
| To run each of them for an hour, run | ||
|
|
||
| ```bash | ||
| ./cycle.sh | ||
| ``` | ||
| This script uses the `chrt` utility to try to reduce the priority of the | ||
| jobs. If you would like to run for longer, the most straightforward way | ||
| is to edit `cycle.sh` before starting. To run the fuzz-tests in parallel, | ||
| you will need to implement a custom harness. | ||
|
|
||
| To run a single fuzztest indefinitely, run | ||
|
|
||
| ```bash | ||
| cargo +nightly fuzz run "<target>" | ||
| ``` | ||
|
|
||
| ## Adding fuzz tests | ||
|
|
||
| All fuzz tests can be found in the `fuzz_target/` directory. Adding a new | ||
| one is as simple as copying an existing one and editing the `do_test` | ||
| function to do what you want. | ||
|
|
||
| If your test clearly belongs to a specific crate, please put it in that | ||
| crate's directory. Otherwise, you can put it directly in `fuzz_target/`. | ||
|
|
||
| If you need to add dependencies, edit the file `generate-files.sh` to add | ||
| it to the generated `Cargo.toml`. | ||
|
|
||
| Once you've added a fuzztest, regenerate the `Cargo.toml` and CI job by | ||
| running | ||
|
|
||
| ```bash | ||
| ./generate-files.sh | ||
| ``` | ||
|
|
||
| Then to test your fuzztest, run | ||
|
|
||
| ```bash | ||
| ./fuzz.sh <target> | ||
| ``` | ||
|
|
||
| If it is working, you will see a rapid stream of data for many seconds | ||
| (you can hit Ctrl+C to stop it early) that looks something like this: | ||
| ```text | ||
| INFO: Running with entropic power schedule (0xFF, 100). | ||
| INFO: Seed: 2953319389 | ||
| INFO: Loaded 1 modules (9121 inline 8-bit counters): 9121 [0x104132ea0, 0x104135241), | ||
| INFO: Loaded 1 PC tables (9121 PCs): 9121 [0x104135248,0x104158c58), | ||
| INFO: 0 files found in /some/path/to/rust-bitcoin/fuzz/corpus/units_arbitrary_weight | ||
| INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes | ||
| INFO: A corpus is not provided, starting from an empty corpus | ||
| #2 INITED cov: 42 ft: 42 corp: 1/1b exec/s: 0 rss: 36Mb | ||
| #411 NEW cov: 43 ft: 43 corp: 2/9b lim: 8 exec/s: 0 rss: 37Mb L: 8/8 MS: 4 ChangeBinInt-ShuffleBytes-ShuffleBytes-InsertRepeatedBytes- | ||
| #1329 NEW cov: 43 ft: 44 corp: 3/26b lim: 17 exec/s: 0 rss: 37Mb L: 17/17 MS: 3 InsertRepeatedBytes-CMP-CopyPart- DE: "\001\000\000\000"- | ||
| #1357 REDUCE cov: 43 ft: 44 corp: 3/25b lim: 17 exec/s: 0 rss: 37Mb L: 16/16 MS: 3 CopyPart-CMP-EraseBytes- DE: "\000\000\000\000\000\000\000\000"- | ||
| ... | ||
| ``` | ||
| If you don't see this, you should quickly see an error. | ||
|
|
||
| ## Reproducing Failures | ||
|
|
||
| If a fuzztest fails, it will exit with a summary which looks something like | ||
| ```text | ||
| ... | ||
| thread '<unnamed>' (3001874) panicked at units/src/weight.rs:103:25: | ||
| attempt to multiply with overflow | ||
| note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace | ||
| ==66478== ERROR: libFuzzer: deadly signal | ||
| #0 0x0001049fd3c4 in __sanitizer_print_stack_trace+0x28 (librustc-nightly_rt.asan.dylib:arm64+0x5d3c4) | ||
| #1 0x000104078b90 in fuzzer::PrintStackTrace()+0x30 (units_arbitrary_weight:arm64+0x100070b90) | ||
| #2 0x00010406d074 in fuzzer::Fuzzer::CrashCallback()+0x54 (units_arbitrary_weight:arm64+0x100065074) | ||
| #3 0x000180d26740 in _sigtramp+0x34 (libsystem_platform.dylib:arm64+0x3740) | ||
| ... | ||
| ``` | ||
| This will tell you where the test failed and is followed by information about how to reproduce the crash. | ||
| It will look something like this: | ||
|
|
||
| ```text | ||
| ... | ||
| NOTE: libFuzzer has rudimentary signal handlers. | ||
| Combine libFuzzer with AddressSanitizer or similar for better crash reports. | ||
| SUMMARY: libFuzzer: deadly signal | ||
| MS: 2 ChangeByte-CopyPart-; base unit: 25058c6b0d02cd1d71a030ad61c46b7396ddcdb9 | ||
| 0x5e,0x5e,0x5e,0x5e,0x5e,0x44,0x0,0x0,0x0,0x0,0x0,0x5d,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x5e,0xa,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0xa5,0x1,0x1,0x1, | ||
| ^^^^^D\000\000\000\000\000]\001\000\000\000\000\000\000^\012\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\245\001\001\001 | ||
| artifact_prefix='/some/path/to/rust-bitcoin/fuzz/artifacts/units_arbitrary_weight/'; Test unit written to /some/path/to/rust-bitcoin/fuzz/artifacts/units_arbitrary_weight/crash-1b454523d38a6c3f45d453dfea4099f3cb574822 | ||
| Base64: Xl5eXl5EAAAAAABdAQAAAAAAAF4KAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBpQEBAQ== | ||
| ──────────────────────────────────────────────────────────────────────────────── | ||
|
|
||
| Failing input: | ||
|
|
||
| fuzz/artifacts/units_arbitrary_weight/crash-1b454523d38a6c3f45d453dfea4099f3cb574822 | ||
|
|
||
| Output of `std::fmt::Debug`: | ||
|
|
||
| [94, 94, 94, 94, 94, 68, 0, 0, 0, 0, 0, 93, 1, 0, 0, 0, 0, 0, 0, 94, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 165, 1, 1, 1] | ||
|
|
||
| Reproduce with: | ||
|
|
||
| cargo fuzz run units_arbitrary_weight fuzz/artifacts/units_arbitrary_weight/crash-1b454523d38a6c3f45d453dfea4099f3cb574822 | ||
|
|
||
| Minimize test case with: | ||
|
|
||
| cargo fuzz tmin units_arbitrary_weight fuzz/artifacts/units_arbitrary_weight/crash-1b454523d38a6c3f45d453dfea4099f3cb574822 | ||
|
|
||
| ──────────────────────────────────────────────────────────────────────────────── | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| #!/usr/bin/env bash | ||
|
|
||
| # Continuously cycle over fuzz targets running each for 1 hour. | ||
| # It uses chrt SCHED_IDLE so that other process takes priority. | ||
| # | ||
| # For cargo-fuzz usage see https://github.com/rust-fuzz/cargo-fuzz?tab=readme-ov-file#usage | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| REPO_DIR=$(git rev-parse --show-toplevel) | ||
| # can't find the file because of the ENV var | ||
| # shellcheck source=/dev/null | ||
| source "$REPO_DIR/fuzz/fuzz-util.sh" | ||
|
|
||
| while : | ||
| do | ||
| for targetFile in $(listTargetFiles); do | ||
| targetName=$(targetFileToName "$targetFile") | ||
| echo "Fuzzing target $targetName ($targetFile)" | ||
|
|
||
| # fuzz for one hour | ||
| chrt -i 0 cargo +nightly fuzz run "$targetName" -- -max_total_time=3600 | ||
| cargo +nightly fuzz cmin "$targetName" | ||
| done | ||
| done | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| #!/usr/bin/env bash | ||
| # This script is used to briefly fuzz every target when no target is provided. Otherwise, it will briefly fuzz the | ||
| # provided target | ||
|
|
||
| set -euox pipefail | ||
|
|
||
| REPO_DIR=$(git rev-parse --show-toplevel) | ||
|
|
||
| # can't find the file because of the ENV var | ||
| # shellcheck source=/dev/null | ||
| source "$REPO_DIR/fuzz/fuzz-util.sh" | ||
|
|
||
| target= | ||
| max_total_time=100 | ||
|
|
||
| for arg in "$@"; do | ||
| case "$arg" in | ||
| -max_total_time=*) | ||
| max_total_time="${arg#-max_total_time=}" | ||
| ;; | ||
| -*) | ||
| echo "Unknown option: $arg" | ||
| exit 2 | ||
| ;; | ||
| *) | ||
| if [ -n "$target" ]; then | ||
| echo "Unexpected argument: $arg" | ||
| exit 2 | ||
| fi | ||
| target="$arg" | ||
| ;; | ||
| esac | ||
| done | ||
|
|
||
| case "$max_total_time" in | ||
| ''|*[!0-9]*) | ||
| echo "-max_total_time must be a non-negative integer number of seconds" | ||
| exit 2 | ||
| ;; | ||
| esac | ||
|
|
||
| # Check that input files are correct Windows file names | ||
| checkWindowsFiles | ||
|
|
||
| if [ -z "$target" ]; then | ||
| targetFiles="$(listTargetFiles)" | ||
| else | ||
| targetFiles=fuzz_targets/"$target".rs | ||
| fi | ||
|
|
||
| cargo --version | ||
| rustc --version | ||
|
|
||
| # Testing | ||
| cargo install --force --locked --version 0.12.0 cargo-fuzz | ||
| for targetFile in $targetFiles; do | ||
| targetName=$(targetFileToName "$targetFile") | ||
| echo "Fuzzing target $targetName ($targetFile) for $max_total_time seconds" | ||
| # cargo-fuzz will check for the corpus at fuzz/corpus/<target> | ||
| cargo +nightly fuzz run "$targetName" -- -max_total_time="$max_total_time" | ||
| checkReport "$targetName" | ||
| done |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: can be done in a follow-up if necessary
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do in a followup so we can get the CI job running (or not) ASAP.