]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
sctp: diag: reject stale associations in dump_one path
authorZhao Zhang <zzhan461@ucr.edu>
Sat, 30 May 2026 15:57:14 +0000 (23:57 +0800)
committerJakub Kicinski <kuba@kernel.org>
Tue, 2 Jun 2026 21:25:17 +0000 (14:25 -0700)
The SCTP exact sock_diag lookup can hold a transport reference, block on
lock_sock(sk), and then resume after sctp_association_free() has marked
the association dead and freed its bind address list.

When that happens, inet_assoc_attr_size() and
inet_diag_msg_sctpasoc_fill() can still dereference association state
that is no longer valid for reporting. In particular,
inet_diag_msg_sctpasoc_fill() may read an empty bind-address list as a
real sctp_sockaddr_entry and trigger an out-of-bounds read from
unrelated association memory.

Reject the association after taking the socket lock if it has been
reaped or detached from the endpoint, and report the lookup as stale.
This keeps the exact dump-one path from formatting torn association
state.

Fixes: 8f840e47f190 ("sctp: add the sctp_diag.c file")
Cc: stable@kernel.org
Reported-by: Yuan Tan <yuantan098@gmail.com>
Reported-by: Yifan Wu <yifanwucs@gmail.com>
Reported-by: Juefei Pu <tomapufckgml@gmail.com>
Reported-by: Zhengchuan Liang <zcliangcn@gmail.com>
Reported-by: Xin Liu <bird@lzu.edu.cn>
Signed-off-by: Zhao Zhang <zzhan461@ucr.edu>
Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
Acked-by: Xin Long <lucien.xin@gmail.com>
Link: https://patch.msgid.link/fac6043fa20a2ff68e12958c431836f692c51268.1780113823.git.zzhan461@ucr.edu
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/sctp/diag.c

index 2afb376299fe47c214216476f5a99adbe98cc158..d758f5c3e06e565335a1b9232f94f7973b5578fe 100644 (file)
@@ -266,15 +266,15 @@ static int sctp_sock_dump_one(struct sctp_endpoint *ep, struct sctp_transport *t
 
        lock_sock(sk);
 
-       rep = nlmsg_new(inet_assoc_attr_size(sk, assoc), GFP_KERNEL);
-       if (!rep) {
-               release_sock(sk);
-               return -ENOMEM;
+       if (ep != assoc->ep || assoc->base.dead) {
+               err = -ESTALE;
+               goto out_unlock;
        }
 
-       if (ep != assoc->ep) {
-               err = -EAGAIN;
-               goto out;
+       rep = nlmsg_new(inet_assoc_attr_size(sk, assoc), GFP_KERNEL);
+       if (!rep) {
+               err = -ENOMEM;
+               goto out_unlock;
        }
 
        err = inet_sctp_diag_fill(sk, assoc, rep, req, sk_user_ns(NETLINK_CB(skb).sk),
@@ -289,8 +289,9 @@ static int sctp_sock_dump_one(struct sctp_endpoint *ep, struct sctp_transport *t
        return nlmsg_unicast(sock_net(skb->sk)->diag_nlsk, rep, NETLINK_CB(skb).portid);
 
 out:
-       release_sock(sk);
        kfree_skb(rep);
+out_unlock:
+       release_sock(sk);
        return err;
 }