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

Multiple demuxers call avio_read() without checking its return value. When 
input is truncated, destination buffers remain uninitialized but are still used 
for offset calculations, memcmp, and metadata handling. This results in 
undefined behavior (detectable with Valgrind/MSan).

Fix this by checking the return value of avio_read() in:
- dss.c: dss_read_seek() - check before using header buffer
- dtshddec.c: FILEINFO chunk - check before using value buffer
- mlvdec.c: check_file_header() - check before memcmp on version

Fixes: #21520


From ee0b1c0b0981ed7965816597b531fee87a95a5ee Mon Sep 17 00:00:00 2001
From: Sankalpa Sarkar <[email protected]>
Date: Fri, 27 Mar 2026 21:12:46 +0530
Subject: [PATCH] avformat: check avio_read() return values in dss/dtshd/mlv
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Multiple demuxers call avio_read() without checking its return
value. When input is truncated, destination buffers remain
uninitialized but are still used for offset calculations, memcmp,
and metadata handling. This results in undefined behavior
(detectable with Valgrind/MSan).

Fix this by checking the return value of avio_read() in:
- dss.c: dss_read_seek() — check before using header buffer
- dtshddec.c: FILEINFO chunk — check before using value buffer
- mlvdec.c: check_file_header() — check before memcmp on version

Fixes: #21520
---
 libavformat/dss.c      | 4 +++-
 libavformat/dtshddec.c | 6 +++++-
 libavformat/mlvdec.c   | 3 ++-
 3 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/libavformat/dss.c b/libavformat/dss.c
index 6cabdb5421..aa7ef08622 100644
--- a/libavformat/dss.c
+++ b/libavformat/dss.c
@@ -339,7 +339,9 @@ static int dss_read_seek(AVFormatContext *s, int 
stream_index,
     if (ret < 0)
         return ret;
 
-    avio_read(s->pb, header, DSS_AUDIO_BLOCK_HEADER_SIZE);
+    ret = avio_read(s->pb, header, DSS_AUDIO_BLOCK_HEADER_SIZE);
+    if (ret < DSS_AUDIO_BLOCK_HEADER_SIZE)
+        return ret < 0 ? ret : AVERROR_INVALIDDATA;
     ctx->swap = !!(header[0] & 0x80);
     offset = 2*header[1] + 2*ctx->swap;
     if (offset < DSS_AUDIO_BLOCK_HEADER_SIZE)
diff --git a/libavformat/dtshddec.c b/libavformat/dtshddec.c
index b980fde6a9..e516eba2f1 100644
--- a/libavformat/dtshddec.c
+++ b/libavformat/dtshddec.c
@@ -125,7 +125,11 @@ static int dtshd_read_header(AVFormatContext *s)
             value = av_malloc(chunk_size);
             if (!value)
                 goto skip;
-            avio_read(pb, value, chunk_size);
+            ret = avio_read(pb, value, chunk_size);
+            if (ret < chunk_size) {
+                av_free(value);
+                goto skip;
+            }
             value[chunk_size - 1] = 0;
             av_dict_set(&s->metadata, "fileinfo", value,
                         AV_DICT_DONT_STRDUP_VAL);
diff --git a/libavformat/mlvdec.c b/libavformat/mlvdec.c
index fa35bc9c45..d9d7815f54 100644
--- a/libavformat/mlvdec.c
+++ b/libavformat/mlvdec.c
@@ -79,7 +79,8 @@ static int check_file_header(AVIOContext *pb, uint64_t guid)
     size = avio_rl32(pb);
     if (size < 52)
         return AVERROR_INVALIDDATA;
-    avio_read(pb, version, 8);
+    if (avio_read(pb, version, 8) < 8)
+        return AVERROR_INVALIDDATA;
     if (memcmp(version, MLV_VERSION, 5) || avio_rl64(pb) != guid)
         return AVERROR_INVALIDDATA;
     avio_skip(pb, size - 24);
-- 
2.52.0

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

Reply via email to