* [PATCH v2] RDMA/siw: Fix early peer close handling on listeners
@ 2026-11-04 10:10 Jaeyeong Lee
0 siblings, 0 replies; only message in thread
From: Jaeyeong Lee @ 2026-11-04 10:10 UTC (permalink / raw)
To: Bernard Metzler
Cc: Jason Gunthorpe, Leon Romanovsky, linux-rdma, linux-kernel
A TCP child socket inherits the listener callbacks and sk_user_data before
kernel_accept() associates it with a new connection endpoint. If the peer
closes during this window, siw_cm_llp_state_change() queues a PEER_CLOSE
work item against the listening endpoint.
The worker releases that endpoint without removing it from the listener
list. A later listener teardown then walks the dangling entry, causing a
use-after-free in siw_destroy_listen().
Ignoring close notifications while the endpoint is LISTENING is not
sufficient. The endpoint remains IDLE for a short interval after listen()
starts accepting connections, and a close delivered before the accepted
socket is handed to its new endpoint would otherwise be lost.
Ignore close notifications from unaccepted child sockets during the IDLE
interval as well. During accept, serialize the endpoint handoff with TCP
state changes and reject a child that has already reached TCP_CLOSE or
TCP_CLOSE_WAIT. Live accepted sockets continue through the normal close
path.
The issue was found by static analysis. It was reproduced with SIW over
loopback in an x86_64 QEMU guest. KASAN reported the listener endpoint
use-after-free on the unpatched kernel. Tests covering RST before accept,
an MPA request followed by FIN, and an extended post-listen IDLE window
completed without KASAN or lockdep reports after this change.
Fixes: 6c52fdc244b5 ("rdma/siw: connection management")
Cc: stable@vger.kernel.org
Signed-off-by: Jaeyeong Lee <lee@jaeyeong.cc>
---
Changes in v2:
- Cover the IDLE interval between listen() and the LISTENING transition.
- Serialize accepted-socket handoff and reject an already closed child.
drivers/infiniband/sw/siw/siw_cm.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/drivers/infiniband/sw/siw/siw_cm.c b/drivers/infiniband/sw/siw/siw_cm.c
index ed49818793dde..92fcbcabb5984 100644
--- a/drivers/infiniband/sw/siw/siw_cm.c
+++ b/drivers/infiniband/sw/siw/siw_cm.c
@@ -973,6 +973,7 @@ static void siw_accept_newconn(struct siw_cep *cep)
struct socket *s = cep->sock;
struct socket *new_s = NULL;
struct siw_cep *new_cep = NULL;
+ bool peer_closed;
int rv = 0; /* debug only. should disappear */
if (cep->state != SIW_EPSTATE_LISTENING)
@@ -1009,11 +1010,23 @@ static void siw_accept_newconn(struct siw_cep *cep)
}
new_cep->sock = new_s;
siw_cep_get(new_cep);
- new_s->sk->sk_user_data = new_cep;
if (siw_tcp_nagle == false)
tcp_sock_set_nodelay(new_s->sk);
+
+ lock_sock(new_s->sk);
+ write_lock_bh(&new_s->sk->sk_callback_lock);
new_cep->state = SIW_EPSTATE_AWAIT_MPAREQ;
+ new_s->sk->sk_user_data = new_cep;
+ peer_closed = new_s->sk->sk_state == TCP_CLOSE ||
+ new_s->sk->sk_state == TCP_CLOSE_WAIT;
+ write_unlock_bh(&new_s->sk->sk_callback_lock);
+ release_sock(new_s->sk);
+
+ if (peer_closed) {
+ rv = -ECONNRESET;
+ goto error;
+ }
rv = siw_cm_queue_work(new_cep, SIW_CM_WORK_MPATIMEOUT);
if (rv)
@@ -1361,6 +1374,10 @@ static void siw_cm_llp_state_change(struct sock *sk)
case TCP_CLOSE:
case TCP_CLOSE_WAIT:
+ if (cep->state == SIW_EPSTATE_LISTENING ||
+ (cep->state == SIW_EPSTATE_IDLE &&
+ !READ_ONCE(sk->sk_socket)))
+ break;
if (cep->qp)
cep->qp->tx_ctx.tx_suspend = 1;
siw_cm_queue_work(cep, SIW_CM_WORK_PEER_CLOSE);
--
2.43.0
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-11-04 10:10 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-04 10:10 [PATCH v2] RDMA/siw: Fix early peer close handling on listeners Jaeyeong Lee
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®