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

`decode_zlib()` accepts a zlib stream that ends (`Z_STREAM_END`) before 
`uncompressed_size` bytes have been produced. `s->delta` is reused between 
packets (`av_fast_padded_malloc()` only allocates when it has to grow), so the 
part that was not written still holds the previous packet's data, and 
`decode_move()`, `decode_dlta()` and the cursor code use it as if it had just 
been decoded.

For example, a RASC AVI whose second `MOUS` chunk declares 24 bytes of cursor 
data but whose zlib stream inflates to 3 bytes is decoded without any error, 
and 21 bytes of the first packet's cursor end up in the second frame; a `DLTA` 
chunk that inflates to 2 of 758 declared bytes runs the delta opcodes over the 
previous packet's data.

The patch returns `AVERROR_INVALIDDATA` when fewer than `uncompressed_size` 
bytes were inflated; all three callers then read exactly `uncompressed_size` 
bytes from `s->delta`. With it, both cases above report "Inflated 3 of 24 
bytes" / "Inflated 2 of 758 bytes" and the packet is dropped, while the same 
files with complete streams decode to identical framemd5 output as before. A 
file whose very first packet is short (where the tail was zeroed by the first 
allocation) is now rejected too. I could not find real RASC samples (none in 
fate-suite, samples.ffmpeg.org or trac), so this was tested with constructed 
files only; if short streams turn up in real files, zero-filling the rest would 
be the alternative.

This issue was found by an LLM-Enhanced Static Analysis Engine and verified 
manually.

🤖 Generated with [Claude Code](https://claude.com/claude-code)



From 9def621750195a11eb1e120f934394f1e110329c Mon Sep 17 00:00:00 2001
From: Martin Mirchev <[email protected]>
Date: Tue, 27 Oct 2026 09:59:22 +0800
Subject: [PATCH] avcodec/rasc: fail if the zlib data is shorter than the
 declared size

decode_zlib() accepted a stream that ended before uncompressed_size
bytes were produced. s->delta is reused between packets, so the rest of
it still held the previous packet's data, which decode_move(),
decode_dlta() and the cursor code then used as if it had just been
decoded. Return AVERROR_INVALIDDATA instead.

Signed-off-by: Martin Mirchev <[email protected]>
---
 libavcodec/rasc.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/libavcodec/rasc.c b/libavcodec/rasc.c
index d784a440633..654c9145f9f 100644
--- a/libavcodec/rasc.c
+++ b/libavcodec/rasc.c
@@ -204,6 +204,12 @@ static int decode_zlib(AVCodecContext *avctx, const 
AVPacket *avpkt,
         return AVERROR_INVALIDDATA;
     }
 
+    if (zstream->total_out < uncompressed_size) {
+        av_log(avctx, AV_LOG_ERROR, "Inflated %lu of %u bytes.\n",
+               zstream->total_out, uncompressed_size);
+        return AVERROR_INVALIDDATA;
+    }
+
     return 0;
 }
 
-- 
2.54.0

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

Reply via email to