tests: add fuzzing support with a packet parser target - #502
Merged
Merged
Conversation
Adds cargo-fuzz scaffolding under fuzz/ and a first target, parse_packet,
covering DnsIncoming::new. ServiceDaemon hands that function the bytes it
reads off a UDP socket without inspecting them first, so every byte it
touches is reachable by any host on the link.
dns_parser is a private module, so a fuzz target -- a separate crate --
cannot call it. The new unstable-fuzz-api feature exposes src/fuzz_api.rs,
a #[doc(hidden)] module of thin wrappers, rather than widening the
visibility of dns_parser itself. It is not public API and carries no
stability guarantee.
The target checks invariants, not just the absence of panics: a parsed
message must agree with its own header counts, and must be exactly one of
a query or a response. It also renders the error of a rejected packet and
the Debug of an accepted one, since both format slices of the raw packet.
Running it needs no arguments:
cargo +nightly fuzz run parse_packet
cargo-fuzz supplies the corpus directory and artifact prefix itself. A
dictionary and an explicit -max_len were both tried and dropped: over
30-second cold starts neither moved coverage outside noise. DnsIncoming::new
has no size-dependent branch -- MAX_PKT_ABSOLUTE_IPV4 bounds the encoder,
not the parser -- so libFuzzer's default 4096-byte cap costs nothing here.
A later target that exercises to_packets would want -max_len=8972.
CI gains a fuzz job that builds the targets on nightly without running a
campaign. clippy --all-features already covers src/fuzz_api.rs, but nothing
else built fuzz/Cargo.toml or the targets, so they could break unnoticed.
The first run of this target found a remotely-triggerable panic, an HINFO
record with RDLENGTH 0 at the end of a message, fixed in #499 and covered
there by a regression test that runs on stable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
keepsimple1
force-pushed
the
add-fuzzing
branch
from
September 5, 2026 04:22
16ddd0a to
0bbfd07
Compare
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
What
Adds [
cargo-fuzz] scaffolding underfuzz/and a first target,parse_packet, coveringDnsIncoming::new.That function is the crate's main attack surface:
ServiceDaemon::handle_readpasses it the bytes it reads off a UDP socket from potentially any host over the network.Reaching crate internals
dns_parseris a private module, so a fuzz target — a separate crate — cannot call it. Rather than makingDnsIncomingpublic, this adds anunstable-fuzz-apifeature that exposessrc/fuzz_api.rs, a#[doc(hidden)]module of thin wrappers.cargo packagestill excludesfuzz/entirely, so publishing is unaffected.The target
parse_packetchecks invariants, not just panicsA packet that parses must agree with its own header: the question count is exact, the authority and additional counts are upper bounds (a record with malformed RDATA is skipped, so those can legitimately come up short), and a message is exactly one of a query or a response. It also renders the error of a rejected packet and the
Debugof an accepted one, since both format slices of the raw packet.No corpus files are committed
CI is updated to include a simple fuzz build, no actual fuzzing run