CVE-2022-2566: Integer Overflow or Wraparound (CWE-190)
value: A heap out-of-bounds memory write exists in FFMPEG since version 5.1. The size calculation in `build_open_gop_key_points()` goes through all entries in the loop and adds `sc->ctts_data[i].count` to `sc->sample_offsets_count`. This can lead to an integer overflow resulting in a small allocation with `av_calloc()`. An attacker can cause remote code execution via a malicious mp4 file. We recommend upgrading past commit c953baa084607dd1d84c3bfcce3cf6a87c3e6e05
CWE description: The product performs a calculation that can
         produce an integer overflow or wraparound when the logic
         assumes that the resulting value will always be larger than
         the original value. This occurs when an integer value is
         incremented to a value that is too large to store in the
         associated representation. When this occurs, the value may
         become a very small or negative number.
CVSS v3 base score: 7.8
Published: 2022-09-23T12:15Z
Repository: https://github.com/FFmpeg/FFmpeg
Language: C
Files changed: libavformat/mov.c
Commit date: 2022-08-28 22:06:45 +0200
Commit message: avformat/mov: Check count sums in build_open_gop_key_points()

Fixes: ffmpeg.md
Fixes: Out of array access
Fixes: CVE-2022-2566

Found-by: Andy Nguyen <theflow@google.com>
Found-by: 3pvd <3pvd@google.com>
Reviewed-by: Andy Nguyen <theflow@google.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>

Diff: diff --git a/libavformat/mov.c b/libavformat/mov.c
index 1d8c5b2904e8c..35e2271b147dd 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -3965,12 +3965,15 @@ static int build_open_gop_key_points(AVStream *st)
     if (st->codecpar->codec_id != AV_CODEC_ID_HEVC || !sc->sync_group_count)
         return 0;
 
     /* Build an unrolled index of the samples */
     sc->sample_offsets_count = 0;
-    for (uint32_t i = 0; i < sc->ctts_count; i++)
+    for (uint32_t i = 0; i < sc->ctts_count; i++) {
+        if (sc->ctts_data[i].count > INT_MAX - sc->sample_offsets_count)
+            return AVERROR(ENOMEM);
         sc->sample_offsets_count += sc->ctts_data[i].count;
+    }
     av_freep(&sc->sample_offsets);
     sc->sample_offsets = av_calloc(sc->sample_offsets_count, sizeof(*sc->sample_offsets));
     if (!sc->sample_offsets)
         return AVERROR(ENOMEM);
     k = 0;
@@ -3985,22 +3988,27 @@ static int build_open_gop_key_points(AVStream *st)
         return 0;
 
     /* Build a list of open-GOP key samples */
     sc->open_key_samples_count = 0;
     for (uint32_t i = 0; i < sc->sync_group_count; i++)
-        if (sc->sync_group[i].index == cra_index)
+        if (sc->sync_group[i].index == cra_index) {
+            if (sc->sync_group[i].count > INT_MAX - sc->open_key_samples_count)
+                return AVERROR(ENOMEM);
             sc->open_key_samples_count += sc->sync_group[i].count;
+        }
     av_freep(&sc->open_key_samples);
     sc->open_key_samples = av_calloc(sc->open_key_samples_count, sizeof(*sc->open_key_samples));
     if (!sc->open_key_samples)
         return AVERROR(ENOMEM);
     k = 0;
     for (uint32_t i = 0; i < sc->sync_group_count; i++) {
         const MOVSbgp *sg = &sc->sync_group[i];
         if (sg->index == cra_index)
             for (uint32_t j = 0; j < sg->count; j++)
                 sc->open_key_samples[k++] = sample_id;
+        if (sg->count > INT_MAX - sample_id)
+            return AVERROR_PATCHWELCOME;
         sample_id += sg->count;
     }
 
     /* Identify the minimal time step between samples */
     sc->min_sample_duration = UINT_MAX;

Vulnerable code:     for (uint32_t i = 0; i < sc->ctts_count; i++)
        if (sc->sync_group[i].index == cra_index)
Fixed code:     for (uint32_t i = 0; i < sc->ctts_count; i++) {
        if (sc->ctts_data[i].count > INT_MAX - sc->sample_offsets_count)
            return AVERROR(ENOMEM);
    }
        if (sc->sync_group[i].index == cra_index) {
            if (sc->sync_group[i].count > INT_MAX - sc->open_key_samples_count)
                return AVERROR(ENOMEM);
        }
        if (sg->count > INT_MAX - sample_id)
            return AVERROR_PATCHWELCOME;