Repository navigation
fix(rdpsnd): echo the Training PDU's wPackSize in the Training Confirm - #2019
meanaverage (meanaverage) wants to merge 2 commits into
Conversation
|
Automated review will not run because this contributor is not yet eligible under the automation policy. Contributors become eligible after one qualifying IronRDP pull request is merged into |
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The protocol fix is correct and regression-tested; the remaining allocation concern is optional.
Review effort: Balanced
Findings: 1
Open (1)
What changed in this PR
Corrects RDPSND Training Confirm sizing to comply with MS-RDPEA.
Changes:
- Echoes the complete Training PDU size.
- Adds regression coverage for non-empty training data.
| File | Description |
|---|---|
crates/ironrdp-rdpsnd/src/client.rs |
Corrects wPackSize generation. |
crates/ironrdp-testsuite-core/tests/rdpsnd/client.rs |
Tests the corrected size. |
| let pack_size = if pdu.data.is_empty() { | ||
| 0 | ||
| } else { | ||
| pdu::ServerAudioOutputPdu::Training(pdu.clone()).size() | ||
| }; |
There was a problem hiding this comment.
Fixed in 2d99f67, no clone anymore (see the reply below).
There was a problem hiding this comment.
The PR correctly fixes RDPSND Training Confirm wPackSize to echo the Training PDU's whole-PDU size per MS-RDPEA 2.2.3.2. The recomputed value (4-byte header + 4-byte fixed part + data length, or 0 when empty) is byte-identical to what TrainingPdu::encode writes, and because decode derives data length as wPackSize minus 8, it reproduces the received wPackSize exactly for wire-sourced PDUs; the empty-data branch correctly emits 0. The new regression test asserts the exact encoder math. No correctness, protocol, or safety defect found; the only published finding is a low-severity maintainability note about duplicated size-computation logic and an unnecessary full PDU clone, best addressed with a shared helper on TrainingPdu.
| let pack_size = if pdu.data.is_empty() { | ||
| 0 | ||
| } else { | ||
| pdu::ServerAudioOutputPdu::Training(pdu.clone()).size() | ||
| }; |
There was a problem hiding this comment.
[code-compressor] Duplicated wPackSize computation plus a full PDU clone; share one helper with TrainingPdu::encode — low 🟡 — The added if/else re-implements the size rule already encoded in TrainingPdu::encode (pdu/mod.rs:637-641: 0 when data is empty, otherwise size() + ServerAudioOutputPdu::FIXED_PART_SIZE), creating two copies of the same invariant that can drift. The ServerAudioOutputPdu::Training(pdu.clone()) exists only because size() is called through the enum variant; the value equals TrainingPdu::FIXED_PART_SIZE + data.len() + 4 regardless, so the clone needlessly allocates and copies the data buffer. Extracting a private TrainingPdu helper (e.g. fn w_pack_size(&self) -> usize) used by both encode and training_confirm removes the branch, the clone, and the duplicated arithmetic with byte-identical output and no API change; the existing cast_length!/map_err error handling stays as-is.
There was a problem hiding this comment.
Done in 2d99f67: TrainingPdu::pack_size() now holds the rule, and both TrainingPdu::encode and training_confirm use it, so the confirm no longer clones the PDU. Output is byte-identical; the rdpsnd tests pass.
MS-RDPEA 2.2.3.2: the Training Confirm PDU's wPackSize "MUST be the value of the wPackSize field of the Training PDU", which is the size of the whole PDU including its header, or 0 when it carries no data. The client sent the length of the training data instead. Servers that check it ignore the confirm: GNOME Remote Desktop logs "Received invalid Training Confirm PDU. Ignoring..." and never starts playback. Training PDUs without data were unaffected (both are 0). Adds a test with a data-carrying Training PDU.
…nd confirm TrainingPdu::pack_size() holds the rule (0 without data, otherwise the whole PDU's size) that TrainingPdu::encode writes and training_confirm echoes, so the confirm no longer clones the PDU to measure it.
2d99f67 to
45c76bd
Compare
|
Update: no rebase needed anymore. picky-krb 0.12.5 was yanked from crates.io (re-released as 0.13.0), so the API check builds again without changes to this branch. PR automation has been re-run here and passes. |
There was a problem hiding this comment.
The PR correctly fixes the RDPSND client's Training Confirm to echo the Training PDU's wPackSize per MS-RDPEA 2.2.3.1/2.2.3.2 instead of the data length alone. The new TrainingPdu::pack_size() helper (0 for empty data, else body size plus the 4-byte SNDPROLOG header) mirrors the decode path's reverse computation, is shared by encode and training_confirm, and involves no public API change. A new integration test covers the full process() path. The sole candidate is a valid, low-severity optional style cleanup in training_confirm. Nothing blocks merge.
- [code-compressor] Collapse two-step cast_length into a single expression — low 🟡 — crates/ironrdp-rdpsnd/src/client.rs
training_confirm binds cast_length! to an intermediate EncodeResult<_> variable, then maps the error on a second line. Merge into `let pack_size = cast_length!("wPackSize", pdu.pack_size()).map_err(|e| encode_err!(e))?;` to remove the binding and its explicit annotation with identical behavior; u16 is inferred from TrainingConfirmPdu::pack_size. Optional maintainability cleanup, not a correctness defect.

Problem
MS-RDPEA 2.2.3.2 says the Training Confirm PDU's
wPackSize"MUST be the value of thewPackSizefield of the Training PDU": the size of the whole Training PDU, header included, or 0 when it carries no data.Rdpsnd::training_confirmsentpdu.data.len()instead, so any Training PDU with data got a confirm that is 8 bytes short.Servers that check it ignore the confirm. GNOME Remote Desktop 46 logs
[RDP.AUDIO_PLAYBACK] Received invalid Training Confirm PDU. Ignoring...and never starts audio playback. Training PDUs without data were unaffected, since both sides are 0 then.Change
training_confirmechoes the Training PDU's size:0without data, otherwise the encoded size of the wholeServerAudioOutputPdu::Training, which is what the server put inwPackSize.Testing
training_confirm_echoes_the_training_pdu_sizeinironrdp-testsuite-core(rdpsnd client tests): a Training PDU with 32 bytes of data must be confirmed with its fullwPackSize(40). It fails without the fix (left: 32, right: 40).cargo test -p ironrdp-testsuite-core --test integration_tests_core rdpsnd(73 passing),cargo fmt --all -- --check,cargo clippy -p ironrdp-rdpsnd -p ironrdp-testsuite-core --all-targets -- -D warnings.ironrdp-rdpsnd; without it, the server never starts playback.Prepared with AI assistance; I reviewed the change and ran the tests above.