Vulnerability: In FFmpeg 4.0.1, due to a missing check of a profile value before setting it, the ff_mpeg4_decode_picture_header function in libavcodec/mpeg4videodec.c may trigger a NULL pointer dereference while converting a crafted AVI file to MPEG4, leading to a denial of service.
Vulnerability ID: CVE-2018-13301
CWE: CWE-476
Severity score: 2.9
Project: https://github.com/FFmpeg/FFmpeg
Published: 2018-07-05
File: libavcodec/mpeg4videodec.c
Commit message: avcodec/mpeg4videodec: Check read profile before setting it

Fixes: null pointer dereference
Fixes: ffmpeg_crash_7.avi

Found-by: Thuan Pham, Marcel Böhme, Andrew Santosa and Alexandru Razvan Caciulescu with AFLSmart
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
Commit author: Michael Niedermayer

Vulnerable version (before fix):
 static int mpeg4_decode_gop_header(MpegEncContext *s, GetBitContext *gb)     return 0; }  static int mpeg4_decode_profile_level(MpegEncContext *s, GetBitContext *gb) {      s->avctx->profile = get_bits(gb, 4);     s->avctx->level   = get_bits(gb, 4);      // for Simple profile, level 0     if (s->avctx->profile == 0 && s->avctx->level == 8) {         s->avctx->level = 0;     }      return 0; int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb)         } else if (startcode == GOP_STARTCODE) {             mpeg4_decode_gop_header(s, gb);         } else if (startcode == VOS_STARTCODE) {             mpeg4_decode_profile_level(s, gb);             if (s->avctx->profile == FF_PROFILE_MPEG4_SIMPLE_STUDIO &&                 (s->avctx->level > 0 && s->avctx->level < 9)) {                 s->studio_profile = 1;                 next_start_code_studio(gb);                 extension_and_user_data(s, gb, 0);             }         } else if (startcode == VISUAL_OBJ_STARTCODE) {             if (s->studio_profile) {                 if ((ret = decode_studiovisualobject(ctx, gb)) < 0) int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb)     s->avctx->has_b_frames = !s->low_delay;      if (s->studio_profile) {         if (!s->avctx->bits_per_raw_sample) {             av_log(s->avctx, AV_LOG_ERROR, "Missing VOL header\n");             return AVERROR_INVALIDDATA;

Fixed version (after fix):
 static int mpeg4_decode_gop_header(MpegEncContext *s, GetBitContext *gb)     return 0; }  static int mpeg4_decode_profile_level(MpegEncContext *s, GetBitContext *gb, int *profile, int *level) {      *profile = get_bits(gb, 4);     *level   = get_bits(gb, 4);      // for Simple profile, level 0     if (*profile == 0 && *level == 8) {         *level = 0;     }      return 0; int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb)         } else if (startcode == GOP_STARTCODE) {             mpeg4_decode_gop_header(s, gb);         } else if (startcode == VOS_STARTCODE) {             int profile, level;             mpeg4_decode_profile_level(s, gb, &profile, &level);             if (profile == FF_PROFILE_MPEG4_SIMPLE_STUDIO &&                 (level > 0 && level < 9)) {                 s->studio_profile = 1;                 next_start_code_studio(gb);                 extension_and_user_data(s, gb, 0);             } else if (s->studio_profile) {                 avpriv_request_sample(s->avctx, "Mixes studio and non studio profile\n");                 return AVERROR_PATCHWELCOME;             }             s->avctx->profile = profile;             s->avctx->level   = level;         } else if (startcode == VISUAL_OBJ_STARTCODE) {             if (s->studio_profile) {                 if ((ret = decode_studiovisualobject(ctx, gb)) < 0) int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb)     s->avctx->has_b_frames = !s->low_delay;      if (s->studio_profile) {         av_assert0(s->avctx->profile == FF_PROFILE_MPEG4_SIMPLE_STUDIO);         if (!s->avctx->bits_per_raw_sample) {             av_log(s->avctx, AV_LOG_ERROR, "Missing VOL header\n");             return AVERROR_INVALIDDATA;

Patch:
patch: @@ -1980,15 +1980,15 @@ static int mpeg4_decode_gop_header(MpegEncContext *s, GetBitContext *gb)
     return 0;
 }
 
-static int mpeg4_decode_profile_level(MpegEncContext *s, GetBitContext *gb)
+static int mpeg4_decode_profile_level(MpegEncContext *s, GetBitContext *gb, int *profile, int *level)
 {
 
-    s->avctx->profile = get_bits(gb, 4);
-    s->avctx->level   = get_bits(gb, 4);
+    *profile = get_bits(gb, 4);
+    *level   = get_bits(gb, 4);
 
     // for Simple profile, level 0
-    if (s->avctx->profile == 0 && s->avctx->level == 8) {
-        s->avctx->level = 0;
+    if (*profile == 0 && *level == 8) {
+        *level = 0;
     }
 
     return 0;
@@ -3211,13 +3211,19 @@ int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb)
         } else if (startcode == GOP_STARTCODE) {
             mpeg4_decode_gop_header(s, gb);
         } else if (startcode == VOS_STARTCODE) {
-            mpeg4_decode_profile_level(s, gb);
-            if (s->avctx->profile == FF_PROFILE_MPEG4_SIMPLE_STUDIO &&
-                (s->avctx->level > 0 && s->avctx->level < 9)) {
+            int profile, level;
+            mpeg4_decode_profile_level(s, gb, &profile, &level);
+            if (profile == FF_PROFILE_MPEG4_SIMPLE_STUDIO &&
+                (level > 0 && level < 9)) {
                 s->studio_profile = 1;
                 next_start_code_studio(gb);
                 extension_and_user_data(s, gb, 0);
+            } else if (s->studio_profile) {
+                avpriv_request_sample(s->avctx, "Mixes studio and non studio profile\n");
+                return AVERROR_PATCHWELCOME;
             }
+            s->avctx->profile = profile;
+            s->avctx->level   = level;
         } else if (startcode == VISUAL_OBJ_STARTCODE) {
             if (s->studio_profile) {
                 if ((ret = decode_studiovisualobject(ctx, gb)) < 0)
@@ -3238,6 +3244,7 @@ int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb)
     s->avctx->has_b_frames = !s->low_delay;
 
     if (s->studio_profile) {
+        av_assert0(s->avctx->profile == FF_PROFILE_MPEG4_SIMPLE_STUDIO);
         if (!s->avctx->bits_per_raw_sample) {
             av_log(s->avctx, AV_LOG_ERROR, "Missing VOL header\n");
             return AVERROR_INVALIDDATA;
path: libavcodec/mpeg4videodec.c