Bug 1322961: Check SPS and PPS attributes value. r?gerald draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Mon, 12 Dec 2016 21:51:03 +1100
changeset 449463 ccc5bedd778cc0396a9d9ca03bf2393f40f2ca41
parent 449462 ad579ff2aad04ef9feaee51928e42e4fba383e56
child 449464 df75909607697aa4e9bf0eb38cb149e06e404fed
push id38568
push userbmo:jyavenard@mozilla.com
push dateWed, 14 Dec 2016 06:36:13 +0000
reviewersgerald
bugs1322961
milestone53.0a1
Bug 1322961: Check SPS and PPS attributes value. r?gerald MozReview-Commit-ID: LSngXbdQqdL
media/libstagefright/binding/H264.cpp
media/libstagefright/binding/include/mp4_demuxer/H264.h
--- a/media/libstagefright/binding/H264.cpp
+++ b/media/libstagefright/binding/H264.cpp
@@ -8,16 +8,34 @@
 #include "mp4_demuxer/BitReader.h"
 #include "mp4_demuxer/ByteReader.h"
 #include "mp4_demuxer/ByteWriter.h"
 #include "mp4_demuxer/H264.h"
 #include <media/stagefright/foundation/ABitReader.h>
 #include <limits>
 #include <cmath>
 
+#define READSE(var, min, max)                                                  \
+  {                                                                            \
+    int32_t val = br.ReadSE();                                                 \
+    if (val < min || val > max) {                                              \
+      return false;                                                            \
+    }                                                                          \
+    aDest.var = val;                                                           \
+  }
+
+#define READUE(var, max)                                                       \
+  {                                                                            \
+    uint32_t uval = br.ReadUE();                                               \
+    if (uval > max) {                                                          \
+      return false;                                                            \
+    }                                                                          \
+    aDest.var = uval;                                                          \
+  }
+
 using namespace mozilla;
 
 namespace mp4_demuxer {
 
 // Default scaling lists (per spec).
 // ITU H264:
 // Table 7-2 – Assignment of mnemonic names to scaling list indices and
 // specification of fall-back rule
@@ -252,32 +270,30 @@ H264::DecodeSPS(const mozilla::MediaByte
   aDest.constraint_set0_flag = br.ReadBit();
   aDest.constraint_set1_flag = br.ReadBit();
   aDest.constraint_set2_flag = br.ReadBit();
   aDest.constraint_set3_flag = br.ReadBit();
   aDest.constraint_set4_flag = br.ReadBit();
   aDest.constraint_set5_flag = br.ReadBit();
   br.ReadBits(2); // reserved_zero_2bits
   aDest.level_idc = br.ReadBits(8);
-  aDest.seq_parameter_set_id = br.ReadUE();
-  if (aDest.seq_parameter_set_id >= MAX_SPS_COUNT) {
-    return false;
-  }
+  READUE(seq_parameter_set_id, MAX_SPS_COUNT - 1);
 
   if (aDest.profile_idc == 100 || aDest.profile_idc == 110 ||
       aDest.profile_idc == 122 || aDest.profile_idc == 244 ||
       aDest.profile_idc == 44 || aDest.profile_idc == 83 ||
       aDest.profile_idc == 86 || aDest.profile_idc == 118 ||
       aDest.profile_idc == 128 || aDest.profile_idc == 138 ||
       aDest.profile_idc == 139 || aDest.profile_idc == 134) {
-    if ((aDest.chroma_format_idc = br.ReadUE()) == 3) {
+    READUE(chroma_format_idc, 3);
+    if (aDest.chroma_format_idc == 3) {
       aDest.separate_colour_plane_flag = br.ReadBit();
     }
-    aDest.bit_depth_luma_minus8 = br.ReadUE();
-    aDest.bit_depth_chroma_minus8 = br.ReadUE();
+    READUE(bit_depth_luma_minus8, 6);
+    READUE(bit_depth_chroma_minus8, 6);
     br.ReadBit();       // qpprime_y_zero_transform_bypass_flag
     aDest.seq_scaling_matrix_present_flag = br.ReadBit();
     if (aDest.seq_scaling_matrix_present_flag) {
       scaling_list(br, aDest.scaling_matrix4x4[0], Default_4x4_Intra,
                    Default_4x4_Intra);
       scaling_list(br, aDest.scaling_matrix4x4[1], Default_4x4_Intra,
                    aDest.scaling_matrix4x4[0]);
       scaling_list(br, aDest.scaling_matrix4x4[2], Default_4x4_Intra,
@@ -305,24 +321,26 @@ H264::DecodeSPS(const mozilla::MediaByte
       }
     }
   } else if (aDest.profile_idc == 183) {
     aDest.chroma_format_idc = 0;
   } else {
     // default value if chroma_format_idc isn't set.
     aDest.chroma_format_idc = 1;
   }
-  aDest.log2_max_frame_num = br.ReadUE() + 4;
-  aDest.pic_order_cnt_type = br.ReadUE();
+  READUE(log2_max_frame_num, 12);
+  aDest.log2_max_frame_num += 4;
+  READUE(pic_order_cnt_type, 2);
   if (aDest.pic_order_cnt_type == 0) {
-    aDest.log2_max_pic_order_cnt_lsb = br.ReadUE() + 4;
+    READUE(log2_max_pic_order_cnt_lsb, 12);
+    aDest.log2_max_pic_order_cnt_lsb += 4;
   } else if (aDest.pic_order_cnt_type == 1) {
     aDest.delta_pic_order_always_zero_flag = br.ReadBit();
-    aDest.offset_for_non_ref_pic = br.ReadSE();
-    aDest.offset_for_top_to_bottom_field = br.ReadSE();
+    READSE(offset_for_non_ref_pic, -231, 230);
+    READSE(offset_for_top_to_bottom_field, -231, 230);
     uint32_t num_ref_frames_in_pic_order_cnt_cycle = br.ReadUE();
     for (uint32_t i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++) {
       br.ReadSE(); // offset_for_ref_frame[i]
     }
   }
   aDest.max_num_ref_frames = br.ReadUE();
   aDest.gaps_in_frame_num_allowed_flag = br.ReadBit();
   aDest.pic_width_in_mbs = br.ReadUE() + 1;
@@ -339,17 +357,19 @@ H264::DecodeSPS(const mozilla::MediaByte
     aDest.frame_crop_right_offset = br.ReadUE();
     aDest.frame_crop_top_offset = br.ReadUE();
     aDest.frame_crop_bottom_offset = br.ReadUE();
   }
 
   aDest.sample_ratio = 1.0f;
   aDest.vui_parameters_present_flag = br.ReadBit();
   if (aDest.vui_parameters_present_flag) {
-    vui_parameters(br, aDest);
+    if (!vui_parameters(br, aDest)) {
+      return false;
+    }
   }
 
   // Calculate common values.
 
   uint8_t ChromaArrayType =
     aDest.separate_colour_plane_flag ? 0 : aDest.chroma_format_idc;
   // Calculate width.
   uint32_t CropUnitX = 1;
@@ -398,17 +418,17 @@ H264::DecodeSPS(const mozilla::MediaByte
     aDest.display_width = aDest.pic_width;
     aDest.display_height =
       ConditionDimension(aDest.pic_height / aDest.sample_ratio);
   }
 
   return true;
 }
 
-/* static */ void
+/* static */ bool
 H264::vui_parameters(BitReader& aBr, SPSData& aDest)
 {
   aDest.aspect_ratio_info_present_flag = aBr.ReadBit();
   if (aDest.aspect_ratio_info_present_flag) {
     aDest.aspect_ratio_idc = aBr.ReadBits(8);
     aDest.sar_width = aDest.sar_height = 0;
 
     // From E.2.1 VUI parameters semantics (ITU-T H.264 02/2014)
@@ -563,26 +583,28 @@ H264::vui_parameters(BitReader& aBr, SPS
       aDest.colour_primaries = aBr.ReadBits(8);
       aDest.transfer_characteristics = aBr.ReadBits(8);
       aDest.matrix_coefficients = aBr.ReadBits(8);
     }
   }
 
   aDest.chroma_loc_info_present_flag = aBr.ReadBit();
   if (aDest.chroma_loc_info_present_flag) {
-    aDest.chroma_sample_loc_type_top_field = aBr.ReadUE();
-    aDest.chroma_sample_loc_type_bottom_field = aBr.ReadUE();
+    BitReader& br = aBr; // so that macro READUE works
+    READUE(chroma_sample_loc_type_top_field, 5);
+    READUE(chroma_sample_loc_type_bottom_field, 5);
   }
 
   aDest.timing_info_present_flag = aBr.ReadBit();
   if (aDest.timing_info_present_flag) {
     aDest.num_units_in_tick = aBr.ReadBits(32);
     aDest.time_scale = aBr.ReadBits(32);
     aDest.fixed_frame_rate_flag = aBr.ReadBit();
   }
+  return true;
 }
 
 /* static */ bool
 H264::DecodeSPSFromExtraData(const mozilla::MediaByteBuffer* aExtraData,
                              SPSData& aDest)
 {
   H264ParametersSet ps;
   if (!DecodeSPSDataSetFromExtraData(aExtraData, ps.SPSes)) {
@@ -749,36 +771,31 @@ H264::DecodePPS(const mozilla::MediaByte
   }
 
   if (aSPSes.IsEmpty()) {
     return false;
   }
 
   BitReader br(aPPS, GetBitLength(aPPS));
 
-  aDest.pic_parameter_set_id = br.ReadUE();
-  aDest.seq_parameter_set_id = br.ReadUE();
-
-  if (aDest.pic_parameter_set_id >= MAX_PPS_COUNT ||
-      aDest.seq_parameter_set_id >= MAX_SPS_COUNT) {
-    return false;
-  }
+  READUE(pic_parameter_set_id, MAX_PPS_COUNT - 1);
+  READUE(seq_parameter_set_id, MAX_SPS_COUNT - 1);
 
   const SPSData& sps = aSPSes[aDest.seq_parameter_set_id];
 
   memcpy(aDest.scaling_matrix4x4, sps.scaling_matrix4x4,
          sizeof(aDest.scaling_matrix4x4));
   memcpy(aDest.scaling_matrix8x8, sps.scaling_matrix8x8,
          sizeof(aDest.scaling_matrix8x8));
 
   aDest.entropy_coding_mode_flag = br.ReadBit();
   aDest.bottom_field_pic_order_in_frame_present_flag = br.ReadBit();
-  aDest.num_slice_groups_minus1 = br.ReadUE();
+  READUE(num_slice_groups_minus1, 7);
   if (aDest.num_slice_groups_minus1 > 0) {
-    aDest.slice_group_map_type = br.ReadUE();
+    READUE(slice_group_map_type, 6);
     switch (aDest.slice_group_map_type) {
       case 0:
         for (uint8_t iGroup = 0; iGroup <= aDest.num_slice_groups_minus1;
              iGroup++) {
           aDest.run_length_minus1[iGroup] = br.ReadUE();
         }
         break;
       case 2:
@@ -804,28 +821,23 @@ H264::DecodePPS(const mozilla::MediaByte
             inclusive. */
           br.ReadBits(std::ceil(std::log2(aDest.num_slice_groups_minus1 + 1)));
         }
         break;
       default:
         return false;
     }
   }
-  aDest.num_ref_idx_l0_default_active_minus1 = br.ReadUE();
-  aDest.num_ref_idx_l1_default_active_minus1 = br.ReadUE();
-  if (aDest.num_ref_idx_l0_default_active_minus1 > 32 ||
-      aDest.num_ref_idx_l1_default_active_minus1 > 32) {
-    // reference overflow.
-    return false;
-  }
+  READUE(num_ref_idx_l0_default_active_minus1, 31);
+  READUE(num_ref_idx_l1_default_active_minus1, 31);
   aDest.weighted_pred_flag = br.ReadBit();
   aDest.weighted_bipred_idc = br.ReadBits(2);
-  aDest.pic_init_qp_minus26 = br.ReadSE();
-  aDest.pic_init_qs_minus26 = br.ReadSE();
-  aDest.chroma_qp_index_offset = br.ReadSE();
+  READSE(pic_init_qp_minus26, -(26 + 6 * sps.bit_depth_luma_minus8), 25);
+  READSE(pic_init_qs_minus26, -26, 26);
+  READSE(chroma_qp_index_offset, -12, 12);
   aDest.deblocking_filter_control_present_flag = br.ReadBit();
   aDest.constrained_intra_pred_flag = br.ReadBit();
   aDest.redundant_pic_cnt_present_flag = br.ReadBit();
   if (br.BitsLeft()) {
     aDest.transform_8x8_mode_flag = br.ReadBit();
     if (br.ReadBit()) { // pic_scaling_matrix_present_flag
       if (sps.seq_scaling_matrix_present_flag) {
         scaling_list(br, aDest.scaling_matrix4x4[0], Default_4x4_Intra);
@@ -865,17 +877,17 @@ H264::DecodePPS(const mozilla::MediaByte
                        aDest.scaling_matrix8x8[1]);
           scaling_list(br, aDest.scaling_matrix8x8[4], Default_8x8_Intra,
                        aDest.scaling_matrix8x8[2]);
           scaling_list(br, aDest.scaling_matrix8x8[5], Default_8x8_Inter,
                        aDest.scaling_matrix8x8[3]);
         }
       }
     }
-    aDest.second_chroma_qp_index_offset = br.ReadSE();
+    READSE(second_chroma_qp_index_offset, -12, 12);
   }
   return true;
 }
 
 /* static */ bool
 H264::DecodeParametersSet(const mozilla::MediaByteBuffer* aExtraData,
                          H264ParametersSet& aDest)
 {
@@ -932,9 +944,12 @@ H264::GetFrameType(const mozilla::MediaR
       // IDR NAL.
       return FrameType::I_FRAME;
     }
   }
 
   return FrameType::OTHER;
 }
 
+#undef READUE
+#undef READSE
+
 } // namespace mp4_demuxer
--- a/media/libstagefright/binding/include/mp4_demuxer/H264.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/H264.h
@@ -209,17 +209,17 @@ struct SPSData
 
   /*
     max_num_ref_frames specifies the maximum number of short-term and
     long-term reference frames, complementary reference field pairs,
     and non-paired reference fields that may be used by the decoding
     process for inter prediction of any picture in the
     sequence. max_num_ref_frames also determines the size of the sliding
     window operation as specified in subclause 8.2.5.3. The value of
-    max_num_ref_frames shall be in the range of 0 to MaxDpbSize (as
+    max_num_ref_frames shall be in the range of 0 to MaxDpbFrames (as
     specified in subclause A.3.1 or A.3.2), inclusive.
    */
   uint32_t max_num_ref_frames;
 
   /*
     gaps_in_frame_num_value_allowed_flag specifies the allowed
     values of frame_num as specified in subclause 7.4.3 and the
     decoding process in case of an inferred gap between values of
@@ -379,18 +379,23 @@ struct SPSData
     of transfer_characteristics shall be inferred to be equal to 2
     (the transfer characteristics are unspecified or are determined by the
     application).
    */
   uint8_t transfer_characteristics;
 
   uint8_t matrix_coefficients;
   bool chroma_loc_info_present_flag;
-  uint32_t chroma_sample_loc_type_top_field;
-  uint32_t chroma_sample_loc_type_bottom_field;
+  /*
+    The value of chroma_sample_loc_type_top_field and
+    chroma_sample_loc_type_bottom_field shall be in the range of 0 to 5,
+    inclusive
+  */
+  uint8_t chroma_sample_loc_type_top_field;
+  uint8_t chroma_sample_loc_type_bottom_field;
   bool timing_info_present_flag;
   uint32_t num_units_in_tick;
   uint32_t time_scale;
   bool fixed_frame_rate_flag;
 
   bool scaling_matrix_present;
   uint8_t scaling_matrix4x4[6][16];
   uint8_t scaling_matrix8x8[6][64];
@@ -646,16 +651,16 @@ private:
                                             const SPSDataSet& aPS,
                                             PPSDataSet& aDest);
 
   /* Decode SPS NAL RBSP and fill SPSData structure */
   static bool DecodeSPS(const mozilla::MediaByteBuffer* aSPS, SPSData& aDest);
   /* Decode PPS NAL RBSP and fill PPSData structure */
   static bool DecodePPS(const mozilla::MediaByteBuffer* aPPS,
                         const SPSDataSet& aSPSs, PPSData& aDest);
-  static void vui_parameters(BitReader& aBr, SPSData& aDest);
+  static bool vui_parameters(BitReader& aBr, SPSData& aDest);
   // Read HRD parameters, all data is ignored.
   static void hrd_parameters(BitReader& aBr);
 };
 
 } // namespace mp4_demuxer
 
 #endif // MP4_DEMUXER_H264_H_