Skip to content

Fast-path RLE bitmap decode fails against xrdp (16bpp): "not enough bytes: expected 2, but got 1" + "unsupported fast-path update code" — causes visible screen corruption #1693

Description

@d3lsec

Title

Fast-path RLE bitmap decode fails against xrdp (16bpp): "not enough bytes: expected 2, but got 1" + "unsupported fast-path update code" — causes visible screen corruption

Environment

  • @devolutions/iron-remote-desktop 0.11.0 (npm, latest)
  • @devolutions/iron-remote-desktop-rdp 0.7.0 (npm, latest)
  • Client: browser (WASM), connecting through devolutions-gateway 2026.2.4 (RDCleanPath)
  • Server: xrdp 0.10.6.1-2+kali1 + xorgxrdp 1:0.10.5-2 on Kali GNU/Linux Rolling 2026.3, desktop session = Xfce 4.20
  • Server capabilities as sent in ServerDemandActive: Bitmap { pref_bits_per_pix: 16, desktop_resize_flag: true }, GFX/EGFX pipeline NOT used for this connection — negotiated via the classic fast-path bitmap-orders channel instead.

What happens

After a normal, successful connection (TLS handshake OK, login OK, capability exchange OK), the client logs repeated warnings while receiving bitmap updates, and the on-screen result is visibly corrupted (diagonal shearing / torn tiles), while mouse/keyboard input keep working.

Representative log lines from one session (122 total BitmapData fast-path updates received, all bits_per_pixel: 16, 2 of them fail to decode):

DEBUG ironrdp_session::fast_path: Non-32 bpp compressed RLE_BITMAP_STREAM bpp=16
WARN  ironrdp_session::fast_path: Invalid RLE-compressed bitmap: not enough bytes: expected 2 bytes, but got 1
WARN  ironrdp_session::fast_path: Received invalid Fast-Path update field="updateCode" reason="unsupported fast-path update code"

One of the BitmapData PDUs immediately preceding a failure, for reference:

BitmapData { rectangle: InclusiveRectangle { left: 385, top: 427, right: 594, bottom: 448 }, width: 212, height: 22, bits_per_pixel: 16, compression_flags: Compression(BITMAP_COMPRESSION | NO_BITMAP_COMPRESSION_HDR), compressed_data_header: None, bitmap_data.len(): 54 }

What I ruled out (server-side, not a config issue)

Before filing, I checked whether this was an xrdp misconfiguration on our end:

  • desktop_width/desktop_height requested by the client are always rounded to a multiple of 4 (e.g. 796x1020, 900x636) — not a stride/alignment issue on the client side.
  • Toggling bitmap_compression=false in xrdp.ini (forces raw/uncompressed bitmap updates instead of RLE): connection got noticeably slower but showed the exact same corruption — so it isn't specific to the RLE codec's compression math alone, something in the fast-path bitmap-orders handling itself is affected, or xrdp still exercises the same code path regardless of that flag.
  • max_bpp=32 is already set in xrdp.ini (the server's own ceiling), yet preferredBitsPerPixel stays 16 in ServerDemandActive regardless — this doesn't look configurable from our side.
  • Forcing the X11 screen depth to 32 in xorg.conf (DefaultDepth/Depth) breaks the xrdp Xorg session entirely (X server could not be started) — not viable.
  • iron-remote-desktop's ConfigBuilder has no method to request a specific color depth (only withUsername/withPassword/withServerDomain/withDestination/withProxyAddress/withAuthToken/withExtension/withDesktopSize), so we can't influence this from the client config either.
  • Confirmed with xfreerdp (FreeRDP 2.11.5) against the same xrdp instance: connects and renders perfectly clean at the same resolution/session — so this isn't an xrdp/xorgxrdp bug, it's specific to how ironrdp_session::fast_path parses this server's 16bpp interleaved-RLE stream.

Impact

Legacy/non-GFX xrdp sessions (very common — Linux desktop targets, not just Windows) render with visible tearing/corruption. Reproducible every connection against this server, ~2 failed tile decodes out of ~122 per session in our testing, but visually noticeable because failures desync the bitmap cache for subsequent frames referencing the same tile.

Contact

adelson-amorim@outlook.com — happy to provide a packet capture / full session log (currently ~190MB with embedded frame data) if useful for a repro.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions