3.4 KiB
irtt-rs fuzzing
Coverage-guided fuzzing of irtt-proto wire decoders and irtt-server's public
ServerCore::handle_datagram API 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 |
server_core_datagrams |
A bounded sequence of datagrams against one ServerCore, with varied IPv4/IPv6 peers and session/HMAC configuration; it asserts the session cap after every datagram |
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 (MAX_INPUT_LEN in each harness) so libFuzzer
spends its time exploring protocol structure rather than allocating/copying
megabytes. server_core_datagrams additionally caps its sequence length and
each individual datagram and configures the core to the same packet cap, so one
libFuzzer input cannot become a tiny DoS benchmark.
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.