Fix fuzzing issue reported by Chromium fuzzing test
Bug: chromium:1475195, chromium:1475944, chromium:1475909
Change-Id: Iaa9dc6570a8b70ec58efe0a64d468e1cae4cb484
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/317504
Reviewed-by: Sergey Silkin <ssilkin@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Commit-Queue: Sergey Silkin <ssilkin@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40696}
diff --git a/common_video/h265/h265_bitstream_parser.cc b/common_video/h265/h265_bitstream_parser.cc
index 2509398..ee77166 100644
--- a/common_video/h265/h265_bitstream_parser.cc
+++ b/common_video/h265/h265_bitstream_parser.cc
@@ -151,8 +151,6 @@
}
uint32_t num_long_term_sps = 0;
uint32_t num_long_term_pics = 0;
- std::vector<uint32_t> lt_idx_sps;
- std::vector<uint32_t> poc_lsb_lt;
std::vector<bool> used_by_curr_pic_lt_flag;
bool short_term_ref_pic_set_sps_flag = false;
uint32_t short_term_ref_pic_set_idx = 0;
@@ -188,6 +186,8 @@
if (short_term_ref_pic_set_idx_bits > 0) {
short_term_ref_pic_set_idx =
slice_reader.ReadBits(short_term_ref_pic_set_idx_bits);
+ IN_RANGE_OR_RETURN(short_term_ref_pic_set_idx, 0,
+ sps->num_short_term_ref_pic_sets - 1);
}
}
if (sps->long_term_ref_pics_present_flag) {
@@ -201,27 +201,26 @@
num_long_term_pics = slice_reader.ReadExponentialGolomb();
IN_RANGE_OR_RETURN(num_long_term_pics, 0,
kMaxLongTermRefPicSets - num_long_term_sps);
- lt_idx_sps.resize(num_long_term_sps + num_long_term_pics, 0);
used_by_curr_pic_lt_flag.resize(num_long_term_sps + num_long_term_pics,
0);
- poc_lsb_lt.resize(num_long_term_sps + num_long_term_pics, 0);
for (uint32_t i = 0; i < num_long_term_sps + num_long_term_pics; i++) {
if (i < num_long_term_sps) {
- uint32_t lt_idx_sps_bits = 0;
+ uint32_t lt_idx_sps = 0;
if (sps->num_long_term_ref_pics_sps > 1) {
// lt_idx_sps: u(v)
- lt_idx_sps_bits =
+ uint32_t lt_idx_sps_bits =
H265::Log2Ceiling(sps->num_long_term_ref_pics_sps);
- lt_idx_sps[i] = slice_reader.ReadBits(lt_idx_sps_bits);
+ lt_idx_sps = slice_reader.ReadBits(lt_idx_sps_bits);
+ IN_RANGE_OR_RETURN(lt_idx_sps, 0,
+ sps->num_long_term_ref_pics_sps - 1);
}
- poc_lsb_lt[i] = sps->lt_ref_pic_poc_lsb_sps[lt_idx_sps_bits];
used_by_curr_pic_lt_flag[i] =
- sps->used_by_curr_pic_lt_sps_flag[lt_idx_sps_bits];
+ sps->used_by_curr_pic_lt_sps_flag[lt_idx_sps];
} else {
// poc_lsb_lt: u(v)
uint32_t poc_lsb_lt_bits =
sps->log2_max_pic_order_cnt_lsb_minus4 + 4;
- poc_lsb_lt[i] = slice_reader.ReadBits(poc_lsb_lt_bits);
+ slice_reader.ConsumeBits(poc_lsb_lt_bits);
// used_by_curr_pic_lt_flag: u(1)
used_by_curr_pic_lt_flag[i] = slice_reader.Read<bool>();
}
@@ -375,20 +374,22 @@
return kUnsupportedStream;
}
// five_minus_max_num_merge_cand: ue(v)
- int five_minus_max_num_merge_cand = slice_reader.ReadExponentialGolomb();
+ uint32_t five_minus_max_num_merge_cand =
+ slice_reader.ReadExponentialGolomb();
IN_RANGE_OR_RETURN(5 - five_minus_max_num_merge_cand, 1, 5);
}
}
// slice_qp_delta: se(v)
int32_t last_slice_qp_delta = slice_reader.ReadSignedExponentialGolomb();
- IN_RANGE_OR_RETURN(26 + pps->init_qp_minus26 + last_slice_qp_delta,
- -pps->qp_bd_offset_y, 51);
if (!slice_reader.Ok() || (abs(last_slice_qp_delta) > kMaxAbsQpDeltaValue)) {
// Something has gone wrong, and the parsed value is invalid.
- RTC_LOG(LS_WARNING) << "Parsed QP value out of range.";
+ RTC_LOG(LS_ERROR) << "Parsed QP value out of range.";
return kInvalidStream;
}
+ // 7-54 in H265 spec.
+ IN_RANGE_OR_RETURN(26 + pps->init_qp_minus26 + last_slice_qp_delta,
+ -pps->qp_bd_offset_y, 51);
last_slice_qp_delta_ = last_slice_qp_delta;
last_slice_pps_id_ = pps_id;
diff --git a/common_video/h265/h265_bitstream_parser_unittest.cc b/common_video/h265/h265_bitstream_parser_unittest.cc
index 34986e6..7ca9794 100644
--- a/common_video/h265/h265_bitstream_parser_unittest.cc
+++ b/common_video/h265/h265_bitstream_parser_unittest.cc
@@ -67,6 +67,30 @@
0xbe, 0x6b, 0x15, 0x48, 0x59, 0x1f, 0xf7, 0xc1, 0x7c, 0xe2, 0xe8, 0x10,
};
+// Contains enough of the image slice to contain invalid slice QP -52.
+const uint8_t kH265BitstreamInvalidQPChunk[] = {
+ 0x00, 0x00, 0x00, 0x01, 0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x04, 0x08,
+ 0x00, 0x00, 0x03, 0x00, 0x9d, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x78,
+ 0x95, 0x98, 0x09, 0x00, 0x00, 0x00, 0x01, 0x42, 0x01, 0x01, 0x04, 0x08,
+ 0x00, 0x00, 0x03, 0x00, 0x9d, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x78,
+ 0xb0, 0x03, 0xc0, 0x80, 0x10, 0xe5, 0x96, 0x56, 0x69, 0x24, 0xca, 0xe0,
+ 0x10, 0x00, 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x03, 0x01, 0xe0, 0x80,
+ 0x00, 0x00, 0x00, 0x01, 0x44, 0x01, 0xc1, 0x72, 0xb4, 0x62, 0x40, 0x00,
+ 0x00, 0x01, 0x26, 0x01, 0xaf, 0x03, 0x4c,
+};
+
+// Contains enough of the image slice to contain invalid slice QP 52.
+const uint8_t kH265BitstreamInvalidQPChunk52[] = {
+ 0x00, 0x00, 0x00, 0x01, 0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x04, 0x08,
+ 0x00, 0x00, 0x03, 0x00, 0x9d, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x78,
+ 0x95, 0x98, 0x09, 0x00, 0x00, 0x00, 0x01, 0x42, 0x01, 0x01, 0x04, 0x08,
+ 0x00, 0x00, 0x03, 0x00, 0x9d, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x78,
+ 0xb0, 0x03, 0xc0, 0x80, 0x10, 0xe5, 0x96, 0x56, 0x69, 0x24, 0xca, 0xe0,
+ 0x10, 0x00, 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x03, 0x01, 0xe0, 0x80,
+ 0x00, 0x00, 0x00, 0x01, 0x44, 0x01, 0xc1, 0x72, 0xb4, 0x62, 0x40, 0x00,
+ 0x00, 0x01, 0x26, 0x01, 0xaf, 0x03, 0x44,
+};
+
TEST(H265BitstreamParserTest, ReportsNoQpWithoutParsedSlices) {
H265BitstreamParser h265_parser;
EXPECT_FALSE(h265_parser.GetLastSliceQp().has_value());
@@ -109,4 +133,15 @@
EXPECT_EQ(1u, *pps_id);
}
+TEST(H265BitstreamParserTest, ReportsLastSliceQpInvalidQPSlices) {
+ H265BitstreamParser h265_parser;
+ h265_parser.ParseBitstream(kH265BitstreamInvalidQPChunk);
+ absl::optional<int> qp = h265_parser.GetLastSliceQp();
+ ASSERT_FALSE(qp.has_value());
+
+ h265_parser.ParseBitstream(kH265BitstreamInvalidQPChunk52);
+ qp = h265_parser.GetLastSliceQp();
+ ASSERT_FALSE(qp.has_value());
+}
+
} // namespace webrtc
diff --git a/common_video/h265/h265_pps_parser.cc b/common_video/h265/h265_pps_parser.cc
index 419fe31..1cc9abd 100644
--- a/common_video/h265/h265_pps_parser.cc
+++ b/common_video/h265/h265_pps_parser.cc
@@ -228,12 +228,6 @@
}
// lists_modification_present_flag: u(1)
pps.lists_modification_present_flag = reader.Read<bool>();
- // log2_parallel_merge_level_minus2: ue(v)
- uint32_t log2_parallel_merge_level_minus2 = reader.ReadExponentialGolomb();
- IN_RANGE_OR_RETURN_NULL(log2_parallel_merge_level_minus2, 0,
- sps->ctb_log2_size_y - 2);
- // slice_segment_header_extension_present_flag: u(1)
- reader.ConsumeBits(1);
if (!reader.Ok()) {
return absl::nullopt;
diff --git a/common_video/h265/h265_sps_parser.cc b/common_video/h265/h265_sps_parser.cc
index 4dcfa1f..96aee7c 100644
--- a/common_video/h265/h265_sps_parser.cc
+++ b/common_video/h265/h265_sps_parser.cc
@@ -63,8 +63,6 @@
namespace webrtc {
-H265SpsParser::SpsState::SpsState() = default;
-
H265SpsParser::ShortTermRefPicSet::ShortTermRefPicSet() = default;
H265SpsParser::ProfileTierLevel::ProfileTierLevel() = default;
@@ -113,30 +111,23 @@
}
bool H265SpsParser::ParseScalingListData(BitstreamReader& reader) {
- uint32_t scaling_list_pred_mode_flag[kMaxNumSizeIds][kMaxNumMatrixIds];
- int scaling_list_pred_matrix_id_delta[kMaxNumSizeIds][kMaxNumMatrixIds];
int32_t scaling_list_dc_coef_minus8[kMaxNumSizeIds][kMaxNumMatrixIds];
- int32_t scaling_list[kMaxNumSizeIds][kMaxNumMatrixIds][kMaxNumCoefs];
for (int size_id = 0; size_id < kMaxNumSizeIds; size_id++) {
for (int matrix_id = 0; matrix_id < kMaxNumMatrixIds;
matrix_id += (size_id == 3) ? 3 : 1) {
// scaling_list_pred_mode_flag: u(1)
- scaling_list_pred_mode_flag[size_id][matrix_id] = reader.Read<bool>();
- if (!scaling_list_pred_mode_flag[size_id][matrix_id]) {
+ bool scaling_list_pred_mode_flag = reader.Read<bool>();
+ if (!scaling_list_pred_mode_flag) {
// scaling_list_pred_matrix_id_delta: ue(v)
- scaling_list_pred_matrix_id_delta[size_id][matrix_id] =
- reader.ReadExponentialGolomb();
+ int scaling_list_pred_matrix_id_delta = reader.ReadExponentialGolomb();
if (size_id <= 2) {
- IN_RANGE_OR_RETURN_FALSE(
- scaling_list_pred_matrix_id_delta[size_id][matrix_id], 0,
- matrix_id);
+ IN_RANGE_OR_RETURN_FALSE(scaling_list_pred_matrix_id_delta, 0,
+ matrix_id);
} else { // size_id == 3
- IN_RANGE_OR_RETURN_FALSE(
- scaling_list_pred_matrix_id_delta[size_id][matrix_id], 0,
- matrix_id / 3);
+ IN_RANGE_OR_RETURN_FALSE(scaling_list_pred_matrix_id_delta, 0,
+ matrix_id / 3);
}
} else {
- int32_t next_coef = 8;
uint32_t coef_num = std::min(kMaxNumCoefs, 1 << (4 + (size_id << 1)));
if (size_id > 1) {
// scaling_list_dc_coef_minus8: se(v)
@@ -144,15 +135,12 @@
reader.ReadSignedExponentialGolomb();
IN_RANGE_OR_RETURN_FALSE(
scaling_list_dc_coef_minus8[size_id - 2][matrix_id], -7, 247);
- next_coef = scaling_list_dc_coef_minus8[size_id - 2][matrix_id] + 8;
}
for (uint32_t i = 0; i < coef_num; i++) {
// scaling_list_delta_coef: se(v)
int32_t scaling_list_delta_coef =
reader.ReadSignedExponentialGolomb();
IN_RANGE_OR_RETURN_FALSE(scaling_list_delta_coef, -128, 127);
- next_coef = (next_coef + scaling_list_delta_coef + 256) % 256;
- scaling_list[size_id][matrix_id][i] = next_coef;
}
}
}
@@ -192,7 +180,7 @@
uint32_t ref_rps_idx = st_rps_idx - (delta_idx_minus1 + 1);
uint32_t num_delta_pocs =
short_term_ref_pic_set[ref_rps_idx].num_delta_pocs;
- RTC_CHECK_LT(num_delta_pocs, kMaxShortTermRefPicSets);
+ IN_RANGE_OR_RETURN_NULL(num_delta_pocs, 0, kMaxShortTermRefPicSets);
const ShortTermRefPicSet& ref_set = short_term_ref_pic_set[ref_rps_idx];
bool used_by_curr_pic_flag[kMaxShortTermRefPicSets];
bool use_delta_flag[kMaxShortTermRefPicSets];
@@ -212,8 +200,9 @@
// and num_positive_pics.
// Equation 7-61
int i = 0;
- RTC_CHECK_LE(ref_set.num_negative_pics + ref_set.num_positive_pics,
- kMaxShortTermRefPicSets);
+ IN_RANGE_OR_RETURN_NULL(
+ ref_set.num_negative_pics + ref_set.num_positive_pics, 0,
+ kMaxShortTermRefPicSets);
for (int j = ref_set.num_positive_pics - 1; j >= 0; --j) {
int d_poc = ref_set.delta_poc_s1[j] + delta_rps;
if (d_poc < 0 && use_delta_flag[ref_set.num_negative_pics + j]) {
@@ -258,6 +247,11 @@
}
}
st_ref_pic_set.num_positive_pics = i;
+ IN_RANGE_OR_RETURN_NULL(st_ref_pic_set.num_negative_pics, 0,
+ sps_max_dec_pic_buffering_minus1);
+ IN_RANGE_OR_RETURN_NULL(
+ st_ref_pic_set.num_positive_pics, 0,
+ sps_max_dec_pic_buffering_minus1 - st_ref_pic_set.num_negative_pics);
} else {
// num_negative_pics: ue(v)
@@ -643,14 +637,12 @@
sps.num_long_term_ref_pics_sps = reader.ReadExponentialGolomb();
IN_RANGE_OR_RETURN_NULL(sps.num_long_term_ref_pics_sps, 0,
kMaxLongTermRefPicSets);
- sps.lt_ref_pic_poc_lsb_sps.resize(sps.num_long_term_ref_pics_sps, 0);
sps.used_by_curr_pic_lt_sps_flag.resize(sps.num_long_term_ref_pics_sps, 0);
for (uint32_t i = 0; i < sps.num_long_term_ref_pics_sps; i++) {
// lt_ref_pic_poc_lsb_sps: u(v)
uint32_t lt_ref_pic_poc_lsb_sps_bits =
sps.log2_max_pic_order_cnt_lsb_minus4 + 4;
- sps.lt_ref_pic_poc_lsb_sps[i] =
- reader.ReadBits(lt_ref_pic_poc_lsb_sps_bits);
+ reader.ConsumeBits(lt_ref_pic_poc_lsb_sps_bits);
// used_by_curr_pic_lt_sps_flag: u(1)
sps.used_by_curr_pic_lt_sps_flag[i] = reader.Read<bool>();
}
diff --git a/common_video/h265/h265_sps_parser.h b/common_video/h265/h265_sps_parser.h
index c3ac04c..2dece2b 100644
--- a/common_video/h265/h265_sps_parser.h
+++ b/common_video/h265/h265_sps_parser.h
@@ -75,15 +75,15 @@
// The parsed state of the SPS. Only some select values are stored.
// Add more as they are actually needed.
struct SpsState {
- SpsState();
+ SpsState() = default;
- uint32_t sps_max_sub_layers_minus1;
+ uint32_t sps_max_sub_layers_minus1 = 0;
uint32_t chroma_format_idc = 0;
uint32_t separate_colour_plane_flag = 0;
uint32_t pic_width_in_luma_samples = 0;
uint32_t pic_height_in_luma_samples = 0;
uint32_t log2_max_pic_order_cnt_lsb_minus4 = 0;
- uint32_t sps_max_dec_pic_buffering_minus1[kMaxSubLayers];
+ uint32_t sps_max_dec_pic_buffering_minus1[kMaxSubLayers] = {};
uint32_t log2_min_luma_coding_block_size_minus3 = 0;
uint32_t log2_diff_max_min_luma_coding_block_size = 0;
uint32_t sample_adaptive_offset_enabled_flag = 0;
@@ -91,7 +91,6 @@
std::vector<H265SpsParser::ShortTermRefPicSet> short_term_ref_pic_set;
uint32_t long_term_ref_pics_present_flag = 0;
uint32_t num_long_term_ref_pics_sps = 0;
- std::vector<uint32_t> lt_ref_pic_poc_lsb_sps;
std::vector<uint32_t> used_by_curr_pic_lt_sps_flag;
uint32_t sps_temporal_mvp_enabled_flag = 0;
uint32_t width = 0;
@@ -100,7 +99,6 @@
uint32_t vps_id = 0;
uint32_t pic_width_in_ctbs_y = 0;
uint32_t pic_height_in_ctbs_y = 0;
- uint32_t ctb_log2_size_y = 0;
uint32_t bit_depth_luma_minus8 = 0;
};