Bug 1204099: RTP payload type validation.
MozReview-Commit-ID: LYNcxKqKwiC
--- a/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp
+++ b/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp
@@ -2,16 +2,17 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "logging.h"
#include "signaling/src/jsep/JsepSessionImpl.h"
#include <string>
#include <set>
+#include <bitset>
#include <stdlib.h>
#include "nspr.h"
#include "nss.h"
#include "pk11pub.h"
#include "nsDebug.h"
#include <mozilla/Move.h>
@@ -32,16 +33,27 @@ MOZ_MTLOG_MODULE("jsep")
#define JSEP_SET_ERROR(error) \
do { \
std::ostringstream os; \
os << error; \
mLastError = os.str(); \
MOZ_MTLOG(ML_ERROR, mLastError); \
} while (0);
+static std::bitset<128> GetForbiddenSdpPayloadTypes() {
+ std::bitset<128> forbidden(0);
+ forbidden[1] = true;
+ forbidden[2] = true;
+ forbidden[19] = true;
+ for (uint16_t i = 64; i < 96; ++i) {
+ forbidden[i] = true;
+ }
+ return forbidden;
+}
+
nsresult
JsepSessionImpl::Init()
{
mLastError.clear();
MOZ_ASSERT(!mSessionId, "Init called more than once");
nsresult rv = SetupIds();
@@ -1653,26 +1665,31 @@ JsepSessionImpl::ParseSdp(const std::str
}
trackIds.insert(trackId);
} else if (rv != NS_ERROR_NOT_AVAILABLE) {
// Error has already been set
return rv;
}
+ static const std::bitset<128> forbidden = GetForbiddenSdpPayloadTypes();
if (msection.GetMediaType() == SdpMediaSection::kAudio ||
msection.GetMediaType() == SdpMediaSection::kVideo) {
// Sanity-check that payload type can work with RTP
for (const std::string& fmt : msection.GetFormats()) {
uint16_t payloadType;
// TODO (bug 1204099): Make this check for reserved ranges.
if (!SdpHelper::GetPtAsInt(fmt, &payloadType) || payloadType > 127) {
JSEP_SET_ERROR("audio/video payload type is too large: " << fmt);
return NS_ERROR_INVALID_ARG;
}
+ if (forbidden.test(payloadType)) {
+ JSEP_SET_ERROR("Illegal audio/video payload type: " << fmt);
+ return NS_ERROR_INVALID_ARG;
+ }
}
}
}
*parsedp = Move(parsed);
return NS_OK;
}
--- a/media/webrtc/signaling/test/jsep_session_unittest.cpp
+++ b/media/webrtc/signaling/test/jsep_session_unittest.cpp
@@ -2115,16 +2115,31 @@ TEST_P(JsepSessionTest, RenegotiationAns
}
ASSERT_NE(newOffererPairs[0].mRtpTransport.get(),
offererPairs[0].mRtpTransport.get());
ASSERT_NE(newAnswererPairs[0].mRtpTransport.get(),
answererPairs[0].mRtpTransport.get());
}
+TEST_P(JsepSessionTest, ParseRejectsBadMediaFormat)
+{
+ if (GetParam() == "datachannel") {
+ return;
+ }
+ AddTracks(mSessionOff);
+ std::string offer = CreateOffer();
+ UniquePtr<Sdp> munge(Parse(offer));
+ SdpMediaSection& mediaSection = munge->GetMediaSection(0);
+ mediaSection.AddCodec("75", "DummyFormatVal", 8000, 1);
+ std::string sdpString = munge->ToString();
+ nsresult rv = mSessionOff.SetLocalDescription(kJsepSdpOffer, sdpString);
+ ASSERT_EQ(NS_ERROR_INVALID_ARG, rv);
+}
+
TEST_P(JsepSessionTest, FullCallWithCandidates)
{
AddTracks(mSessionOff);
std::string offer = CreateOffer();
SetLocalOffer(offer);
mOffCandidates.Gather(mSessionOff, types);
UniquePtr<Sdp> localOffer(Parse(mSessionOff.GetLocalDescription()));