sdp: reject RTP payload types in the 64-95 range w/rtcp-mux
which is forbidden by
https://tools.ietf.org/html/rfc5761#section-4
BUG=webrtc:12197
Change-Id: I6227f01e7dcbca3f5871a2e4a8cea3c4db0b16cf
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/319120
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Philipp Hancke <phancke@microsoft.com>
Cr-Commit-Position: refs/heads/main@{#40752}
diff --git a/pc/sdp_offer_answer.cc b/pc/sdp_offer_answer.cc
index 06303de..25383e8 100644
--- a/pc/sdp_offer_answer.cc
+++ b/pc/sdp_offer_answer.cc
@@ -120,6 +120,12 @@
static const char kDefaultAudioSenderId[] = "defaulta0";
static const char kDefaultVideoSenderId[] = "defaultv0";
+// NOTE: Duplicated from pc/used_ids.h
+static const int kLastDynamicPayloadTypeLowerRange = 63;
+
+static const int kFirstDynamicPayloadTypeUpperRange = 96;
+static const int kLastDynamicPayloadTypeUpperRange = 127;
+
void NoteAddIceCandidateResult(int result) {
RTC_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.AddIceCandidate", result,
kAddIceCandidateMax);
@@ -562,6 +568,53 @@
return RTCError::OK();
}
+RTCError ValidatePayloadTypes(const cricket::SessionDescription& description) {
+ for (const ContentInfo& content : description.contents()) {
+ if (content.type != MediaProtocolType::kRtp) {
+ continue;
+ }
+ const auto media_description = content.media_description();
+ RTC_DCHECK(media_description);
+ if (content.rejected || !media_description ||
+ !media_description->has_codecs()) {
+ continue;
+ }
+ const auto type = media_description->type();
+ if (type == cricket::MEDIA_TYPE_AUDIO) {
+ RTC_DCHECK(media_description->as_audio());
+ for (const auto& codec : media_description->as_audio()->codecs()) {
+ if (codec.id < 0 || codec.id > kLastDynamicPayloadTypeUpperRange ||
+ (media_description->rtcp_mux() &&
+ (codec.id > kLastDynamicPayloadTypeLowerRange &&
+ codec.id < kFirstDynamicPayloadTypeUpperRange))) {
+ LOG_AND_RETURN_ERROR(
+ RTCErrorType::INVALID_PARAMETER,
+ "The media section with MID='" + content.mid() +
+ "' used an invalid payload type " + rtc::ToString(codec.id) +
+ " for codec '" + codec.name + ", rtcp-mux:" +
+ (media_description->rtcp_mux() ? "enabled" : "disabled"));
+ }
+ }
+ } else if (type == cricket::MEDIA_TYPE_VIDEO) {
+ RTC_DCHECK(media_description->as_video());
+ for (const auto& codec : media_description->as_video()->codecs()) {
+ if (codec.id < 0 || codec.id > kLastDynamicPayloadTypeUpperRange ||
+ (media_description->rtcp_mux() &&
+ (codec.id > kLastDynamicPayloadTypeLowerRange &&
+ codec.id < kFirstDynamicPayloadTypeUpperRange))) {
+ LOG_AND_RETURN_ERROR(
+ RTCErrorType::INVALID_PARAMETER,
+ "The media section with MID='" + content.mid() +
+ "' used an invalid payload type " + rtc::ToString(codec.id) +
+ " for codec '" + codec.name + ", rtcp-mux:" +
+ (media_description->rtcp_mux() ? "enabled" : "disabled"));
+ }
+ }
+ }
+ }
+ return RTCError::OK();
+}
+
bool IsValidOfferToReceiveMedia(int value) {
typedef PeerConnectionInterface::RTCOfferAnswerOptions Options;
return (value >= Options::kUndefined) &&
@@ -3587,6 +3640,11 @@
kBundleWithoutRtcpMux);
}
+ error = ValidatePayloadTypes(*sdesc->description());
+ if (!error.ok()) {
+ return error;
+ }
+
// TODO(skvlad): When the local rtcp-mux policy is Require, reject any
// m-lines that do not rtcp-mux enabled.
diff --git a/pc/sdp_offer_answer_unittest.cc b/pc/sdp_offer_answer_unittest.cc
index 14e9557..bbf7e2b 100644
--- a/pc/sdp_offer_answer_unittest.cc
+++ b/pc/sdp_offer_answer_unittest.cc
@@ -993,4 +993,26 @@
EXPECT_EQ(error.type(), RTCErrorType::INVALID_PARAMETER);
}
+TEST_F(SdpOfferAnswerTest, SdpMungingWithInvalidPayloadTypeIsRejected) {
+ auto pc = CreatePeerConnection();
+ pc->AddAudioTrack("audio_track", {});
+
+ auto offer = pc->CreateOffer();
+ ASSERT_EQ(offer->description()->contents().size(), 1u);
+ auto* audio =
+ offer->description()->contents()[0].media_description()->as_audio();
+ ASSERT_GT(audio->codecs().size(), 0u);
+ EXPECT_TRUE(audio->rtcp_mux());
+ auto codecs = audio->codecs();
+ for (int invalid_payload_type = 64; invalid_payload_type < 96;
+ invalid_payload_type++) {
+ codecs[0].id =
+ invalid_payload_type; // The range [64-95] is disallowed with rtcp_mux.
+ audio->set_codecs(codecs);
+ // ASSERT to avoid getting into a bad state.
+ ASSERT_FALSE(pc->SetLocalDescription(offer->Clone()));
+ ASSERT_FALSE(pc->SetRemoteDescription(offer->Clone()));
+ }
+}
+
} // namespace webrtc