Skip to content

feat(pdu,graphics,egfx): add ClearCodec bitmap compression codec#1174

Open
Greg Lamberson (glamberson) wants to merge 6 commits intoDevolutions:masterfrom
lamco-admin:feat/clearcodec-codec
Open

feat(pdu,graphics,egfx): add ClearCodec bitmap compression codec#1174
Greg Lamberson (glamberson) wants to merge 6 commits intoDevolutions:masterfrom
lamco-admin:feat/clearcodec-codec

Conversation

@glamberson
Copy link
Contributor

Part of the multi-codec EGFX implementation described in #1158 (Section 3).

Summary

Add ClearCodec (MS-RDPEGFX 2.2.4.1), the mandatory lossless bitmap codec
for all EGFX versions (V8-V10.7). ClearCodec uses three-layer compositing
(residual BGR RLE, bands with V-bar caching, subcodec regions) to encode
text, UI elements, and icons with pixel-perfect fidelity.

This is the first ClearCodec encoder in any open-source RDP implementation.
FreeRDP has client-side decode only.

What it adds

ironrdp-pdu (wire format):

  • codecs/clearcodec/: ClearCodecBitmapStream, CompositePayload, residual
    RLE decode/encode, bands with V-bar cache references (full hit, short
    hit, short miss), RLEX subcodec, raw/NSCodec dispatch
  • 24 inline unit tests for wire format parsing

ironrdp-graphics (codec logic):

  • clearcodec/: ClearCodecDecoder with persistent V-bar and glyph caches,
    ClearCodecEncoder with residual-only encoding and glyph deduplication
  • VBarCache: 32,768 full + 16,384 short V-bar ring buffers per spec
  • GlyphCache: 4,000 entries, area <= 1024 pixels per spec
  • 18 inline unit tests for cache operations

ironrdp-egfx (server integration):

  • GraphicsPipelineServer::send_clearcodec_frame()

ironrdp-testsuite-core:

  • 35 integration tests: codec round-trip with pixel-perfect verification,
    adversarial input handling (max run_length, OOM dimensions, malformed
    streams, uncached glyph hits), bands layer compositing through the full
    decode pipeline, cache state management across multi-frame sessions,
    compression quality assertions

Security hardening

Three rounds of code review against FreeRDP ClearCodec CVEs:

  • Cap residual run_length to output buffer (GHSA-32q9-m5qr-9j2v)
  • Cap allocation to 8192x8192 pixels (CVE-2026-26955 class)
  • Fix shortVBarYOff: absolute end-row offset, not pixel count delta
    (MS-RDPEGFX 2.2.4.1.1.2.1.1.3)
  • Validate glyph index range 0-3999 (CVE-2026-23531 class)
  • Validate shortVBarYOff >= shortVBarYOn

NSCodec

The NSCodec subcodec (Layer 3 option) is not implemented in this PR.
The encoder avoids generating NSCodec tiles, and the decoder stub leaves
NSCodec regions at their residual-layer values. This can be added later
without API changes.

Test plan

  • cargo xtask check fmt/lints/tests/typos/locks (all pass)
  • 77 total tests (35 testsuite + 42 inline)

Implement MS-RDPEGFX 2.2.4.1 ClearCodec (codecId=0x0008), a mandatory
lossless codec for all EGFX versions.

PDU layer (ironrdp-pdu):
- Top-level bitmap stream with glyph index/hit/cache reset flags
- Three-layer composite payload (residual, bands, subcodec)
- Residual: BGR run-length encoding with variable-length factors
- Bands: V-bar dispatch (full cache hit, short cache hit, cache miss)
- RLEX: palette-indexed RLE with gradient suite encoding
- Subcodec: container for Raw, NSCodec (stub), and RLEX regions

Graphics layer (ironrdp-graphics):
- ClearCodecDecoder with persistent V-bar and glyph cache state
- V-bar cache: 32K full + 16K short entries in ring buffers
- Glyph cache: 4,000 entries for small bitmap deduplication
- Full three-layer compositing (residual -> bands -> subcodec)

35 tests covering all codec layers and round-trip encoding.
NSCodec subcodec deferred (servers can use Raw or RLEX instead).
Add ClearCodecEncoder for server-side ClearCodec bitmap compression:
- Residual-only encoding strategy (BGR RLE) for reliable compression
- Glyph cache with automatic hit detection for small repeated bitmaps
- Sequence number tracking matching the decoder protocol
- Cache reset message encoding
- BGRA-to-BGR run segment conversion with run-length coalescing

7 new encoder tests including encode-decode round trips that verify
interoperability between the encoder and decoder.
Add send_clearcodec_frame() to GraphicsPipelineServer, following the
same pattern as send_avc420_frame(). Takes pre-encoded ClearCodec
bitmap data and queues it as a WireToSurface1 PDU with the standard
three-PDU frame sequence (StartFrame, WireToSurface1, EndFrame).

ClearCodec is mandatory for all EGFX versions and provides lossless
compression optimized for text and UI elements.
…tion

Security hardening informed by FreeRDP ClearCodec CVEs (GHSA-3frr,
GHSA-32q9, CVE-2026-26955, CVE-2026-23531) and three rounds of
targeted code review.

Fixes:
- Correct shortVBarYOff interpretation: 6-bit field is an absolute
  end-row offset, not a pixel count. Pixel count = yOff - yOn per
  MS-RDPEGFX 2.2.4.1.1.2.1.1.3. (Round 2)
- Validate shortVBarYOff >= shortVBarYOn and <= band_height (Round 2)
- Cap residual run_length iterations to output buffer size (Round 1)
- Cap decoder allocation to 8192x8192 pixels max (Round 3)
- Validate glyph index range 0-3999 per spec 2.2.4.1 (Round 2)
- Cap encoder input to available pixel data (Round 1)

Add integration tests in ironrdp-testsuite-core (35 tests) covering
codec round-trip, adversarial input (DoS, OOM, malformed streams),
bands layer compositing, cache state, compression quality, and
multi-frame session simulation. Inline unit tests (42 tests) in the
PDU and graphics crates cover wire format decode/encode.
Greg Lamberson (glamberson) added a commit to lamco-admin/IronRDP that referenced this pull request Mar 18, 2026
Wire ClearCodec into the EGFX client's WireToSurface1 codec dispatch,
following the same pattern as AVC420 and Uncompressed decode.

- Add ClearCodecDecoder field (always enabled, no external codec needed)
- Decode ClearCodec bitmap data and convert BGRA output to RGBA
- Reset decoder caches on ResetGraphics (V-bar + glyph state)
- Add 3 integration tests: basic decode, RGBA output, reset survival
- Add unit test for BGRA-to-RGBA channel reordering

Depends on the ClearCodec codec PR (Devolutions#1174).
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds ClearCodec (MS-RDPEGFX 2.2.4.1) support across the wire-format layer (ironrdp-pdu), codec logic (ironrdp-graphics), and EGFX server API (ironrdp-egfx), with extensive new tests in ironrdp-testsuite-core.

Changes:

  • Introduces ironrdp-pdu::codecs::clearcodec with residual/bands/subcodec parsing and helpers.
  • Adds ironrdp-graphics::clearcodec encoder/decoder plus persistent V-bar and glyph caching.
  • Extends GraphicsPipelineServer with send_clearcodec_frame() and adds ClearCodec integration tests.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
crates/ironrdp-testsuite-core/tests/graphics/mod.rs Registers the new ClearCodec integration test module.
crates/ironrdp-testsuite-core/tests/graphics/clearcodec.rs Adds ClearCodec end-to-end and adversarial integration tests.
crates/ironrdp-pdu/src/codecs/mod.rs Exposes the new ClearCodec codec module.
crates/ironrdp-pdu/src/codecs/clearcodec/mod.rs Defines ClearCodec bitmap stream + composite payload parsing and exports layer decoders.
crates/ironrdp-pdu/src/codecs/clearcodec/residual.rs Implements residual (BGR RLE) encode/decode.
crates/ironrdp-pdu/src/codecs/clearcodec/bands.rs Implements bands layer decoding (V-bar references + inline data).
crates/ironrdp-pdu/src/codecs/clearcodec/subcodec.rs Implements subcodec layer parsing (raw/NSCodec/RLEX region headers).
crates/ironrdp-pdu/src/codecs/clearcodec/rlex.rs Implements RLEX subcodec parsing.
crates/ironrdp-graphics/src/lib.rs Exposes the new clearcodec module.
crates/ironrdp-graphics/src/clearcodec/mod.rs Implements ClearCodec decoder/encoder and compositing across layers.
crates/ironrdp-graphics/src/clearcodec/glyph_cache.rs Adds glyph cache backing storage used by encoder/decoder.
crates/ironrdp-graphics/src/clearcodec/vbar_cache.rs Adds V-bar/short V-bar cache backing storage used by decoder.
crates/ironrdp-egfx/src/server.rs Adds send_clearcodec_frame() EGFX server API entry point.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

…items

Address review feedback on Devolutions#1174:

- Validate subcodec region bounds against surface dimensions
- Validate RLEX palette indices and enforce region pixel budget
- Remove silent pixel skipping that caused coordinate desync
- Add glyph cache dimension mismatch check on hit
- Use checked arithmetic for raw subcodec data length
- Remove unused expected_seq field from ClearCodecDecoder
- Use saturating_mul in encoder for pixel count
- Add missing QoE backpressure recording for ClearCodec frames
- Document vbar_cache wrap constant derivation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants