Skip to content

Commit 6499c03

Browse files
David Kilzerphiln
authored andcommitted
Harden WebRTC HEVC RFC 7798 RTP Payload Format Implementation
https://bugs.webkit.org/show_bug.cgi?id=264021 <rdar://117778946> Reviewed by Youenn Fablet. * Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h265/h265_sps_parser.cc: (webrtc::kMaxSPSLongTermRefPics): (webrtc::kMaxSPSPics): (webrtc::kMaxSPSShortTermRefPics): - Add constants representing limits for various fields. (webrtc::H265SpsParser::ParseScalingListData): - Return false if BitstreamReader was invalidated. (webrtc::H265SpsParser::ParseShortTermRefPicSet): - Return absl::nullopt if BitstreamReader was invalidated, or if reader.ReadExponentialGolomb() returned unrealistic values. (webrtc::H265SpsParser::ParseSpsInternal): - Return absl::nullopt if BitstreamReader was invalidated, or if reader.ReadExponentialGolomb() returned unrealistic values. - Move early return up since reader is not used after that point. * Source/ThirdParty/libwebrtc/Source/webrtc/rtc_base/bitstream_reader.cc: (webrtc::BitstreamReader::ReadBits): - Add runtime check for (bits < 0). Use Invalidate() instead of subtracting bits from remaining_bits_ to prevent integer underflow. (webrtc::BitstreamReader::ReadExponentialGolomb): - Add check for (remaining_bits_ < 0) so that zero_bit_count doesn't have to reach 32 before invalidation occurs. * Source/ThirdParty/libwebrtc/WebKit/0001-Harden-WebRTC-HEVC-RFC-7798-RTP-Payload-Format-Imple.patch: Add. Canonical link: https://commits.webkit.org/270179@main
1 parent 43cbc67 commit 6499c03

3 files changed

Lines changed: 204 additions & 0 deletions

File tree

Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h265/h265_sps_parser.cc

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ typedef absl::optional<webrtc::H265SpsParser::ShortTermRefPicSet>
2525

2626
namespace webrtc {
2727

28+
#if WEBRTC_WEBKIT_BUILD
29+
const uint32_t kMaxSPSLongTermRefPics = 32;
30+
const uint32_t kMaxSPSPics = 16;
31+
const uint32_t kMaxSPSShortTermRefPics = 64;
32+
#endif
33+
2834
H265SpsParser::SpsState::SpsState() = default;
2935

3036
H265SpsParser::ShortTermRefPicSet::ShortTermRefPicSet() = default;
@@ -73,6 +79,13 @@ bool H265SpsParser::ParseScalingListData(BitstreamReader& reader) {
7379
}
7480
}
7581
}
82+
83+
#if WEBRTC_WEBKIT_BUILD
84+
if (!reader.Ok()) {
85+
return false;
86+
}
87+
#endif
88+
7689
return true;
7790
}
7891

@@ -134,6 +147,12 @@ H265SpsParser::ParseShortTermRefPicSet(
134147
ref_pic_set.num_negative_pics = reader.ReadExponentialGolomb();
135148
// num_positive_pics: ue(v)
136149
ref_pic_set.num_positive_pics = reader.ReadExponentialGolomb();
150+
#if WEBRTC_WEBKIT_BUILD
151+
if (!reader.Ok() || ref_pic_set.num_negative_pics > kMaxSPSPics || ref_pic_set.num_positive_pics > kMaxSPSPics
152+
|| (ref_pic_set.num_negative_pics + ref_pic_set.num_positive_pics) > kMaxSPSPics) {
153+
return absl::nullopt;
154+
}
155+
#endif
137156

138157
ref_pic_set.delta_poc_s0_minus1.resize(ref_pic_set.num_negative_pics, 0);
139158
ref_pic_set.used_by_curr_pic_s0_flag.resize(ref_pic_set.num_negative_pics,
@@ -155,6 +174,12 @@ H265SpsParser::ParseShortTermRefPicSet(
155174
}
156175
}
157176

177+
#if WEBRTC_WEBKIT_BUILD
178+
if (!reader.Ok()) {
179+
return absl::nullopt;
180+
}
181+
#endif
182+
158183
return OptionalShortTermRefPicSet(ref_pic_set);
159184
}
160185

@@ -335,6 +360,11 @@ absl::optional<H265SpsParser::SpsState> H265SpsParser::ParseSpsInternal(
335360

336361
// num_short_term_ref_pic_sets: ue(v)
337362
sps.num_short_term_ref_pic_sets = reader.ReadExponentialGolomb();
363+
#if WEBRTC_WEBKIT_BUILD
364+
if (!reader.Ok() || sps.num_short_term_ref_pic_sets > kMaxSPSShortTermRefPics) {
365+
return absl::nullopt;
366+
}
367+
#endif
338368
sps.short_term_ref_pic_set.resize(sps.num_short_term_ref_pic_sets);
339369
for (uint32_t st_rps_idx = 0; st_rps_idx < sps.num_short_term_ref_pic_sets;
340370
st_rps_idx++) {
@@ -354,6 +384,11 @@ absl::optional<H265SpsParser::SpsState> H265SpsParser::ParseSpsInternal(
354384
if (sps.long_term_ref_pics_present_flag) {
355385
// num_long_term_ref_pics_sps: ue(v)
356386
sps.num_long_term_ref_pics_sps = reader.ReadExponentialGolomb();
387+
#if WEBRTC_WEBKIT_BUILD
388+
if (!reader.Ok() || sps.num_long_term_ref_pics_sps > kMaxSPSLongTermRefPics) {
389+
return absl::nullopt;
390+
}
391+
#endif
357392
sps.used_by_curr_pic_lt_sps_flag.resize(sps.num_long_term_ref_pics_sps, 0);
358393
for (uint32_t i = 0; i < sps.num_long_term_ref_pics_sps; i++) {
359394
// lt_ref_pic_poc_lsb_sps: u(v)
@@ -369,6 +404,11 @@ absl::optional<H265SpsParser::SpsState> H265SpsParser::ParseSpsInternal(
369404
sps.sps_temporal_mvp_enabled_flag = reader.Read<bool>();
370405

371406
// Far enough! We don't use the rest of the SPS.
407+
#if WEBRTC_WEBKIT_BUILD
408+
if (!reader.Ok()) {
409+
return absl::nullopt;
410+
}
411+
#endif
372412

373413
sps.vps_id = sps_video_parameter_set_id;
374414

@@ -395,9 +435,11 @@ absl::optional<H265SpsParser::SpsState> H265SpsParser::ParseSpsInternal(
395435
sps.height -= sub_height_c * (conf_win_top_offset + conf_win_bottom_offset);
396436
}
397437

438+
#ifndef WEBRTC_WEBKIT_BUILD
398439
if (!reader.Ok()) {
399440
return absl::nullopt;
400441
}
442+
#endif
401443

402444
return OptionalSps(sps);
403445
}

Source/ThirdParty/libwebrtc/Source/webrtc/rtc_base/bitstream_reader.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,17 @@ uint64_t BitstreamReader::ReadBits(int bits) {
2525
RTC_DCHECK_LE(bits, 64);
2626
set_last_read_is_verified(false);
2727

28+
#if WEBRTC_WEBKIT_BUILD
29+
if (remaining_bits_ < bits || bits < 0) {
30+
Invalidate();
31+
return 0;
32+
}
33+
#else
2834
if (remaining_bits_ < bits) {
2935
remaining_bits_ -= bits;
3036
return 0;
3137
}
38+
#endif
3239

3340
int remaining_bits_in_first_byte = remaining_bits_ % 8;
3441
remaining_bits_ -= bits;
@@ -110,11 +117,19 @@ uint32_t BitstreamReader::ReadExponentialGolomb() {
110117
// Count the number of leading 0.
111118
int zero_bit_count = 0;
112119
while (ReadBit() == 0) {
120+
#if WEBRTC_WEBKIT_BUILD
121+
if (++zero_bit_count >= 32 || remaining_bits_ < 0) {
122+
// Golob value won't fit into 32 bits of the return value, or we ran out of bits. Fail the parse.
123+
Invalidate();
124+
return 0;
125+
}
126+
#else
113127
if (++zero_bit_count >= 32) {
114128
// Golob value won't fit into 32 bits of the return value. Fail the parse.
115129
Invalidate();
116130
return 0;
117131
}
132+
#endif
118133
}
119134

120135
// The bit count of the value is the number of zeros + 1.
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h265/h265_sps_parser.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h265/h265_sps_parser.cc
2+
index e53e2c405b32..521aea7e24f0 100644
3+
--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h265/h265_sps_parser.cc
4+
+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h265/h265_sps_parser.cc
5+
@@ -25,6 +25,12 @@ typedef absl::optional<webrtc::H265SpsParser::ShortTermRefPicSet>
6+
7+
namespace webrtc {
8+
9+
+#if WEBRTC_WEBKIT_BUILD
10+
+const uint32_t kMaxSPSLongTermRefPics = 32;
11+
+const uint32_t kMaxSPSPics = 16;
12+
+const uint32_t kMaxSPSShortTermRefPics = 64;
13+
+#endif
14+
+
15+
H265SpsParser::SpsState::SpsState() = default;
16+
17+
H265SpsParser::ShortTermRefPicSet::ShortTermRefPicSet() = default;
18+
@@ -73,6 +79,13 @@ bool H265SpsParser::ParseScalingListData(BitstreamReader& reader) {
19+
}
20+
}
21+
}
22+
+
23+
+#if WEBRTC_WEBKIT_BUILD
24+
+ if (!reader.Ok()) {
25+
+ return false;
26+
+ }
27+
+#endif
28+
+
29+
return true;
30+
}
31+
32+
@@ -134,6 +147,12 @@ H265SpsParser::ParseShortTermRefPicSet(
33+
ref_pic_set.num_negative_pics = reader.ReadExponentialGolomb();
34+
// num_positive_pics: ue(v)
35+
ref_pic_set.num_positive_pics = reader.ReadExponentialGolomb();
36+
+#if WEBRTC_WEBKIT_BUILD
37+
+ if (!reader.Ok() || ref_pic_set.num_negative_pics > kMaxSPSPics || ref_pic_set.num_positive_pics > kMaxSPSPics
38+
+ || (ref_pic_set.num_negative_pics + ref_pic_set.num_positive_pics) > kMaxSPSPics) {
39+
+ return absl::nullopt;
40+
+ }
41+
+#endif
42+
43+
ref_pic_set.delta_poc_s0_minus1.resize(ref_pic_set.num_negative_pics, 0);
44+
ref_pic_set.used_by_curr_pic_s0_flag.resize(ref_pic_set.num_negative_pics,
45+
@@ -155,6 +174,12 @@ H265SpsParser::ParseShortTermRefPicSet(
46+
}
47+
}
48+
49+
+#if WEBRTC_WEBKIT_BUILD
50+
+ if (!reader.Ok()) {
51+
+ return absl::nullopt;
52+
+ }
53+
+#endif
54+
+
55+
return OptionalShortTermRefPicSet(ref_pic_set);
56+
}
57+
58+
@@ -348,6 +373,11 @@ absl::optional<H265SpsParser::SpsState> H265SpsParser::ParseSpsInternal(
59+
60+
// num_short_term_ref_pic_sets: ue(v)
61+
sps.num_short_term_ref_pic_sets = reader.ReadExponentialGolomb();
62+
+#if WEBRTC_WEBKIT_BUILD
63+
+ if (!reader.Ok() || sps.num_short_term_ref_pic_sets > kMaxSPSShortTermRefPics) {
64+
+ return absl::nullopt;
65+
+ }
66+
+#endif
67+
sps.short_term_ref_pic_set.resize(sps.num_short_term_ref_pic_sets);
68+
for (uint32_t st_rps_idx = 0; st_rps_idx < sps.num_short_term_ref_pic_sets;
69+
st_rps_idx++) {
70+
@@ -367,6 +397,11 @@ absl::optional<H265SpsParser::SpsState> H265SpsParser::ParseSpsInternal(
71+
if (sps.long_term_ref_pics_present_flag) {
72+
// num_long_term_ref_pics_sps: ue(v)
73+
sps.num_long_term_ref_pics_sps = reader.ReadExponentialGolomb();
74+
+#if WEBRTC_WEBKIT_BUILD
75+
+ if (!reader.Ok() || sps.num_long_term_ref_pics_sps > kMaxSPSLongTermRefPics) {
76+
+ return absl::nullopt;
77+
+ }
78+
+#endif
79+
sps.used_by_curr_pic_lt_sps_flag.resize(sps.num_long_term_ref_pics_sps, 0);
80+
for (uint32_t i = 0; i < sps.num_long_term_ref_pics_sps; i++) {
81+
// lt_ref_pic_poc_lsb_sps: u(v)
82+
@@ -382,6 +417,11 @@ absl::optional<H265SpsParser::SpsState> H265SpsParser::ParseSpsInternal(
83+
sps.sps_temporal_mvp_enabled_flag = reader.Read<bool>();
84+
85+
// Far enough! We don't use the rest of the SPS.
86+
+#if WEBRTC_WEBKIT_BUILD
87+
+ if (!reader.Ok()) {
88+
+ return absl::nullopt;
89+
+ }
90+
+#endif
91+
92+
sps.vps_id = sps_video_parameter_set_id;
93+
94+
@@ -408,9 +448,11 @@ absl::optional<H265SpsParser::SpsState> H265SpsParser::ParseSpsInternal(
95+
sps.height -= sub_height_c * (conf_win_top_offset + conf_win_bottom_offset);
96+
}
97+
98+
+#ifndef WEBRTC_WEBKIT_BUILD
99+
if (!reader.Ok()) {
100+
return absl::nullopt;
101+
}
102+
+#endif
103+
104+
return OptionalSps(sps);
105+
}
106+
diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/rtc_base/bitstream_reader.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/rtc_base/bitstream_reader.cc
107+
index 2442d1664eed..bd2b2fb8e932 100644
108+
--- a/Source/ThirdParty/libwebrtc/Source/webrtc/rtc_base/bitstream_reader.cc
109+
+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/rtc_base/bitstream_reader.cc
110+
@@ -25,10 +25,17 @@ uint64_t BitstreamReader::ReadBits(int bits) {
111+
RTC_DCHECK_LE(bits, 64);
112+
set_last_read_is_verified(false);
113+
114+
+#if WEBRTC_WEBKIT_BUILD
115+
+ if (remaining_bits_ < bits || bits < 0) {
116+
+ Invalidate();
117+
+ return 0;
118+
+ }
119+
+#else
120+
if (remaining_bits_ < bits) {
121+
remaining_bits_ -= bits;
122+
return 0;
123+
}
124+
+#endif
125+
126+
int remaining_bits_in_first_byte = remaining_bits_ % 8;
127+
remaining_bits_ -= bits;
128+
@@ -115,11 +122,19 @@ uint32_t BitstreamReader::ReadExponentialGolomb() {
129+
// Count the number of leading 0.
130+
int zero_bit_count = 0;
131+
while (ReadBit() == 0) {
132+
+#if WEBRTC_WEBKIT_BUILD
133+
+ if (++zero_bit_count >= 32 || remaining_bits_ < 0) {
134+
+ // Golob value won't fit into 32 bits of the return value, or we ran out of bits. Fail the parse.
135+
+ Invalidate();
136+
+ return 0;
137+
+ }
138+
+#else
139+
if (++zero_bit_count >= 32) {
140+
// Golob value won't fit into 32 bits of the return value. Fail the parse.
141+
Invalidate();
142+
return 0;
143+
}
144+
+#endif
145+
}
146+
147+
// The bit count of the value is the number of zeros + 1.

0 commit comments

Comments
 (0)