Prevent JS from bypassing RTP data channel bandwidth limitation.

Normally the RTP data channel is capped at 30kbps, but by mangling the
SDP string, one could get around this limitation. With this fix,
SdpDeserialize will return an error if it detects this condition.

BUG=280726
R=pthatcher@webrtc.org

Review URL: https://codereview.webrtc.org/1196403004.

Cr-Commit-Position: refs/heads/master@{#9499}
This commit is contained in:
Peter Thatcher 2015-06-24 15:31:25 -07:00
parent 8d3e489d01
commit c0c3a865f4
2 changed files with 39 additions and 42 deletions

View File

@ -1274,16 +1274,7 @@ void BuildMediaDescription(const ContentInfo* content_info,
// RFC 4566 // RFC 4566
// b=AS:<bandwidth> // b=AS:<bandwidth>
// We should always use the default bandwidth for RTP-based data if (media_desc->bandwidth() >= 1000) {
// channels. Don't allow SDP to set the bandwidth, because that
// would give JS the opportunity to "break the Internet".
// TODO(pthatcher): But we need to temporarily allow the SDP to control
// this for backwards-compatibility. Once we don't need that any
// more, remove this.
bool support_dc_sdp_bandwidth_temporarily = true;
if (media_desc->bandwidth() >= 1000 &&
(media_type != cricket::MEDIA_TYPE_DATA ||
support_dc_sdp_bandwidth_temporarily)) {
InitLine(kLineTypeSessionBandwidth, kApplicationSpecificMaximum, &os); InitLine(kLineTypeSessionBandwidth, kApplicationSpecificMaximum, &os);
os << kSdpDelimiterColon << (media_desc->bandwidth() / 1000); os << kSdpDelimiterColon << (media_desc->bandwidth() / 1000);
AddLine(os.str(), message); AddLine(os.str(), message);
@ -2249,17 +2240,6 @@ bool ParseMediaDescription(const std::string& message,
if (!AddSctpDataCodec(data_desc, p)) if (!AddSctpDataCodec(data_desc, p))
return false; return false;
} }
// We should always use the default bandwidth for RTP-based data
// channels. Don't allow SDP to set the bandwidth, because that
// would give JS the opportunity to "break the Internet".
// TODO(pthatcher): But we need to temporarily allow the SDP to control
// this for backwards-compatibility. Once we don't need that any
// more, remove this.
bool support_dc_sdp_bandwidth_temporarily = true;
if (content.get() && !support_dc_sdp_bandwidth_temporarily) {
content->set_bandwidth(cricket::kAutoBandwidth);
}
} else { } else {
LOG(LS_WARNING) << "Unsupported media type: " << line; LOG(LS_WARNING) << "Unsupported media type: " << line;
continue; continue;
@ -2517,6 +2497,17 @@ bool ParseContent(const std::string& message,
if (!GetValueFromString(line, bandwidth, &b, error)) { if (!GetValueFromString(line, bandwidth, &b, error)) {
return false; return false;
} }
// We should never use more than the default bandwidth for RTP-based
// data channels. Don't allow SDP to set the bandwidth, because
// that would give JS the opportunity to "break the Internet".
// See: https://code.google.com/p/chromium/issues/detail?id=280726
if (media_type == cricket::MEDIA_TYPE_DATA && IsRtp(protocol) &&
b > cricket::kDataMaxBandwidth / 1000) {
std::ostringstream description;
description << "RTP-based data channels may not send more than "
<< cricket::kDataMaxBandwidth / 1000 << "kbps.";
return ParseFailed(line, description.str(), error);
}
media_desc->set_bandwidth(b * 1000); media_desc->set_bandwidth(b * 1000);
} }
} }

View File

@ -1698,12 +1698,7 @@ TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithDataChannelAndBandwidth) {
std::string expected_sdp = kSdpString; std::string expected_sdp = kSdpString;
expected_sdp.append(kSdpRtpDataChannelString); expected_sdp.append(kSdpRtpDataChannelString);
// We want to test that serializing data content ignores bandwidth // Serializing data content shouldn't ignore bandwidth settings.
// settings (it should always be the default). Thus, we don't do
// the following:
// TODO(pthatcher): We need to temporarily allow the SDP to control
// this for backwards-compatibility. Once we don't need that any
// more, remove this.
InjectAfter("m=application 9 RTP/SAVPF 101\r\nc=IN IP4 0.0.0.0\r\n", InjectAfter("m=application 9 RTP/SAVPF 101\r\nc=IN IP4 0.0.0.0\r\n",
"b=AS:100\r\n", "b=AS:100\r\n",
&expected_sdp); &expected_sdp);
@ -2259,19 +2254,11 @@ TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelAndNewPort) {
} }
TEST_F(WebRtcSdpTest, DeserializeSdpWithRtpDataChannelsAndBandwidth) { TEST_F(WebRtcSdpTest, DeserializeSdpWithRtpDataChannelsAndBandwidth) {
AddRtpDataChannel(); // We want to test that deserializing data content limits bandwidth
JsepSessionDescription jdesc(kDummyString); // settings (it should never be greater than the default).
// We want to test that deserializing data content ignores bandwidth // This should prevent someone from using unlimited data bandwidth through
// settings (it should always be the default). Thus, we don't do // JS and "breaking the Internet".
// the following: // See: https://code.google.com/p/chromium/issues/detail?id=280726
// TODO(pthatcher): We need to temporarily allow the SDP to control
// this for backwards-compatibility. Once we don't need that any
// more, remove this.
DataContentDescription* dcd = static_cast<DataContentDescription*>(
GetFirstDataContent(&desc_)->description);
dcd->set_bandwidth(100 * 1000);
ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
std::string sdp_with_bandwidth = kSdpString; std::string sdp_with_bandwidth = kSdpString;
sdp_with_bandwidth.append(kSdpRtpDataChannelString); sdp_with_bandwidth.append(kSdpRtpDataChannelString);
InjectAfter("a=mid:data_content_name\r\n", InjectAfter("a=mid:data_content_name\r\n",
@ -2279,8 +2266,27 @@ TEST_F(WebRtcSdpTest, DeserializeSdpWithRtpDataChannelsAndBandwidth) {
&sdp_with_bandwidth); &sdp_with_bandwidth);
JsepSessionDescription jdesc_with_bandwidth(kDummyString); JsepSessionDescription jdesc_with_bandwidth(kDummyString);
EXPECT_TRUE( EXPECT_FALSE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth)); }
TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsAndBandwidth) {
AddSctpDataChannel();
JsepSessionDescription jdesc(kDummyString);
DataContentDescription* dcd = static_cast<DataContentDescription*>(
GetFirstDataContent(&desc_)->description);
dcd->set_bandwidth(100 * 1000);
ASSERT_TRUE(jdesc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
std::string sdp_with_bandwidth = kSdpString;
sdp_with_bandwidth.append(kSdpSctpDataChannelString);
InjectAfter("a=mid:data_content_name\r\n",
"b=AS:100\r\n",
&sdp_with_bandwidth);
JsepSessionDescription jdesc_with_bandwidth(kDummyString);
// SCTP has congestion control, so we shouldn't limit the bandwidth
// as we do for RTP.
EXPECT_TRUE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_with_bandwidth)); EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_with_bandwidth));
} }