CVE-2020-35964: Out-of-bounds Write (CWE-787)
value: track_header in libavformat/vividas.c in FFmpeg 4.3.1 has an out-of-bounds write because of incorrect extradata packing.
CWE description: The product writes data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 6.5
Published: 2021-01-03T19:15Z
Repository: https://github.com/FFmpeg/FFmpeg
Language: C
Files changed: libavformat/vividas.c
Commit date: 2020-11-04 23:30:53 +0100
Commit message: avformat/vividas: improve extradata packing checks in track_header()

Fixes: out of array accesses
Fixes: 26622/clusterfuzz-testcase-minimized-ffmpeg_dem_VIVIDAS_fuzzer-6581200338288640

Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>

Diff: diff --git a/libavformat/vividas.c b/libavformat/vividas.c
index 83d0ed116787..46c66bf9a0ae 100644
--- a/libavformat/vividas.c
+++ b/libavformat/vividas.c
@@ -26,10 +26,11 @@
  * @brief Vividas VIV (.viv) file demuxer
  * @author Andrzej Szombierski [qq at kuku eu org] (2010-07)
  * @sa http://wiki.multimedia.cx/index.php?title=Vividas_VIV
  */
 
+#include "libavutil/avassert.h"
 #include "libavutil/intreadwrite.h"
 #include "avio_internal.h"
 #include "avformat.h"
 #include "internal.h"
 
@@ -377,11 +378,11 @@ static int track_header(VividasDemuxContext *viv, AVFormatContext *s,  uint8_t *
         avio_seek(pb, q, SEEK_CUR); // data_2
         avio_r8(pb); // zeropad
 
         if (avio_tell(pb) < off) {
             int num_data;
-            int xd_size = 0;
+            int xd_size = 1;
             int data_len[256];
             int offset = 1;
             uint8_t *p;
             ffio_read_varlen(pb); // val_13
             avio_r8(pb); // '19'
@@ -391,35 +392,34 @@ static int track_header(VividasDemuxContext *viv, AVFormatContext *s,  uint8_t *
                 uint64_t len = ffio_read_varlen(pb);
                 if (len > INT_MAX/2 - xd_size) {
                     return AVERROR_INVALIDDATA;
                 }
                 data_len[j] = len;
-                xd_size += len;
+                xd_size += len + 1 + len/255;
             }
 
-            ret = ff_alloc_extradata(st->codecpar, 64 + xd_size + xd_size / 255);
+            ret = ff_alloc_extradata(st->codecpar, xd_size);
             if (ret < 0)
                 return ret;
 
             p = st->codecpar->extradata;
             p[0] = 2;
 
             for (j = 0; j < num_data - 1; j++) {
                 unsigned delta = av_xiphlacing(&p[offset], data_len[j]);
-                if (delta > data_len[j]) {
-                    return AVERROR_INVALIDDATA;
-                }
+                av_assert0(delta <= xd_size - offset);
                 offset += delta;
             }
 
             for (j = 0; j < num_data; j++) {
                 int ret = avio_read(pb, &p[offset], data_len[j]);
                 if (ret < data_len[j]) {
                     st->codecpar->extradata_size = 0;
                     av_freep(&st->codecpar->extradata);
                     break;
                 }
+                av_assert0(data_len[j] <= xd_size - offset);
                 offset += data_len[j];
             }
 
             if (offset < st->codecpar->extradata_size)
                 st->codecpar->extradata_size = offset;

Vulnerable code:             int xd_size = 0;
                xd_size += len;
            ret = ff_alloc_extradata(st->codecpar, 64 + xd_size + xd_size / 255);
                if (delta > data_len[j]) {
                    return AVERROR_INVALIDDATA;
                }
Fixed code: #include "libavutil/avassert.h"
            int xd_size = 1;
                xd_size += len + 1 + len/255;
            ret = ff_alloc_extradata(st->codecpar, xd_size);
                av_assert0(delta <= xd_size - offset);
                av_assert0(data_len[j] <= xd_size - offset);