Skip to content

Commit 1d11c95

Browse files
committed
fix(egfx): cap Avc420BitmapStream pre-allocation against remaining bytes
Avc420BitmapStream::decode reads a u32 num_regions and called Vec::with_capacity(num_regions as usize) twice without bounding the value. A fuzzer-controlled num_regions near u32::MAX caused the allocator to attempt several gigabytes per call, which ASan trapped as out-of-memory in the new pdu_decode egfx coverage. Caps the with_capacity argument at src.len() / per-region size, where per-region is the minimum decode footprint (InclusiveRectangle plus QuantQuality). The actual read loop is unchanged and still returns NotEnoughBytes via the inner Decode impls if num_regions does not match the actual payload, so the only behavioural change is bounded pre-allocation. Surfaced by the egfx fuzz coverage added earlier on this branch.
1 parent ad1401f commit 1d11c95

1 file changed

Lines changed: 9 additions & 2 deletions

File tree

  • crates/ironrdp-egfx/src/pdu

crates/ironrdp-egfx/src/pdu/avc.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,15 @@ impl<'de> Decode<'de> for Avc420BitmapStream<'de> {
117117
let num_regions = src.read_u32();
118118
#[expect(clippy::as_conversions, reason = "num_regions bounded by practical limits")]
119119
let num_regions_usize = num_regions as usize;
120-
let mut rectangles = Vec::with_capacity(num_regions_usize);
121-
let mut quant_qual_vals = Vec::with_capacity(num_regions_usize);
120+
// Cap pre-allocation against the remaining buffer to avoid OOM from a
121+
// malicious num_regions: each region needs at least one rectangle
122+
// (8 bytes) plus one QuantQuality entry (2 bytes). The actual read
123+
// loop will fail with NotEnoughBytes if num_regions is bogus.
124+
let per_region = InclusiveRectangle::FIXED_PART_SIZE + QuantQuality::FIXED_PART_SIZE;
125+
let max_possible = src.len() / per_region;
126+
let bounded_capacity = num_regions_usize.min(max_possible);
127+
let mut rectangles = Vec::with_capacity(bounded_capacity);
128+
let mut quant_qual_vals = Vec::with_capacity(bounded_capacity);
122129
for _ in 0..num_regions {
123130
rectangles.push(InclusiveRectangle::decode(src)?);
124131
}

0 commit comments

Comments
 (0)