diff --git a/webrtc/common_video/h264/h264_bitstream_parser.cc b/webrtc/common_video/h264/h264_bitstream_parser.cc index 048cdd2f6e..4ad0ed4b28 100644 --- a/webrtc/common_video/h264/h264_bitstream_parser.cc +++ b/webrtc/common_video/h264/h264_bitstream_parser.cc @@ -19,6 +19,12 @@ #include "webrtc/common_video/h264/h264_common.h" #include "webrtc/base/logging.h" +namespace { +const int kMaxAbsQpDeltaValue = 51; +const int kMinQpValue = 0; +const int kMaxQpValue = 51; +} + namespace webrtc { #define RETURN_ON_FAIL(x, res) \ @@ -251,6 +257,12 @@ H264BitstreamParser::Result H264BitstreamParser::ParseNonParameterSetNalu( int32_t last_slice_qp_delta; RETURN_INV_ON_FAIL( slice_reader.ReadSignedExponentialGolomb(&last_slice_qp_delta)); + if (abs(last_slice_qp_delta) > kMaxAbsQpDeltaValue) { + // Something has gone wrong, and the parsed value is invalid. + LOG(LS_WARNING) << "Parsed QP value out of range."; + return kInvalidStream; + } + last_slice_qp_delta_ = rtc::Optional(last_slice_qp_delta); return kOk; } @@ -291,7 +303,12 @@ void H264BitstreamParser::ParseBitstream(const uint8_t* bitstream, bool H264BitstreamParser::GetLastSliceQp(int* qp) const { if (!last_slice_qp_delta_ || !pps_) return false; - *qp = 26 + pps_->pic_init_qp_minus26 + *last_slice_qp_delta_; + const int parsed_qp = 26 + pps_->pic_init_qp_minus26 + *last_slice_qp_delta_; + if (parsed_qp < kMinQpValue || parsed_qp > kMaxQpValue) { + LOG(LS_ERROR) << "Parsed invalid QP from bitstream."; + return false; + } + *qp = parsed_qp; return true; } diff --git a/webrtc/common_video/h264/pps_parser.cc b/webrtc/common_video/h264/pps_parser.cc index 0215549959..b2860c221f 100644 --- a/webrtc/common_video/h264/pps_parser.cc +++ b/webrtc/common_video/h264/pps_parser.cc @@ -22,6 +22,11 @@ return rtc::Optional(); \ } +namespace { +const int kMaxPicInitQpDeltaValue = 25; +const int kMinPicInitQpDeltaValue = -26; +} + namespace webrtc { // General note: this is based off the 02/2014 version of the H.264 standard. @@ -162,6 +167,11 @@ rtc::Optional PpsParser::ParseInternal( // pic_init_qp_minus26: se(v) RETURN_EMPTY_ON_FAIL( bit_buffer->ReadSignedExponentialGolomb(&pps.pic_init_qp_minus26)); + // Sanity-check parsed value + if (pps.pic_init_qp_minus26 > kMaxPicInitQpDeltaValue || + pps.pic_init_qp_minus26 < kMinPicInitQpDeltaValue) { + RETURN_EMPTY_ON_FAIL(false); + } // pic_init_qs_minus26: se(v) RETURN_EMPTY_ON_FAIL(bit_buffer->ReadExponentialGolomb(&golomb_ignored)); // chroma_qp_index_offset: se(v) diff --git a/webrtc/common_video/h264/pps_parser_unittest.cc b/webrtc/common_video/h264/pps_parser_unittest.cc index b9ec92ba25..03490647c0 100644 --- a/webrtc/common_video/h264/pps_parser_unittest.cc +++ b/webrtc/common_video/h264/pps_parser_unittest.cc @@ -201,7 +201,7 @@ TEST_F(PpsParserTest, ZeroPps) { TEST_F(PpsParserTest, MaxPps) { generated_pps_.bottom_field_pic_order_in_frame_present_flag = true; - generated_pps_.pic_init_qp_minus26 = std::numeric_limits::max(); + generated_pps_.pic_init_qp_minus26 = 25; generated_pps_.redundant_pic_cnt_present_flag = 1; // 1 bit value. generated_pps_.weighted_bipred_idc = (1 << 2) - 1; // 2 bit value. generated_pps_.weighted_pred_flag = true; @@ -210,7 +210,7 @@ TEST_F(PpsParserTest, MaxPps) { generated_pps_.sps_id = 1; RunTest(); - generated_pps_.pic_init_qp_minus26 = std::numeric_limits::min() + 1; + generated_pps_.pic_init_qp_minus26 = -25; RunTest(); }