]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
RDMA/siw: Fix endpoint/socket association handling
authorBernard Metzler <bernard.metzler@linux.dev>
Thu, 4 Jun 2026 16:08:08 +0000 (18:08 +0200)
committerJason Gunthorpe <jgg@nvidia.com>
Fri, 5 Jun 2026 17:25:52 +0000 (14:25 -0300)
Disassociating a socket from an endpoint via siw_socket_disassoc() may
release the last reference on that endpoint and free it. Therefore, don't
clear the endpoints socket pointer after calling that function, but
within.

This fixes a:

  BUG: KASAN: slab-use-after-free in siw_cm_work_handler (drivers/infiniband/sw/siw/siw_cm.c:1053 drivers/infiniband/sw/siw/siw_cm.c:1075)

which occurred after processing a malformed MPA request during connection
establishment, causing the new endpoint to be closed.

Fixes: 6c52fdc244b5c ("rdma/siw: connection management")
Link: https://patch.msgid.link/r/20260604160808.30948-1-bernard.metzler@linux.dev
Reported-by: Shuangpeng Bai <shuangpeng.kernel@gmail.com>
Signed-off-by: Bernard Metzler <bernard.metzler@linux.dev>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
drivers/infiniband/sw/siw/siw_cm.c

index f7ac81c0f267a6cab76a870197a9d0b388c31055..87c79527ac0903f4183d01ed010ed92d82dffb4a 100644 (file)
@@ -138,6 +138,7 @@ static void siw_socket_disassoc(struct socket *s)
                cep = sk_to_cep(sk);
                if (cep) {
                        siw_sk_restore_upcalls(sk, cep);
+                       cep->sock = NULL;
                        siw_cep_put(cep);
                } else {
                        pr_warn("siw: cannot restore sk callbacks: no ep\n");
@@ -418,10 +419,11 @@ static void siw_free_cm_id(struct siw_cep *cep)
 
 static void siw_destroy_cep_sock(struct siw_cep *cep)
 {
-       if (cep->sock) {
-               siw_socket_disassoc(cep->sock);
-               sock_release(cep->sock);
-               cep->sock = NULL;
+       struct socket *s = cep->sock;
+
+       if (s) {
+               siw_socket_disassoc(s);
+               sock_release(s);
        }
 }
 
@@ -1050,7 +1052,6 @@ error:
        if (new_s) {
                siw_socket_disassoc(new_s);
                sock_release(new_s);
-               new_cep->sock = NULL;
        }
        siw_dbg_cep(cep, "error %d\n", rv);
 }
@@ -1202,6 +1203,8 @@ static void siw_cm_work_handler(struct work_struct *w)
                WARN(1, "Undefined CM work type: %d\n", work->type);
        }
        if (release_cep) {
+               struct socket *s = cep->sock;
+
                siw_dbg_cep(cep,
                            "release: timer=%s, QP[%u]\n",
                            cep->mpa_timer ? "y" : "n",
@@ -1227,10 +1230,9 @@ static void siw_cm_work_handler(struct work_struct *w)
                        cep->qp = NULL;
                        siw_qp_put(qp);
                }
-               if (cep->sock) {
-                       siw_socket_disassoc(cep->sock);
-                       sock_release(cep->sock);
-                       cep->sock = NULL;
+               if (s) {
+                       siw_socket_disassoc(s);
+                       sock_release(s);
                }
                if (cep->cm_id) {
                        siw_free_cm_id(cep);
@@ -1561,7 +1563,6 @@ error:
        if (cep) {
                siw_socket_disassoc(s);
                sock_release(s);
-               cep->sock = NULL;
 
                cep->qp = NULL;
 
@@ -1937,7 +1938,6 @@ error:
                siw_cep_set_inuse(cep);
 
                siw_free_cm_id(cep);
-               cep->sock = NULL;
                siw_socket_disassoc(s);
                cep->state = SIW_EPSTATE_CLOSED;
 
@@ -1959,6 +1959,7 @@ static void siw_drop_listeners(struct iw_cm_id *id)
         */
        list_for_each_safe(p, tmp, (struct list_head *)id->provider_data) {
                struct siw_cep *cep = list_entry(p, struct siw_cep, listenq);
+               struct socket *s = cep->sock;
 
                list_del(p);
 
@@ -1967,10 +1968,9 @@ static void siw_drop_listeners(struct iw_cm_id *id)
                siw_cep_set_inuse(cep);
 
                siw_free_cm_id(cep);
-               if (cep->sock) {
-                       siw_socket_disassoc(cep->sock);
-                       sock_release(cep->sock);
-                       cep->sock = NULL;
+               if (s) {
+                       siw_socket_disassoc(s);
+                       sock_release(s);
                }
                cep->state = SIW_EPSTATE_CLOSED;
                siw_cep_set_free_and_put(cep);