dcsctp: Don't access TCB when the socket is closed

When the shutdown timer has expired, the socket will abort/close and the
TCB is not valid after InternalClose.

Bug: webrtc:12614
Change-Id: I09a94a049f0cda4577225dd9c80a92a8ec7e0423
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/217767
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33956}
This commit is contained in:
Victor Boivie
2021-05-07 11:22:50 +02:00
committed by WebRTC LUCI CQ
parent cf2aeffdc2
commit 914925f51e
2 changed files with 40 additions and 6 deletions

View File

@ -763,12 +763,7 @@ absl::optional<DurationMs> DcSctpSocket::OnShutdownTimerExpiry() {
<< " has expired: " << t2_shutdown_->expiration_count()
<< "/" << t2_shutdown_->options().max_restarts;
// https://tools.ietf.org/html/rfc4960#section-9.2
// "If the timer expires, the endpoint must resend the SHUTDOWN with the
// updated last sequential TSN received from its peer."
if (t2_shutdown_->is_running()) {
SendShutdown();
} else {
if (!t2_shutdown_->is_running()) {
// https://tools.ietf.org/html/rfc4960#section-9.2
// "An endpoint should limit the number of retransmissions of the SHUTDOWN
// chunk to the protocol parameter 'Association.Max.Retrans'. If this
@ -781,7 +776,14 @@ absl::optional<DurationMs> DcSctpSocket::OnShutdownTimerExpiry() {
.Build())));
InternalClose(ErrorKind::kTooManyRetries, "No SHUTDOWN_ACK received");
RTC_DCHECK(IsConsistent());
return absl::nullopt;
}
// https://tools.ietf.org/html/rfc4960#section-9.2
// "If the timer expires, the endpoint must resend the SHUTDOWN with the
// updated last sequential TSN received from its peer."
SendShutdown();
RTC_DCHECK(IsConsistent());
return tcb_->current_rto();
}

View File

@ -30,6 +30,7 @@
#include "net/dcsctp/packet/chunk/idata_chunk.h"
#include "net/dcsctp/packet/chunk/init_chunk.h"
#include "net/dcsctp/packet/chunk/sack_chunk.h"
#include "net/dcsctp/packet/chunk/shutdown_chunk.h"
#include "net/dcsctp/packet/error_cause/error_cause.h"
#include "net/dcsctp/packet/error_cause/unrecognized_chunk_type_cause.h"
#include "net/dcsctp/packet/parameter/heartbeat_info_parameter.h"
@ -507,6 +508,37 @@ TEST_F(DcSctpSocketTest, ShutdownConnection) {
EXPECT_EQ(sock_z_.state(), SocketState::kClosed);
}
TEST_F(DcSctpSocketTest, ShutdownTimerExpiresTooManyTimeClosesConnection) {
ConnectSockets();
sock_a_.Shutdown();
// Drop first SHUTDOWN packet.
cb_a_.ConsumeSentPacket();
EXPECT_EQ(sock_a_.state(), SocketState::kShuttingDown);
for (int i = 0; i < options_.max_retransmissions; ++i) {
AdvanceTime(DurationMs(options_.rto_initial * (1 << i)));
RunTimers();
// Dropping every shutdown chunk.
ASSERT_HAS_VALUE_AND_ASSIGN(SctpPacket packet,
SctpPacket::Parse(cb_a_.ConsumeSentPacket()));
EXPECT_EQ(packet.descriptors()[0].type, ShutdownChunk::kType);
EXPECT_TRUE(cb_a_.ConsumeSentPacket().empty());
}
// The last expiry, makes it abort the connection.
AdvanceTime(options_.rto_initial * (1 << options_.max_retransmissions));
EXPECT_CALL(cb_a_, OnAborted).Times(1);
RunTimers();
EXPECT_EQ(sock_a_.state(), SocketState::kClosed);
ASSERT_HAS_VALUE_AND_ASSIGN(SctpPacket packet,
SctpPacket::Parse(cb_a_.ConsumeSentPacket()));
EXPECT_EQ(packet.descriptors()[0].type, AbortChunk::kType);
EXPECT_TRUE(cb_a_.ConsumeSentPacket().empty());
}
TEST_F(DcSctpSocketTest, EstablishConnectionWhileSendingData) {
sock_a_.Connect();