CVE-2018-1999010: Out-of-bounds Read (CWE-125)
value: FFmpeg before commit cced03dd667a5df6df8fd40d8de0bff477ee02e8 contains multiple out of array access vulnerabilities in the mms protocol that can result in attackers accessing out of bound data. This attack appear to be exploitable via network connectivity. This vulnerability appears to have been fixed in cced03dd667a5df6df8fd40d8de0bff477ee02e8 and later.
CWE description: The product reads data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 9.8
Published: 2018-07-23T15:29Z
Repository: https://github.com/FFmpeg/FFmpeg
Language: C
Files changed: libavformat/mms.c
Commit date: 2018-07-06 12:36:09 +0200
Commit message: avformat/mms: Add missing chunksize check

Fixes: out of array read
Fixes: mms-crash-01b6c5d85f9d9f40f4e879896103e9f5b222816a

Found-by: Paul Ch <paulcher@icloud.com>
1st hunk by Paul Ch <paulcher@icloud.com>
Tested-by: Paul Ch <paulcher@icloud.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>

Diff: diff --git a/libavformat/mms.c b/libavformat/mms.c
index 17fa76a8d44d..768fda652543 100644
--- a/libavformat/mms.c
+++ b/libavformat/mms.c
@@ -92,28 +92,30 @@ int ff_mms_asf_header_parser(MMSContext *mms)
                            mms->asf_packet_len);
                     return AVERROR_INVALIDDATA;
                 }
             }
         } else if (!memcmp(p, ff_asf_stream_header, sizeof(ff_asf_guid))) {
-            flags     = AV_RL16(p + sizeof(ff_asf_guid)*3 + 24);
-            stream_id = flags & 0x7F;
-            //The second condition is for checking CS_PKT_STREAM_ID_REQUEST packet size,
-            //we can calculate the packet size by stream_num.
-            //Please see function send_stream_selection_request().
-            if (mms->stream_num < MMS_MAX_STREAMS &&
-                    46 + mms->stream_num * 6 < sizeof(mms->out_buffer)) {
-                mms->streams = av_fast_realloc(mms->streams,
-                                   &mms->nb_streams_allocated,
-                                   (mms->stream_num + 1) * sizeof(MMSStream));
-                if (!mms->streams)
-                    return AVERROR(ENOMEM);
-                mms->streams[mms->stream_num].id = stream_id;
-                mms->stream_num++;
-            } else {
-                av_log(NULL, AV_LOG_ERROR,
-                       "Corrupt stream (too many A/V streams)\n");
-                return AVERROR_INVALIDDATA;
+            if (end - p >= (sizeof(ff_asf_guid) * 3 + 26)) {
+                flags     = AV_RL16(p + sizeof(ff_asf_guid)*3 + 24);
+                stream_id = flags & 0x7F;
+                //The second condition is for checking CS_PKT_STREAM_ID_REQUEST packet size,
+                //we can calculate the packet size by stream_num.
+                //Please see function send_stream_selection_request().
+                if (mms->stream_num < MMS_MAX_STREAMS &&
+                        46 + mms->stream_num * 6 < sizeof(mms->out_buffer)) {
+                    mms->streams = av_fast_realloc(mms->streams,
+                                       &mms->nb_streams_allocated,
+                                       (mms->stream_num + 1) * sizeof(MMSStream));
+                    if (!mms->streams)
+                        return AVERROR(ENOMEM);
+                    mms->streams[mms->stream_num].id = stream_id;
+                    mms->stream_num++;
+                } else {
+                    av_log(NULL, AV_LOG_ERROR,
+                           "Corrupt stream (too many A/V streams)\n");
+                    return AVERROR_INVALIDDATA;
+                }
             }
         } else if (!memcmp(p, ff_asf_ext_stream_header, sizeof(ff_asf_guid))) {
             if (end - p >= 88) {
                 int stream_count = AV_RL16(p + 84), ext_len_count = AV_RL16(p + 86);
                 uint64_t skip_bytes = 88;
@@ -141,10 +143,16 @@ int ff_mms_asf_header_parser(MMSContext *mms)
                 if (chunksize - skip_bytes > 24)
                     chunksize = skip_bytes;
             }
         } else if (!memcmp(p, ff_asf_head1_guid, sizeof(ff_asf_guid))) {
             chunksize = 46; // see references [2] section 3.4. This should be set 46.
+            if (chunksize > end - p) {
+                av_log(NULL, AV_LOG_ERROR,
+                    "Corrupt stream (header chunksize %"PRId64" is invalid)\n",
+                    chunksize);
+                return AVERROR_INVALIDDATA;
+            }
         }
         p += chunksize;
     }
 
     return 0;

Vulnerable code:             flags     = AV_RL16(p + sizeof(ff_asf_guid)*3 + 24);
            stream_id = flags & 0x7F;
            //The second condition is for checking CS_PKT_STREAM_ID_REQUEST packet size,
            //we can calculate the packet size by stream_num.
            //Please see function send_stream_selection_request().
            if (mms->stream_num < MMS_MAX_STREAMS &&
                    46 + mms->stream_num * 6 < sizeof(mms->out_buffer)) {
                mms->streams = av_fast_realloc(mms->streams,
                                   &mms->nb_streams_allocated,
                                   (mms->stream_num + 1) * sizeof(MMSStream));
                if (!mms->streams)
                    return AVERROR(ENOMEM);
                mms->streams[mms->stream_num].id = stream_id;
                mms->stream_num++;
            } else {
                av_log(NULL, AV_LOG_ERROR,
                       "Corrupt stream (too many A/V streams)\n");
                return AVERROR_INVALIDDATA;
Fixed code:             if (end - p >= (sizeof(ff_asf_guid) * 3 + 26)) {
                flags     = AV_RL16(p + sizeof(ff_asf_guid)*3 + 24);
                stream_id = flags & 0x7F;
                //The second condition is for checking CS_PKT_STREAM_ID_REQUEST packet size,
                //we can calculate the packet size by stream_num.
                //Please see function send_stream_selection_request().
                if (mms->stream_num < MMS_MAX_STREAMS &&
                        46 + mms->stream_num * 6 < sizeof(mms->out_buffer)) {
                    mms->streams = av_fast_realloc(mms->streams,
                                       &mms->nb_streams_allocated,
                                       (mms->stream_num + 1) * sizeof(MMSStream));
                    if (!mms->streams)
                        return AVERROR(ENOMEM);
                    mms->streams[mms->stream_num].id = stream_id;
                    mms->stream_num++;
                } else {
                    av_log(NULL, AV_LOG_ERROR,
                           "Corrupt stream (too many A/V streams)\n");
                    return AVERROR_INVALIDDATA;
                }
            if (chunksize > end - p) {
                av_log(NULL, AV_LOG_ERROR,
                    "Corrupt stream (header chunksize %"PRId64" is invalid)\n",
                    chunksize);
                return AVERROR_INVALIDDATA;
            }