h264: prevent decoding of slice NALs in extradata
authorJanne Grunau <janne-libav@jannau.net>
Sat, 15 Dec 2012 21:21:23 +0000 (22:21 +0100)
committerJanne Grunau <janne-libav@jannau.net>
Tue, 18 Dec 2012 10:01:14 +0000 (11:01 +0100)
It is not posible to call get_buffer during frame-mt codec
initialization. Libavformat might pass huge amounts of data as
extradata after parsing broken files. The 'extradata' for the fuzzed
sample sample_varPAR_s5374_r001-02.avi is 2.8M large and contains
multiple slices.

libavcodec/h264.c
libavcodec/h264.h

index 4146b6f..f568858 100644 (file)
@@ -954,7 +954,8 @@ fail:
     return -1; // free_tables will clean up for us
 }
 
-static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size);
+static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size,
+                            int parse_extradata);
 
 static av_cold void common_init(H264Context *h)
 {
@@ -1001,7 +1002,7 @@ int ff_h264_decode_extradata(H264Context *h)
             nalsize = AV_RB16(p) + 2;
             if (p - avctx->extradata + nalsize > avctx->extradata_size)
                 return -1;
-            if (decode_nal_units(h, p, nalsize) < 0) {
+            if (decode_nal_units(h, p, nalsize, 1) < 0) {
                 av_log(avctx, AV_LOG_ERROR,
                        "Decoding sps %d from avcC failed\n", i);
                 return -1;
@@ -1014,7 +1015,7 @@ int ff_h264_decode_extradata(H264Context *h)
             nalsize = AV_RB16(p) + 2;
             if (p - avctx->extradata + nalsize > avctx->extradata_size)
                 return -1;
-            if (decode_nal_units(h, p, nalsize) < 0) {
+            if (decode_nal_units(h, p, nalsize, 1) < 0) {
                 av_log(avctx, AV_LOG_ERROR,
                        "Decoding pps %d from avcC failed\n", i);
                 return -1;
@@ -1025,7 +1026,7 @@ int ff_h264_decode_extradata(H264Context *h)
         h->nal_length_size = (avctx->extradata[4] & 0x03) + 1;
     } else {
         h->is_avc = 0;
-        if (decode_nal_units(h, avctx->extradata, avctx->extradata_size) < 0)
+        if (decode_nal_units(h, avctx->extradata, avctx->extradata_size, 1) < 0)
             return -1;
     }
     return 0;
@@ -3708,7 +3709,8 @@ static int execute_decode_slices(H264Context *h, int context_count)
     return 0;
 }
 
-static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size)
+static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size,
+                            int parse_extradata)
 {
     MpegEncContext *const s     = &h->s;
     AVCodecContext *const avctx = s->avctx;
@@ -3831,6 +3833,17 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size)
                 continue;
 
 again:
+            /* Ignore every NAL unit type except PPS and SPS during extradata
+             * parsing. Decoding slices is not possible in codec init
+             * with frame-mt */
+            if (parse_extradata && HAVE_THREADS &&
+                (s->avctx->active_thread_type & FF_THREAD_FRAME) &&
+                (hx->nal_unit_type != NAL_PPS &&
+                 hx->nal_unit_type != NAL_SPS)) {
+                av_log(avctx, AV_LOG_INFO, "Ignoring NAL unit %d during "
+                       "extradata parsing\n", hx->nal_unit_type);
+                hx->nal_unit_type = NAL_FF_IGNORE;
+            }
             err = 0;
             switch (hx->nal_unit_type) {
             case NAL_IDR_SLICE:
@@ -3953,6 +3966,8 @@ again:
             case NAL_SPS_EXT:
             case NAL_AUXILIARY_SLICE:
                 break;
+            case NAL_FF_IGNORE:
+                break;
             default:
                 av_log(avctx, AV_LOG_DEBUG, "Unknown NAL code: %d (%d bits)\n",
                        hx->nal_unit_type, bit_length);
@@ -4049,7 +4064,7 @@ out:
         return buf_index;
     }
 
-    buf_index = decode_nal_units(h, buf, buf_size);
+    buf_index = decode_nal_units(h, buf, buf_size, 0);
     if (buf_index < 0)
         return -1;
 
index 3c99030..3049470 100644 (file)
@@ -112,7 +112,8 @@ enum {
     NAL_END_STREAM,
     NAL_FILLER_DATA,
     NAL_SPS_EXT,
-    NAL_AUXILIARY_SLICE = 19
+    NAL_AUXILIARY_SLICE = 19,
+    NAL_FF_IGNORE       = 0xff0f001,
 };
 
 /**