Add isolated cargo-fuzz/libFuzzer infrastructure for irtt-proto, fuzzing decode_request, decode_open_reply, decode_echo_reply, Params::decode(_with_presence), and the varint codec against arbitrary and structurally-derived wire input. Each target's core invariant is that arbitrary bytes must never panic; a small clean-room seed corpus (generated from irtt-proto's own encoders) and a bounded nightly smoke CI workflow are included. The fuzz project is its own isolated cargo workspace and does not affect the root workspace, its lockfile, or any published crate's dependency graph.
3.0 KiB
irtt-proto fuzzing
Coverage-guided fuzzing of irtt-proto's wire decoders via
cargo-fuzz/libFuzzer.
This project is intentionally isolated from the normal stable/MSRV
workspace: it lives in its own [workspace] under fuzz/, is never a member
of the root workspace, requires nightly Rust, and is not built by
cargo check/test/clippy/doc at the workspace root.
Prerequisites
- nightly Rust (
rustup toolchain install nightly) cargo-fuzz(cargo install cargo-fuzz --locked --version 0.13.1)
Targets
| Target | Exercises |
|---|---|
decode_request |
decode_request, Params::decode on a decoded Open, verify_packet_hmac |
decode_open_reply |
decode_open_reply, unauthenticated and HMAC-authenticated |
decode_echo_reply |
decode_echo_reply against a deterministic, bounded Params matrix, unauthenticated and HMAC-authenticated |
decode_params |
Params::decode and Params::decode_with_presence, plus an encode/decode round trip |
decode_varint |
varint::decode_uvarint/decode_varint and their round trip through encode_uvarint/encode_varint |
The invariant every target asserts is: arbitrary bytes must never panic.
Returning Err is normal and expected; a successful decode is also normal.
Every target bounds its input to 128 KiB (MAX_INPUT_LEN in each harness) so
libFuzzer spends its time exploring protocol structure rather than
allocating/copying megabytes — production IRTT datagrams are UDP-sized, well
under this bound.
Running
cargo +nightly fuzz run decode_request
Bounded smoke run, e.g. 30 seconds:
cargo +nightly fuzz run decode_request -- -max_total_time=30
Build every target without running:
cargo +nightly fuzz build
Corpus
Seed corpora live under fuzz/corpus/<target>/. They were generated once
from irtt-proto's own public encoders (encode_request, encode_open_reply,
encode_echo_reply, Params::encode) by a throwaway local script, not copied
from any external source, and not derived from upstream heistp/irtt. Each
file is a small, representative wire packet (minimal Open, Close, Echo, HMAC
variants, ordinary/recv-count/recv-window/midpoint Echo replies, and a few
Params payloads including an unknown tag and server_fill).
Crash artifacts
A failing case is written under fuzz/artifacts/<target>/. To replay it:
cargo +nightly fuzz run decode_request fuzz/artifacts/decode_request/<crash-file>
Isolation notes
fuzz/Cargo.tomldeclares its own[workspace], so it is never picked up by the root[workspace]in../Cargo.toml.libfuzzer-sysandarbitraryare fuzz-only dependencies; they never appear in any published crate's dependency graph.fuzz/Cargo.lockis committed for reproducible fuzzing builds, independent of the rootCargo.lock.