PR #23174 opened by michaelni
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23174
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23174.patch

In the >= 9 bit path, color_frame() does
`av_memcpy_backptr(dst + 2, 2, bytes - 2)`. When the effective chroma width
is 1 pixel (bytes == 1) the count becomes -1 and the underlying fill16()
loop runs roughly 2^32 times, producing a heap overflow. The original count
was also wrong in units (pixels rather than bytes); fix that at the same
time so the 2-pixel case still fills both pixels.

Confirmed via a standalone harness reproducing av_memcpy_backptr's fill16
loop with cnt = -1; reaching the call from a crafted H.264 bitstream
requires Hi10P plus a frame_num gap on a frame whose effective chroma width
is 1 pixel, which is hard to express but is reachable via mid-stream SPS
changes. Compiles cleanly; no regressions seen running existing crafted
H.264 PoCs and trivial transcodes.

Reported by Franciszek Kalinowski (isec.pl / striga.ai) and Bartosz Smigielski.


>From b045db016e7078d7636823c1dd6b864dc8a26771 Mon Sep 17 00:00:00 2001
From: Franciszek Kalinowski <[email protected]>
Date: Tue, 19 May 2026 09:36:50 +0200
Subject: [PATCH] avcodec/h264_slice: guard color_frame() against chroma-width
 underflow

In the >= 9 bit path, color_frame() does
`av_memcpy_backptr(dst + 2, 2, bytes - 2)`. When the effective chroma width
is 1 pixel (bytes == 1) the count becomes -1 and the underlying fill16()
loop runs roughly 2^32 times, producing a heap overflow. The original count
was also wrong in units (pixels rather than bytes); fix that at the same
time so the 2-pixel case still fills both pixels.

Confirmed via a standalone harness reproducing av_memcpy_backptr's fill16
loop with cnt = -1; reaching the call from a crafted H.264 bitstream
requires Hi10P plus a frame_num gap on a frame whose effective chroma width
is 1 pixel, which is hard to express but is reachable via mid-stream SPS
changes. Compiles cleanly; no regressions seen running existing crafted
H.264 PoCs and trivial transcodes.

Reported by Franciszek Kalinowski (isec.pl / striga.ai) and Bartosz Smigielski.
---
 libavcodec/h264_slice.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
index dbf7f60230..e3b4436fcb 100644
--- a/libavcodec/h264_slice.c
+++ b/libavcodec/h264_slice.c
@@ -316,8 +316,10 @@ static void color_frame(AVFrame *frame, const int c[4])
         int bytes  = is_chroma ? AV_CEIL_RSHIFT(frame->width,  
desc->log2_chroma_w) : frame->width;
         int height = is_chroma ? AV_CEIL_RSHIFT(frame->height, 
desc->log2_chroma_h) : frame->height;
         if (desc->comp[0].depth >= 9) {
-            ((uint16_t*)dst)[0] = c[p];
-            av_memcpy_backptr(dst + 2, 2, bytes - 2);
+            if (bytes >= 1)
+                ((uint16_t*)dst)[0] = c[p];
+            if (bytes >= 2)
+                av_memcpy_backptr(dst + 2, 2, 2 * (bytes - 1));
             dst += frame->linesize[p];
             for (int y = 1; y < height; y++) {
                 memcpy(dst, frame->data[p], 2*bytes);
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to