feat(fuzz): add message_decoding_invariants oracle and target#1320
Open
Greg Lamberson (glamberson) wants to merge 1 commit into
Open
feat(fuzz): add message_decoding_invariants oracle and target#1320Greg Lamberson (glamberson) wants to merge 1 commit into
Greg Lamberson (glamberson) wants to merge 1 commit into
Conversation
This was referenced May 26, 2026
6a66a60 to
d77c3b3
Compare
Member
There was a problem hiding this comment.
Thank you!
This is looking good to me. My only suggestion here would be to make the patch more "self-contained":
Implements #1124 task 2 (
message_decoding_invariants). Companion topdu_round_trip(#1124 task 1)
Gets much less relevant after the work is merged, and we only care about the final shape of the code
Member
|
#1313 got merged! |
Contributor
Author
|
You're right that the ticket-numbered framing in the doc-comment doesn't earn its space after the PR lands. I stripped the prefix that pointed at #1124 task 2 and #1291 task 1. I rewrote the bug-class contrast that followed it so it stands on its own. I also rewrote the parallel referential framing in the commit-message body for the same reason. |
This PR adds an assertion-based oracle that checks the `Encode::size()` soundness contract on every decoder-accepted input. The asserted property is `pdu.size() == encode_vec(&pdu).len()`. The `Encode` trait's `size()` is the contract caller code relies on for buffer sizing (`ensure_size!`, `cast_length!`, downstream allocations). A size that lies about its own length produces under-allocation (truncated encode) or over-allocation (wasted memory and buffer-overflow risk depending on surrounding context). The workspace already asserts this property against known-good byte fixtures in `ironrdp-testsuite-core/tests/pdu/rdp.rs::buffer_length_is_correct_for_*`. This oracle extends the assertion across the fuzz input surface. This oracle differs from `pdu_round_trip` in two ways: - `pdu_round_trip` silently drops `Err` results. It catches panics only. - `message_decoding_invariants` asserts the size contract. A violation aborts the fuzz iteration as a libFuzzer crash. The bug-reporting mechanism follows the oracle module's documentation. This oracle catches the following bug classes that `pdu_round_trip` does not: - `Encode::size()` returns N but `encode` writes M, where M does not equal N. Callers then over-allocate or under-allocate buffers. - The encoder cannot reconstruct decode-acceptable bytes to the same length, which means decode loses framing structure. This oracle does not catch the following bug classes, which other oracles cover: - `pdu_decode` covers decode-time panics and OOM. - `pdu_round_trip` covers re-decode equality after round-trip via its silent-drop pattern. Assertion-based re-decode stays out of scope here to keep this oracle's failure mode unambiguous. Type coverage matches `pdu_round_trip`. The cohort includes `capability_sets::CapabilitySet` and `headers::ShareControlHeader`. The latter transits through `CapabilitySet`'s encoder via the Active variants. The same encoder path exercises both types. The new target auto-discovers into CI via the `cargo xtask fuzz list` dynamic fan-out mechanism. The test plan covers two checks. First, all five `cargo xtask check fmt/lints/tests/typos/locks` gates pass on the post-rebase head. Second, the new `check_message_decoding_invariants` regression-replay test in `crates/ironrdp-testsuite-core/tests/fuzz_regression.rs` passes against the seed corpus. This PR refs the Devolutions#1120 fuzzing umbrella. The PR also closes Devolutions#1124.
d77c3b3 to
e67ca25
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.
This PR adds an assertion-based oracle that checks the
Encode::size()soundness contract on every decoder-accepted input. The asserted
property is
pdu.size() == encode_vec(&pdu).len().The
Encodetrait'ssize()is the contract caller code relies on forbuffer sizing (
ensure_size!,cast_length!, downstream allocations).A size that lies about its own length produces under-allocation
(truncated encode) or over-allocation (wasted memory and
buffer-overflow risk depending on surrounding context). The workspace
already asserts this property against known-good byte fixtures in
ironrdp-testsuite-core/tests/pdu/rdp.rs::buffer_length_is_correct_for_*.This oracle extends the assertion across the fuzz input surface.
This oracle differs from
pdu_round_tripin two ways:pdu_round_tripsilently dropsErrresults. It catches panicsonly.
message_decoding_invariantsasserts the size contract. A violationaborts the fuzz iteration as a libFuzzer crash. The bug-reporting
mechanism follows the oracle module's documentation.
This oracle catches the following bug classes that
pdu_round_tripdoes not:
Encode::size()returns N butencodewrites M, where M does notequal N. Callers then over-allocate or under-allocate buffers.
length, which means decode loses framing structure.
This oracle does not catch the following bug classes, which other
oracles cover:
pdu_decodecovers decode-time panics and OOM.pdu_round_tripcovers re-decode equality after round-trip via itssilent-drop pattern. Assertion-based re-decode stays out of scope
here to keep this oracle's failure mode unambiguous.
Type coverage matches
pdu_round_trip. The cohort includescapability_sets::CapabilitySetandheaders::ShareControlHeader.The latter transits through
CapabilitySet's encoder via the Activevariants. The same encoder path exercises both types.
The new target auto-discovers into CI via the
cargo xtask fuzz listdynamic fan-out mechanism.
The test plan covers two checks. First, all five
cargo xtask check fmt/lints/tests/typos/locksgates pass on thepost-rebase head. Second, the new
check_message_decoding_invariantsregression-replay test in
crates/ironrdp-testsuite-core/tests/fuzz_regression.rspassesagainst the seed corpus.
This PR refs the #1120 fuzzing umbrella. The PR also closes #1124.