fix(session): Fix bitmap stride mismatch and out-of-bounds writes for xRDP compatibility - #1252
fix(session): Fix bitmap stride mismatch and out-of-bounds writes for xRDP compatibility#1252Amartya Anshuman (amartyaa) wants to merge 4 commits into
Conversation
|
Thanks for the report and the fix Amartya Anshuman (@amartyaa). The stride insight is correct: MS-RDPBCGR §2.2.9.1.1.3.1.2.2 does distinguish A few suggestions a reviewer is likely to raise: 1. Horizontal over-paint when 2. Tests. A regression test for the stride case (construct a known-pattern bitmap whose data width differs from the destination width, call 3. Inconsistent bounds-check operators. Five sites use 4. Silent clipping vs Downstream context: this is relevant to Lamco's xRDP interop testing. Our test fleet uses xRDP 0.10.x on Ubuntu as a non-Windows comparison server, and IronRDP clients connecting there hit the diagonal-distortion symptom you describe. A version of this fix landing upstream would resolve a recurring noise item in our fleet runs. If a revised version lands, I can run it through our xRDP test fleet to confirm. |
|
Hello Greg Lamberson (@glamberson) !!
Happy to iterate further. Looking forward to Lamco's xRDP fleet results once this lands! |
There was a problem hiding this comment.
Pull request overview
Fixes diagonal bitmap shearing and out-of-bounds panics observed when ironrdp-session connects to xRDP servers, which send BitmapData whose pixel dimensions (update.width/update.height) don't match the destination rectangle. The fix derives a blit_rect whose size is the per-spec clip of bitmap-data vs. destination-rect dimensions and routes all apply_* calls through it, plus adds per-pixel/per-slice bounds guards in image.rs and enables unit tests for the crate.
Changes:
- In
fast_path.rs::process_bitmap_update, build ablit_rectfrommin(update.width, rect.width)/min(update.height, rect.height)and pass it to everyapply_*path instead ofupdate.rectangle. - In
image.rs, adddebug_assert!+if dst_idx + DST_COLOR_DEPTH <= self.data.len()per-pixel guards to all slow-path apply methods, amax_rowsclamp inapply_rgb24_iter, and a silent clamp indata_for_rect; also add atestsmodule covering rgb32 placement, rgb16 in-bounds writes, oversize rect rejection, anddata_for_rectclamping. - In
ironrdp-session/Cargo.toml, comment outtest = falseto enable the new unit tests.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
crates/ironrdp-session/src/fast_path.rs |
Introduces clipped blit_rect and routes all apply_* calls through it to fix stride/shearing. |
crates/ironrdp-session/src/image.rs |
Adds redundant-with-rect_fits per-pixel guards, clamps data_for_rect, and adds a unit-test module. |
crates/ironrdp-session/Cargo.toml |
Comments out test = false to allow the new tests to run. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @@ -844,7 +863,9 @@ impl DecodedImage { | |||
| .for_each(|(col_idx, src_pixel)| { | |||
| let dst_idx = ((top + row_idx) * image_width + left + col_idx) * DST_COLOR_DEPTH; | |||
|
|
|||
|
Hi Amartya Anshuman (@amartyaa), your four points are addressed cleanly. The Copilot's follow-up review has some substantive items worth working through. In particular, the asymmetric-clipping note at I'll run the patched version against our xRDP 0.10.x test fleet once you've worked through Copilot's review; running against an in-flight revision wouldn't tell us much about the final shape. Should take 1-2 days from your next push. |
e0e2d0a to
b7fdb8e
Compare
* fix: minor code quality changes * fix: formatting fixed * fix: Lint Issues fixed
|
Hello Greg Lamberson (@glamberson)! I think all the points are covered now. |
|
Amartya Anshuman (@amartyaa) First, apologies for the slow turnaround on getting back to you here. Thanks for the revision. The I think one piece of Copilot's asymmetric-clipping point is still open, though, in the bitmap-wider-than-rect direction. It is at the call sites rather than in the All of the decoded buffers have a row stride of
But only the RDP6 path passes Ok(()) => image.apply_rgb24(&buf, &blit_rect, update.width, true)?,The RLE and uncompressed paths pass Ok(RlePixelFormat::Rgb16) => image.apply_rgb16_bitmap(&buf, &blit_rect, clipped_width)?,
...
32 => image.apply_rgb32_bitmap(&buf, PixelFormat::BgrX32, &blit_rect, clipped_width)?,When The fix is small and matches what the RDP6 path already does: pass One note on the new tests: they call the Once that is in, I will run the result through our xRDP test fleet and report back. Heads-up that the branch is currently showing as conflicting with master, so it will need a rebase as well. |
## Summary - Preserve `TS_BITMAP_DATA` source stride independently of destination bounds for raw, Interleaved RLE, and RDP6 bitmap updates. - Remove raw 4-byte scanline padding without collapsing padded source columns into following rows. - Crop only the source extent beyond the destination and reject empty dimensions explicitly; do not add framebuffer bounds suppression. - Render decoded RDP6 RGB data top-down and retain bottom-up rendering for raw and RLE data. ## Why this supersedes the overlapping proposals - #1252 identifies both dimensions but applies a clipped stride, which still misaddresses padded source rows; its broad framebuffer-clipping changes are intentionally excluded. - #1398 correctly identifies the RDP6 stride/orientation issue, but leaves raw and RLE paths unresolved. - #1408 includes the related stride issue but also mixes unrelated Win7 activation and web changes; its allocation/inference normalization is unnecessary once source stride is explicit. - #1436 correctly crops padded rows but repacks each path into temporary buffers; this PR preserves the source stride directly and covers all bitmap codecs. ## Specification basis - MS-RDPBCGR 2.2.9.1.1.3.1.2.2 (`TS_BITMAP_DATA`): separate destination bounds, dimensions, and bottom-up raw rows with 4-byte row padding. - MS-RDPBCGR 2.2.9.1.1.3.1.2.3 and 2.2.9.1.1.3.1.2.4: compressed bitmap header and Interleaved RLE stream. - MS-RDPEGDI 2.2.2.5.1: RDP 6.0 bitmap stream. ## Validation - `cargo test -p ironrdp-session --lib` - `cargo check -p ironrdp-session --all-features` - `cargo clippy -p ironrdp-session --all-targets -- -D warnings` - `cargo xtask check fmt -v` Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
partially superseded by #1486 if you want to rebase |
|
Automated review found two blocking QOIZ decoding denial-of-service risks in |
Fixes #1251
Summary
This PR fixes two related issues in
ironrdp-sessionthat cause diagonal bitmap distortion and index-out-of-bounds panics when connecting to xRDP servers.Changes
crates/ironrdp-session/src/fast_path.rsxRDP sends bitmap updates where the data dimensions (
update.width×update.height) differ from the destination rectangle (update.rectangle). Per MS-RDPBCGR §2.2.9.1.1.3.1.2.2,bitmapWidth/bitmapHeightdefine the pixel data layout whiledestLeft/destTop/destRight/destBottomdefine the screen placement.The
apply_*methods use the rectangle's width as the row stride. Passingupdate.rectanglewhen it's wider/narrower than the actual data causes diagonal shearing.Fix: Construct a
blit_rectwhose dimensions match the actual bitmap data, positioned at the destination's top-left corner:crates/ironrdp-session/src/image.rsAdded bounds checks to all apply_* bitmap methods that were missing them:
Each pixel write is now guarded with
if dst_idx + bytes_per_pixel < self.data.len().This is consistent with how other parts of the codebase handle edge-of-framebuffer updates — pixels beyond the buffer are silently clipped rather than panicking.
Also added a
max_rowsclamp inapply_rgb24_iterto prevent iterating beyond the framebuffer height.Testing