fix(session): always create bulk decompressor; drop compressed FastPath without one#1255
Open
Greg Lamberson (glamberson) wants to merge 2 commits into
Conversation
added 2 commits
May 10, 2026 12:43
…th without one Closes Devolutions#1193 Microsoft RDP servers send compressed FastPath updates in some scenarios (notably full-frame redraws after a window resize or fullscreen toggle) regardless of whether the client advertised compression in the Client Info PDU. The previous code path: 1. ActiveStage::new gated decompressor creation on `connection_result.compression_type.is_some()`. With the default `ironrdp-client` config (no `--compression-level`), this is `None` and no decompressor was created. 2. fast_path::Processor, when receiving a compressed update with no decompressor, logged a warning and forwarded the still-compressed bytes downstream. The downstream PDU decoder then read what it thought was a length field from compressed payload and failed with `NotEnoughBytes { received: N, expected: <huge> }`, killing the session. Fix: 1. Always create a bulk decompressor in ActiveStage::new. Default to Rdp61 (XCRUSH) when no compression type was negotiated; the per-update compression type from the FastPath PDU header is passed through to `decompress` per call, so the decompressor handles whatever variant the server actually sends. 2. As defense in depth, change the no-decompressor branch in process_fast_path_update from "pass compressed bytes through" to "drop the update with a warning". A dropped update loses one frame's worth of pixels; forwarding compressed bytes corrupts the session.
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.
Closes #1193
Problem
Microsoft RDP servers send compressed FastPath updates in some scenarios (notably full-frame redraws after a window resize or fullscreen toggle) regardless of whether the client advertised compression in the Client Info PDU.
The previous code path:
ActiveStage::newgated decompressor creation onconnection_result.compression_type.is_some(). With the defaultironrdp-clientconfig (no--compression-level), this isNoneand no decompressor was created.fast_path::Processor, when receiving a compressed update with no decompressor, logged a warning and forwarded the still-compressed bytes downstream. The downstream PDU decoder then read what it thought was a length field from compressed payload and failed withNotEnoughBytes { received: N, expected: <huge> }, killing the session.This is exactly the symptom in #1193:
Received compressed FastPath data but no decompressor is configuredfollowed byColorPointerAttribute::decodeNotEnoughBytes { received: 170, expected: 57966 }on a fullscreen toggle against a Windows server.Fix
Always create a bulk decompressor in
ActiveStage::new. Default toRdp61(XCRUSH) when no compression type was negotiated; the per-update compression type from the FastPath PDU header is passed through todecompressper call, so the decompressor handles whatever variant the server actually sends.As defense in depth, change the no-decompressor branch in
process_fast_path_updatefrom "pass compressed bytes through" to "drop the update with a warning". A dropped update loses one frame's worth of pixels; forwarding compressed bytes corrupts the session.Notes
bulk_decompressor: Option<BulkCompressor>field is preserved (no API change). Library consumers that build afast_path::Processordirectly can still passNone; if they do, compressed updates are dropped rather than crashing the session.update_pdu.datapassthrough with the FIXME-shaped comment about informing the decompressor ofFLUSHED/AT_FRONTflags) is unchanged. That's a separate not-yet-implemented requirement.Test
cargo check -p ironrdp-sessioncleancargo clippy -p ironrdp-session --all-targetsclean (only pre-existing MSRV /ironrdp-errorwarnings unrelated to this change)cargo test -p ironrdp-session --libpasses (no new tests added; the path is exercised by integration against real servers)