[FFmpeg-cvslog] avformat/matroskadec: Fix use-after-free when demuxing ProRes

Andreas Rheinhardt git at videolan.org
Thu Jul 2 03:32:51 EEST 2020

ffmpeg | branch: release/4.1 | Andreas Rheinhardt <andreas.rheinhardt at gmail.com> | Sat Dec  7 00:16:19 2019 +0100| [88a19d6b4df69f419381fbc5690cf38e4a55f97f] | committer: Andreas Rheinhardt

avformat/matroskadec: Fix use-after-free when demuxing ProRes

ProRes in Matroska is supposed to not contain the first atom header
(containing a size field and the tag "icpf") and therefore the Matroska
demuxer has to recreate it; this involves an allocation and copy, of
course. Whether the old buffer (containing the data without the atom
header) needs to be freed or not depends upon whether it is what was
directly read (in which case it is owned by an AVBuffer) or whether it
has been allocated when reversing the track's content compression (e.g.
zlib compression) that Matroska supports.

So there are three pointers involved: The one pointing to the directly
read data (owned by the AVBuffer), the one pointing to the currently
valid data (which coincides with the former if no content compression
needed to be reverted) and the one pointing to the new data with the
first atom header. The check for whether to free the second of these is
simply whether the first two are different.

This works mostly, but there is a complication: Some muxers don't strip
the first atom header away and in this case, it is also not reinserted
and no new buffer is allocated; instead, the second and the third
pointers agree. In this case, one must never free the second buffer.
Yet it is currently done if the track is e.g. zlib compressed.
This commit fixes this.

This is a regression since b8e75a2a.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt at gmail.com>
Signed-off-by: James Almer <jamrial at gmail.com>
(cherry picked from commit af50f0a515d8096fece9776e2d3034fe990a1373)
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt at gmail.com>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=88a19d6b4df69f419381fbc5690cf38e4a55f97f

 libavformat/matroskadec.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index 2bec9f6a8e..061d0cb8cf 100644
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -3047,11 +3047,8 @@ fail:
 static int matroska_parse_prores(MatroskaTrack *track, uint8_t *src,
                                  uint8_t **pdst, int *size)
-    uint8_t *dst = src;
-    int dstlen = *size;
-    if (AV_RB32(&src[4]) != MKBETAG('i', 'c', 'p', 'f')) {
-        dstlen += 8;
+    uint8_t *dst;
+    int dstlen = *size + 8;
         dst = av_malloc(dstlen + AV_INPUT_BUFFER_PADDING_SIZE);
         if (!dst)
@@ -3061,7 +3058,6 @@ static int matroska_parse_prores(MatroskaTrack *track, uint8_t *src,
         AV_WB32(dst + 4, MKBETAG('i', 'c', 'p', 'f'));
         memcpy(dst + 8, src, dstlen - 8);
         memset(dst + dstlen, 0, AV_INPUT_BUFFER_PADDING_SIZE);
-    }
     *pdst = dst;
     *size = dstlen;
@@ -3216,7 +3212,8 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
         pkt_data = wv_data;
-    if (st->codecpar->codec_id == AV_CODEC_ID_PRORES) {
+    if (st->codecpar->codec_id == AV_CODEC_ID_PRORES &&
+        AV_RB32(pkt_data + 4)  != MKBETAG('i', 'c', 'p', 'f')) {
         uint8_t *pr_data;
         res = matroska_parse_prores(track, pkt_data, &pr_data, &pkt_size);
         if (res < 0) {

More information about the ffmpeg-cvslog mailing list