Delete a cricket::DtlsTransport when PC is closed
This avoids use-after-free problems that occur when references
to webrtc::DtlsTransport objects are held outside of the PC.
Bug: chromium:907849
Change-Id: Id428c8e616482eff0f4327d2eac17e29bb3f6484
Reviewed-on: https://webrtc-review.googlesource.com/c/113303
Reviewed-by: Fredrik Solenberg <solenberg@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25915}
diff --git a/pc/dtlstransport.h b/pc/dtlstransport.h
index dacdba2..03901c3 100644
--- a/pc/dtlstransport.h
+++ b/pc/dtlstransport.h
@@ -27,6 +27,7 @@
cricket::DtlsTransportInternal* internal() {
return internal_dtls_transport_.get();
}
+ void clear() { internal_dtls_transport_.reset(); }
private:
std::unique_ptr<cricket::DtlsTransportInternal> internal_dtls_transport_;
diff --git a/pc/jseptransport.cc b/pc/jseptransport.cc
index c60c28d..28389d5 100644
--- a/pc/jseptransport.cc
+++ b/pc/jseptransport.cc
@@ -136,6 +136,12 @@
if (media_transport_) {
media_transport_->SetMediaTransportStateCallback(nullptr);
}
+ // Clear all DtlsTransports. There may be pointers to these from
+ // other places, so we can't assume they'll be deleted by the destructor.
+ rtp_dtls_transport_->clear();
+ if (rtcp_dtls_transport_) {
+ rtcp_dtls_transport_->clear();
+ }
}
webrtc::RTCError JsepTransport::SetLocalJsepTransportDescription(
@@ -192,9 +198,11 @@
}
}
+ RTC_DCHECK(rtp_dtls_transport_->internal());
SetLocalIceParameters(rtp_dtls_transport_->internal()->ice_transport());
if (rtcp_dtls_transport_) {
+ RTC_DCHECK(rtcp_dtls_transport_->internal());
SetLocalIceParameters(rtcp_dtls_transport_->internal()->ice_transport());
}
@@ -255,9 +263,11 @@
}
remote_description_.reset(new JsepTransportDescription(jsep_description));
+ RTC_DCHECK(rtp_dtls_transport_->internal());
SetRemoteIceParameters(rtp_dtls_transport_->internal()->ice_transport());
if (rtcp_dtls_transport_) {
+ RTC_DCHECK(rtcp_dtls_transport_->internal());
SetRemoteIceParameters(rtcp_dtls_transport_->internal()->ice_transport());
}
@@ -292,6 +302,7 @@
"Candidate has an unknown component: " +
candidate.ToString() + " for mid " + mid());
}
+ RTC_DCHECK(transport->internal() && transport->internal()->ice_transport());
transport->internal()->ice_transport()->AddRemoteCandidate(candidate);
}
return webrtc::RTCError::OK();
@@ -306,6 +317,7 @@
absl::optional<rtc::SSLRole> JsepTransport::GetDtlsRole() const {
RTC_DCHECK(rtp_dtls_transport_);
+ RTC_DCHECK(rtp_dtls_transport_->internal());
rtc::SSLRole dtls_role;
if (!rtp_dtls_transport_->internal()->GetDtlsRole(&dtls_role)) {
return absl::optional<rtc::SSLRole>();
@@ -317,8 +329,10 @@
bool JsepTransport::GetStats(TransportStats* stats) {
stats->transport_name = mid();
stats->channel_stats.clear();
+ RTC_DCHECK(rtp_dtls_transport_->internal());
bool ret = GetTransportStats(rtp_dtls_transport_->internal(), stats);
if (rtcp_dtls_transport_) {
+ RTC_DCHECK(rtcp_dtls_transport_->internal());
ret &= GetTransportStats(rtcp_dtls_transport_->internal(), stats);
}
return ret;
@@ -534,6 +548,7 @@
// between future SetRemote/SetLocal invocations and new transport
// creation, we have the negotiation state saved until a new
// negotiation happens.
+ RTC_DCHECK(rtp_dtls_transport_->internal());
webrtc::RTCError error = SetNegotiatedDtlsParameters(
rtp_dtls_transport_->internal(), negotiated_dtls_role,
remote_fingerprint.get());
@@ -542,6 +557,7 @@
}
if (rtcp_dtls_transport_) {
+ RTC_DCHECK(rtcp_dtls_transport_->internal());
error = SetNegotiatedDtlsParameters(rtcp_dtls_transport_->internal(),
negotiated_dtls_role,
remote_fingerprint.get());
diff --git a/pc/jseptransportcontroller_unittest.cc b/pc/jseptransportcontroller_unittest.cc
index 03ef2ea..fd8a779 100644
--- a/pc/jseptransportcontroller_unittest.cc
+++ b/pc/jseptransportcontroller_unittest.cc
@@ -385,6 +385,15 @@
EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid2));
EXPECT_EQ(nullptr,
transport_controller_->LookupDtlsTransportByMid(kVideoMid2));
+ // Take a pointer to a transport, shut down the transport controller,
+ // and verify that the resulting container is empty.
+ auto dtls_transport =
+ transport_controller_->LookupDtlsTransportByMid(kVideoMid1);
+ webrtc::DtlsTransport* my_transport =
+ static_cast<DtlsTransport*>(dtls_transport.get());
+ EXPECT_NE(nullptr, my_transport->internal());
+ transport_controller_.reset();
+ EXPECT_EQ(nullptr, my_transport->internal());
}
TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) {