From: Jun Yang sctp_wait_for_connect() drops the socket lock while it sleeps. An out-of-the-blue ABORT can then be processed from the socket backlog and unlink the association. If a concurrent shutdown(fd, SHUT_RD) sets RCV_SHUTDOWN, the waiter breaks with err == 0. Its final put can then free the association. sctp_sendmsg_to_asoc() consequently continues with a dangling pointer. An earlier version moved the asoc->base.dead check ahead of the RCV_SHUTDOWN break in sctp_wait_for_connect(). That changes behavior for the connect() caller of the shared wait helper and reportedly breaks SCTP selftests. Keep the change local to the vulnerable sendmsg caller instead. Hold an extra association reference across sctp_wait_for_connect(), sample base.dead while the socket lock is still held, and only then drop the extra reference. Reject either a wait error or a dead association with the existing -ESRCH result. The extra reference prevents the waiter's final put from freeing the object before the check, while the socket lock prevents a new teardown between the check and the following send path. Fixes: 668c9beb9020 ("sctp: implement assign_number for sctp_stream_interleave") Cc: stable@vger.kernel.org Reported-by: TencentOS Corvus AI Assisted-by: tencentos-corvus-ai:hy4-preview Signed-off-by: Jun Yang --- v2: - Leave sctp_wait_for_connect() unchanged to preserve connect() semantics. - Hold and validate the association in the sendmsg-only caller. - Run the in-tree SCTP VRF selftest and the original reproducer. net/sctp/socket.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index c7b9e325e..09fd6b951 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1842,9 +1842,14 @@ static int sctp_sendmsg_to_asoc(struct sctp_association *asoc, goto err; if (asoc->ep->intl_enable) { + bool dead; + timeo = sock_sndtimeo(sk, 0); + sctp_association_hold(asoc); err = sctp_wait_for_connect(asoc, &timeo); - if (err) { + dead = asoc->base.dead; + sctp_association_put(asoc); + if (err || dead) { err = -ESRCH; goto err; } -- 2.43.0