From 7fbe819cf191a7956ed5c2e3e775804968b12c47 Mon Sep 17 00:00:00 2001 From: hardw00t Date: Thu, 23 Jul 2026 11:06:15 +0400 Subject: [PATCH] Fix out-of-bounds read in plm_video_process_macroblock The bounds check only validated the base indices si/di, but the half-pel prediction reads s[si+1], s[si+dw] and s[si+dw+1] and the block loop spans a block_size x block_size region. For si near max_address with an odd (half-pel) motion component the source read can run up to one row (dw) past the frame plane; when the reference plane is the last plane in the shared frames_data allocation this reads out of bounds. Bound the actual deepest source and destination offsets against the plane size instead of only the base indices. Found with libFuzzer + ASan. --- pl_mpeg.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/pl_mpeg.h b/pl_mpeg.h index b42f53f..ab99610 100755 --- a/pl_mpeg.h +++ b/pl_mpeg.h @@ -3356,8 +3356,17 @@ void plm_video_process_macroblock( unsigned int si = ((self->mb_row * block_size) + vp) * dw + (self->mb_col * block_size) + hp; unsigned int di = (self->mb_row * dw + self->mb_col) * block_size; - unsigned int max_address = (dw * (self->mb_height * block_size - block_size + 1) - block_size); - if (si > max_address || di > max_address) { + // The half-pel prediction reads s[si+1], s[si+dw] and s[si+dw+1], and the + // block loop spans block_size rows/cols, so the deepest source byte read is + // si + (block_size-1)*dw + (block_size-1) + (odd_v?dw:0) + (odd_h?1:0). + // Bound the actual deepest source AND destination offsets against the + // plane, not just the base indices si/di. + unsigned int plane_size = dw * (self->mb_height * block_size); + unsigned int max_di = di + (block_size - 1) * dw + (block_size - 1); + unsigned int max_si = si + (block_size - 1) * dw + (block_size - 1) + + (odd_v ? dw : 0) + (odd_h ? 1 : 0); + if (si >= plane_size || di >= plane_size || + max_si >= plane_size || max_di >= plane_size) { return; // corrupt video }