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

A CLUT entry is 4 bytes in the short form and 6 bytes in the full form, but the 
loop only parsed an entry when at least 5 bytes were left. So a short entry at 
the end of the segment was ignored. A truncated 5-byte full entry was parsed 
using one byte read past the segment.

The loop now parses an entry when 4 bytes are left, and stops at a full entry 
that doesn't fit.

Fuzzed streams under ASan/UBSan show the old code reading past the segment, and 
the new code doesn't.
Streams with only full-range entries, like the real sample and our encoder's 
output, decode the same, and the dvbsub FATE tests are unchanged.

Note: the existing "Invalid clut depth" message is now also logged when only 4 
stray bytes are left at the end of a segment (before, it needed at least 5).

Found during a code review sweep of ffmpeg using an LLM.

<!--
If this PR requires new FATE test samples, attach them to the PR and
list their target paths below (relative to the fate-suite root).

Attached filenames must match the sample's filename:

```fate-samples
# e.g. vorbis/new-sample.ogg
```
-->



>From 2dea9926d71b0a9b7068de9c891f7f2e163fdcea Mon Sep 17 00:00:00 2001
From: romainhedouin <[email protected]>
Date: Sat, 7 Nov 2026 13:05:19 +0100
Subject: [PATCH] avcodec/dvbsubdec: do not drop a reduced-range last CLUT
 entry

A CLUT entry is 4 bytes in reduced-range form and 6 bytes in full-range
form (EN 300 743, table 16), but the CLUT segment loop only parsed an
entry when at least 5 bytes were left. A reduced-range entry at the end
of the segment was therefore ignored and that palette index kept its
previous value (the default colour unless an earlier CLUT version set
it), and a full-range entry with only 5 bytes left was parsed using one
byte read past the end of the segment (the sync byte of the next
segment, or the packet padding).

Parse an entry when the 4 bytes of a reduced-range entry are left, and
stop at a full-range entry that does not fit, so that a truncated
trailing entry is ignored. Four stray bytes at the end of a segment are
now parsed as an entry too, and reported by the existing "Invalid clut
depth" message if their depth flags are 0.

Well-formed streams that only use full-range entries, such as the ones
written by the FFmpeg encoder, are not affected.

Found during a code review sweep of ffmpeg using an LLM.

Signed-off-by: romainhedouin <[email protected]>
---
 libavcodec/dvbsubdec.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/libavcodec/dvbsubdec.c b/libavcodec/dvbsubdec.c
index 2426da896d1..fc994af099b 100644
--- a/libavcodec/dvbsubdec.c
+++ b/libavcodec/dvbsubdec.c
@@ -1101,7 +1101,7 @@ static int dvbsub_parse_clut_segment(AVCodecContext 
*avctx,
 
         clut->version = version;
 
-        while (buf + 4 < buf_end) {
+        while (buf + 3 < buf_end) {
             entry_id = *buf++;
 
             depth = (*buf) & 0xe0;
@@ -1113,6 +1113,8 @@ static int dvbsub_parse_clut_segment(AVCodecContext 
*avctx,
             full_range = (*buf++) & 1;
 
             if (full_range) {
+                if (buf_end - buf < 4)
+                    break;
                 y     = *buf++;
                 cr    = *buf++;
                 cb    = *buf++;
-- 
2.54.0

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

Reply via email to