* [PATCH net] sctp: re-point the GSO head_skb socket on association migration
@ 2026-07-30 11:05 Jun Yang
0 siblings, 0 replies; only message in thread
From: Jun Yang @ 2026-07-30 11:05 UTC (permalink / raw)
To: netdev
Cc: Jun Yang, stable, TencentOS Corvus AI, Marcelo Ricardo Leitner,
Xin Long, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, linux-sctp, linux-kernel
From: Jun Yang <junvyyang@tencent.com>
sctp_ulpevent_set_owner() stashes the receiving socket on the GSO "cover
letter" skb as a bare pointer (net/sctp/ulpevent.c:90):
if (chunk && chunk->head_skb && !chunk->head_skb->sk)
chunk->head_skb->sk = asoc->base.sk;
That store takes no reference and installs no destructor, unlike the
sctp_skb_set_owner_r() applied to the event skb just above it.
When an association is moved to another socket -- SCTP_SOCKOPT_PEELOFF, or
accept() on a TCP-style socket -- sctp_sock_migrate() re-owns the queued
skbs with sctp_skb_set_owner_r_frag(). That walks the receive, lobby and
reassembly queues, but chunk->head_skb is on none of them: it is reachable
only through event->chunk->head_skb. Its ->sk therefore keeps pointing at
the original socket. Once that socket is closed and freed, the dangling
pointer is dereferenced on the very next receive, in sctp_recvmsg()
(net/sctp/socket.c:2155):
sp->pf->skb_msgname(head_skb, msg->msg_name, &msg->msg_namelen);
which for IPv6 reads sctp_sk(skb->sk)->v4mapped (net/sctp/ipv6.c:894).
Re-point the cover-letter skb during migration as well. The event lives in
skb->cb of the event skb only, so this cannot be folded into
sctp_skb_set_owner_r_frag(), which also recurses over fragment skbs; add a
small wrapper and use it at the three migration call sites.
BUG: KASAN: slab-use-after-free in sctp_inet6_skb_msgname+0x633/0xb30
Read of size 2 at addr ff1100010aafc8e0 by task gso_uaf/6387
CPU: 1 UID: 1000 PID: 6387 Comm: gso_uaf
sctp_inet6_skb_msgname+0x633/0xb30
sctp_recvmsg+0x481/0xa00
sock_recvmsg+0x121/0x170
Freed by task 0:
__sk_destruct+0x39d/0x4c0
sctp_endpoint_destroy_rcu+0x8b/0xc0
The buggy address belongs to the object at ff1100010aafc380
which belongs to the cache SCTPv6 of size 1560
Fixes: 90017accff61 ("sctp: Add GSO support")
Cc: stable@kernel.org
Reported-by: TencentOS Corvus AI <corvus@tencent.com>
Signed-off-by: Jun Yang <junvyyang@tencent.com>
---
net/sctp/socket.c | 27 ++++++++++++++++++++++++---
1 file changed, 24 insertions(+), 3 deletions(-)
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index c7b9e325ec1c..ade413bbec56 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -9522,6 +9522,27 @@ static void sctp_skb_set_owner_r_frag(struct sk_buff *skb, struct sock *sk)
sctp_skb_set_owner_r(skb, sk);
}
+/* Re-own a queued event's skbs, including the GSO "cover letter" skb.
+ *
+ * sctp_ulpevent_set_owner() stashes the socket on chunk->head_skb as a bare
+ * pointer, with no reference and no destructor. That skb is not on any of the
+ * queues walked during a migration, so it has to be re-pointed explicitly.
+ *
+ * Only the event skb itself carries a struct sctp_ulpevent in ->cb, so this
+ * must not be folded into the recursive helper above, which also visits
+ * fragment skbs.
+ */
+static void sctp_skb_set_owner_r_event(struct sk_buff *skb, struct sock *sk)
+{
+ struct sctp_ulpevent *event = sctp_skb2event(skb);
+
+ sctp_skb_set_owner_r_frag(skb, sk);
+
+ if (event->chunk && event->chunk->head_skb &&
+ event->chunk->head_skb != skb)
+ event->chunk->head_skb->sk = sk;
+}
+
/* Populate the fields of the newsk from the oldsk and migrate the assoc
* and its messages to the newsk.
*/
@@ -9571,7 +9592,7 @@ static int sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
if (event->asoc == assoc) {
__skb_unlink(skb, &oldsk->sk_receive_queue);
__skb_queue_tail(&newsk->sk_receive_queue, skb);
- sctp_skb_set_owner_r_frag(skb, newsk);
+ sctp_skb_set_owner_r_event(skb, newsk);
}
}
@@ -9600,7 +9621,7 @@ static int sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
if (event->asoc == assoc) {
__skb_unlink(skb, &oldsp->pd_lobby);
__skb_queue_tail(queue, skb);
- sctp_skb_set_owner_r_frag(skb, newsk);
+ sctp_skb_set_owner_r_event(skb, newsk);
}
}
@@ -9612,7 +9633,7 @@ static int sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
}
- sctp_for_each_rx_skb(assoc, newsk, sctp_skb_set_owner_r_frag);
+ sctp_for_each_rx_skb(assoc, newsk, sctp_skb_set_owner_r_event);
/* Set the type of socket to indicate that it is peeled off from the
* original UDP-style socket or created with the accept() call on a
--
2.43.7
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-07-30 11:06 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-30 11:05 [PATCH net] sctp: re-point the GSO head_skb socket on association migration Jun Yang
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.