Move beyond “bytes-only decode fuzzing” to higher-signal fuzzing that asserts invariants and exercises state machines.
Proposed fuzz targets
- round_trip (typed):
- Generate a structured PDU (
Arbitrary)
- Encode -> Decode -> Compare (plus size invariants)
- message_decoding_invariants (bytes):
- Feed raw bytes into decoder(s)
- If decoding succeeds, assert framing/size/consumption invariants
- connector_state_machine (optional in this issue; can be a follow-up):
- Generate sequences / frames and step connector state machines
- Validate buffer bookkeeping and hint-based framing invariants
Tasks
- Add
round_trip fuzz target wired to an oracle module
- Add at least one non-trivial oracle invariant (not just “no panic”)
- Ensure targets can be run via
cargo xtask fuzz run <target>
- Add regression test mechanism: replay minimized crashers in unit tests
“Round-trip” oracle (typed fuzzing)
This is a high signal harness: generate a structured PDU, encode it, decode it back, compare.
Fuzz target (tiny):
#![no_main]
use libfuzzer_sys::fuzz_target;
use ironrdp_fuzzing::{generators::AnyPdu, oracles};
fuzz_target!(|msg: AnyPdu<'_>| {
oracles::round_trip(msg);
});
Generator idea (AnyPdu<'a>):
Oracle idea:
- encode
- decode_owned
assert_eq!(decoded, original.into_owned())
- also assert size invariants (
encoded.len() == original.size()) where applicable
This is the harness that typically finds:
- wrong length computations
- missing fields in encode/decode
- decode accepting invalid encodings (or encode producing something decode can’t parse)
“Message decoding” oracle (raw bytes, but with invariants)
We keep a raw-bytes decoder too, but it should assert invariants, e.g.:
- if decoding succeeds, then “frame-size detection” should succeed and be consistent
- if decode consumes N bytes, that should match computed/expected sizes
- avoid silent under/over-reads
This is especially valuable for:
- frame boundary logic
- “find size” / “hint” logic
- partial frame handling
State-machine fuzzing (connector sequences)
We also want fuzzing that targets state machines (connector / acceptor / channel sequences), not just stateless PDUs.
The typical pattern:
-
generate a connector + an input payload
-
capture the connector’s “expected next PDU hint”
-
call step(payload, out_buf)
-
if it succeeds:
- verify output length bookkeeping is correct (buffer length matches returned “written length”)
- verify that the hint can indeed determine a frame length for
payload (since the step succeeded)
We can start with “single-step” fuzzing and later move to “multi-step” inputs (a sequence of frames) to reach deeper states.
Acceptance criteria
- Oracles assert invariants (round-trip equality and/or framing invariants)
- Running the fuzz target locally is documented
Move beyond “bytes-only decode fuzzing” to higher-signal fuzzing that asserts invariants and exercises state machines.
Proposed fuzz targets
Arbitrary)Tasks
round_tripfuzz target wired to an oracle modulecargo xtask fuzz run <target>“Round-trip” oracle (typed fuzzing)
This is a high signal harness: generate a structured PDU, encode it, decode it back, compare.
Fuzz target (tiny):
Generator idea (
AnyPdu<'a>):an enum that contains a curated set of PDUs we want to round-trip (start small; expand over time).
it should provide:
encode()(toVec<u8>)decode_owned(bytes)(back into an owned representation)into_owned()for comparisonOracle idea:
assert_eq!(decoded, original.into_owned())encoded.len() == original.size()) where applicableThis is the harness that typically finds:
“Message decoding” oracle (raw bytes, but with invariants)
We keep a raw-bytes decoder too, but it should assert invariants, e.g.:
This is especially valuable for:
State-machine fuzzing (connector sequences)
We also want fuzzing that targets state machines (connector / acceptor / channel sequences), not just stateless PDUs.
The typical pattern:
generate a connector + an input payload
capture the connector’s “expected next PDU hint”
call
step(payload, out_buf)if it succeeds:
payload(since the step succeeded)We can start with “single-step” fuzzing and later move to “multi-step” inputs (a sequence of frames) to reach deeper states.
Acceptance criteria