linux/net/sctp
Ricardo Cañuelo Navarro 9e7c37fadb sctp: detect and prevent references to a freed transport in sendmsg
commit f1a69a940d upstream.

sctp_sendmsg() re-uses associations and transports when possible by
doing a lookup based on the socket endpoint and the message destination
address, and then sctp_sendmsg_to_asoc() sets the selected transport in
all the message chunks to be sent.

There's a possible race condition if another thread triggers the removal
of that selected transport, for instance, by explicitly unbinding an
address with setsockopt(SCTP_SOCKOPT_BINDX_REM), after the chunks have
been set up and before the message is sent. This can happen if the send
buffer is full, during the period when the sender thread temporarily
releases the socket lock in sctp_wait_for_sndbuf().

This causes the access to the transport data in
sctp_outq_select_transport(), when the association outqueue is flushed,
to result in a use-after-free read.

This change avoids this scenario by having sctp_transport_free() signal
the freeing of the transport, tagging it as "dead". In order to do this,
the patch restores the "dead" bit in struct sctp_transport, which was
removed in
commit 47faa1e4c5 ("sctp: remove the dead field of sctp_transport").

Then, in the scenario where the sender thread has released the socket
lock in sctp_wait_for_sndbuf(), the bit is checked again after
re-acquiring the socket lock to detect the deletion. This is done while
holding a reference to the transport to prevent it from being freed in
the process.

If the transport was deleted while the socket lock was relinquished,
sctp_sendmsg_to_asoc() will return -EAGAIN to let userspace retry the
send.

The bug was found by a private syzbot instance (see the error report [1]
and the C reproducer that triggers it [2]).

Link: https://people.igalia.com/rcn/kernel_logs/20250402__KASAN_slab-use-after-free_Read_in_sctp_outq_select_transport.txt [1]
Link: https://people.igalia.com/rcn/kernel_logs/20250402__KASAN_slab-use-after-free_Read_in_sctp_outq_select_transport__repro.c [2]
Cc: stable@vger.kernel.org
Fixes: df132eff46 ("sctp: clear the transport of some out_chunk_list chunks in sctp_assoc_rm_peer")
Suggested-by: Xin Long <lucien.xin@gmail.com>
Signed-off-by: Ricardo Cañuelo Navarro <rcn@igalia.com>
Acked-by: Xin Long <lucien.xin@gmail.com>
Link: https://patch.msgid.link/20250404-kasan_slab-use-after-free_read_in_sctp_outq_select_transport__20250404-v1-1-5ce4a0b78ef2@igalia.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
History 2025-04-20 10:15:50 +02:00
..
associola.c net/sctp: Prevent autoclose integer overflow in sctp_association_init() 2025-01-09 13:33:51 +01:00
auth.c sctp: delete the nested flexible array hmac 2023-04-21 08:19:30 +01:00
bind_addr.c sctp: fail if no bound addresses can be used for a given scope 2023-01-24 18:32:33 -08:00
chunk.c net: sctp: chunk.c: delete duplicated word 2020-08-24 16:21:43 -07:00
debug.c sctp: add the probe timer in transport for PLPMTUD 2021-06-22 11:28:52 -07:00
diag.c inet_diag: add module pointer to "struct inet_diag_handler" 2024-01-23 15:13:54 +01:00
endpointola.c sctp: add dif and sdif check in asoc and ep lookup 2022-11-18 11:42:54 +00:00
input.c sctp: Fix null-ptr-deref in reuseport_add_sock(). 2024-08-02 16:25:06 -07:00
inqueue.c net: sctp: fix skb leak in sctp_inq_free() 2024-02-15 07:34:52 -08:00
ipv6.c sctp: fix possible UAF in sctp_v6_available() 2024-11-09 09:15:04 -08:00
Kconfig sctp: create udp4 sock and add its encap_rcv 2020-10-30 15:23:52 -07:00
Makefile sctp: add fair capacity stream scheduler 2023-03-09 11:31:44 +01:00
objcnt.c treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 104 2019-05-24 17:39:00 +02:00
offload.c net: move gso declarations and functions to their own files 2023-06-10 00:11:41 -07:00
output.c net: allow gso_max_size to exceed 65536 2022-05-16 10:18:55 +01:00
outqueue.c sctp: delete the nested flexible array variable 2023-04-21 08:19:29 +01:00
primitive.c treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 104 2019-05-24 17:39:00 +02:00
proc.c sctp: annotate data-races around sk->sk_wmem_queued 2023-08-31 11:56:59 +02:00
protocol.c sctp: Unmask upper DSCP bits in sctp_v4_get_dst() 2024-09-09 14:14:53 +01:00
sm_make_chunk.c sctp: Spelling s/preceeding/preceding/g 2023-10-04 14:04:58 -07:00
sm_sideeffect.c sctp: handle invalid error codes without calling BUG() 2023-06-12 09:36:27 +01:00
sm_statefuns.c sctp: properly validate chunk size in sctp_sf_ootb() 2024-11-03 11:03:23 -08:00
sm_statetable.c sctp: add the probe timer in transport for PLPMTUD 2021-06-22 11:28:52 -07:00
socket.c sctp: detect and prevent references to a freed transport in sendmsg 2025-04-20 10:15:50 +02:00
stream.c sctp: Fix undefined behavior in left shift operation 2025-03-22 12:54:19 -07:00
stream_interleave.c sctp: delete the nested flexible array skip 2023-04-21 08:19:29 +01:00
stream_sched.c sctp: fix a potential OOB access in sctp_sched_set_sched() 2023-05-10 12:10:15 +01:00
stream_sched_fc.c sctp: add weighted fair queueing stream scheduler 2023-03-09 11:31:44 +01:00
stream_sched_prio.c sctp: add a refcnt in sctp_stream_priorities to avoid a nested loop 2023-02-23 12:59:40 -08:00
stream_sched_rr.c sctp: delete free member from struct sctp_sched_ops 2022-12-01 20:14:23 -08:00
sysctl.c sctp: add mutual exclusion in proc_sctp_do_udp_port() 2025-04-10 14:39:34 +02:00
transport.c sctp: detect and prevent references to a freed transport in sendmsg 2025-04-20 10:15:50 +02:00
tsnmap.c net: sctp: trivial: fix typo in comment 2021-03-04 13:48:32 -08:00
ulpevent.c net: remove noblock parameter from recvmsg() entities 2022-04-12 15:00:25 +02:00
ulpqueue.c sctp: remove unnecessary NULL check in sctp_ulpq_tail_event() 2022-10-20 21:43:10 -07:00