From: Stefan Metzmacher <metze@samba.org>
To: linux-cifs@vger.kernel.org, samba-technical@lists.samba.org
Cc: metze@samba.org, Namjae Jeon <linkinjeon@kernel.org>,
Paulo Alcantara <pc@manguebit.org>, Tom Talpey <tom@talpey.com>,
Lee Seong Hyeon <ihopenre@gmail.com>
Subject: [PATCH v4 0/3] smb: smbdirect: fix listener backlog leak and teardown races
Date: Fri, 9 Oct 2026 12:02:10 +0200 [thread overview]
Message-ID: <cover.1791540051.git.metze@samba.org> (raw)
Hi Namjae,
These fix a set of problems in the shared smbdirect module
(fs/smb/smbdirect/), reached through the listener/accept path, which in
practice is driven by ksmbd for incoming SMB Direct connections.
The main one is a pre-authentication remote denial of service: the
listener keeps every accepted connection on a fixed-size backlog
(listen.pending, limit 10 for ksmbd). A connection is only removed from
that backlog on the success path (promotion to listen.ready after a
completed negotiate, or dequeue by accept()). A connection that is
accepted at the RDMA level but then fails before it is accepted by the
upper layer - negotiate timeout, peer disconnect, or an invalid
negotiate request - is never removed, so its backlog slot is leaked.
After about ten such events the listener rejects every new connection
with -EBUSY and SMB Direct stays unusable until the service is
restarted. An unauthenticated peer can trigger this with ~10 aborted
connections.
This was reported by Lee Seong Hyeon <ihopenre@gmail.com>:
https://lore.kernel.org/linux-cifs/CANTrAmxL5sWU8Sn29JAGZvSq5PBB2OA+VKA0MHsZJMesagtfzA@mail.gmail.com/
The series:
- smbdirect_socket_destroy_sync() no longer waits for
RDMA_CM_EVENT_DISCONNECTED after rdma_disconnect(). That wait could
take very long (until the rdma cm gives up, e.g. a peer that just
vanished) or never complete if the event already happened and the
status was overwritten. rdma_destroy_id() in
smbdirect_socket_destroy() is enough to stop further events; the
rest of the disconnect protocol is handled by the rdma core
asynchronously. This also makes releasing orphaned sockets
(next patch) non-blocking.
- A failed, not-yet-accepted child of a listener now moves itself to a
new listen.orphaned list at the end of its cleanup work and queues
listen.purge_orphaned_work, which releases it, so it no longer leaks
its backlog slot (nor its struct sock / RDMA resources) for the
lifetime of the listener. sc->accept.listener is only changed under
listener->listen.lock, and whoever clears it owns the release;
the listener is freed via kfree_rcu() so a child can dereference it
under rcu_read_lock(). This is the DoS fix.
- smbdirect_socket_accept() no longer hands out a socket that failed
after it was put on the ready list (e.g. the peer disconnected in
the meantime); it checks first_error / the status under listen.lock,
orphans such a socket and tries the next one. And it also
no longer returns -EAGAIN if a non zero timeout was passed.
I tested the reproducer and the problem is fixed
and I run various xfstests.
I think these are important and should go into 7.3
Changes since v3:
(https://lore.kernel.org/r/cover.1791311817.git.metze@samba.org/)
- "smb: smbdirect: release failed pending sockets of a listener":
install the real event handler and the expected event at the very
start of smbdirect_accept_connect_request(), before anything that can
fail. On an early error the caller only schedules nsc's deferred
cleanup and returns 0, so the rdma_cm core keeps the cm_id - it must
then already carry smbdirect_accept_rdma_event_handler(), which turns
any unexpected event (e.g. RDMA_CM_EVENT_DEVICE_REMOVAL) into a clean
smbdirect_socket_schedule_cleanup(). Previously the placeholder
smbdirect_socket_rdma_event_handler() left by
smbdirect_socket_init_accepting() stayed installed on that path and
returned -ESTALE, making the rdma_cm core destroy the cm_id behind the
back of the pending teardown.
- smbdirect_socket_accept always goes back to smbdirect_socket_wait_for_accept
when no valid new socket was found, so that we don't return -EAGAIN
unless a zero timeout was given.
Changes since v2:
(https://lore.kernel.org/r/cover.1791229120.git.metze@samba.org/)
- "smb: smbdirect: release failed pending sockets of a listener":
reworked the connect-request error handling after more Sashiko
review. smbdirect_accept_connect_request() no longer tears down any
RDMA state or clears the cm_id on failure; it only returns a
not-yet-posted recv_io to the pool and returns the error.
smbdirect_listen_connect_request() now sets nsc->accept.listener and
publishes nsc on the pending list *before* it calls
smbdirect_accept_connect_request(), and on a non-zero return it
schedules nsc's teardown with smbdirect_socket_schedule_cleanup() and
always returns 0, so the rdma_cm core keeps the connection id and nsc
owns it (and destroys it in its own deferred teardown). The teardown
must be deferred because nsc's id_priv->handler_mutex is held by the
rdma_cm core across the CONNECT_REQUEST handler; that same lock (and
the listener's) also guarantees nsc can't go away under us. This
closes the race Sashiko reported, where a connection that established
between rdma_accept() and setting the listener could be left stranded
on the pending list.
Changes since v1:
(https://lore.kernel.org/r/cover.1791224972.git.metze@samba.org)
- "smb: smbdirect: release failed pending sockets of a listener":
fix a use-after-free and a missed-orphan race in
smbdirect_listen_connect_request(), spotted by Sashiko. The
nsc->first_error check and the orphaning are now done under
listen.lock, together with setting nsc->accept.listener, so a
concurrent smbdirect_socket_cleanup_work()/purge_orphaned_work()
can neither free nsc while we still look at it, nor miss the
orphaning and leak it on the pending list.
- "smb: smbdirect: don't hand out already failed sockets in
smbdirect_socket_accept()": bound the accept() wait across the
"skip a failed socket and try the next one" retries, also spotted
by Sashiko. smbdirect_socket_wait_for_accept() now returns the
remaining timeout and smbdirect_socket_accept() carries it over, so
a stream of failed connections can no longer reset the caller's
timeout. ksmbd passes MAX_SCHEDULE_TIMEOUT, so it is unaffected in
practice.
- Added Reported-by:/Closes: for the Sashiko reviews.
Stefan Metzmacher (3):
smb: smbdirect: don't wait for RDMA_CM_EVENT_DISCONNECTED in
smbdirect_socket_destroy_sync()
smb: smbdirect: release failed pending sockets of a listener
smb: smbdirect: don't hand out already failed sockets in
smbdirect_socket_accept()
fs/smb/smbdirect/accept.c | 225 ++++++++++++++++++++++++----------
fs/smb/smbdirect/connection.c | 12 +-
fs/smb/smbdirect/internal.h | 2 +
fs/smb/smbdirect/listen.c | 137 +++++++++++++++++++--
fs/smb/smbdirect/socket.c | 113 +++++++++++++++--
fs/smb/smbdirect/socket.h | 42 +++++++
6 files changed, 438 insertions(+), 93 deletions(-)
--
2.43.0
next reply other threads:[~2026-10-09 10:02 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-09 10:02 Stefan Metzmacher [this message]
2026-10-09 10:02 ` [PATCH v4 1/3] smb: smbdirect: don't wait for RDMA_CM_EVENT_DISCONNECTED in smbdirect_socket_destroy_sync() Stefan Metzmacher
2026-10-09 10:02 ` [PATCH v4 2/3] smb: smbdirect: release failed pending sockets of a listener Stefan Metzmacher
2026-10-09 10:02 ` [PATCH v4 3/3] smb: smbdirect: don't hand out already failed sockets in smbdirect_socket_accept() Stefan Metzmacher
2026-10-09 12:46 ` [PATCH v4 0/3] smb: smbdirect: fix listener backlog leak and teardown races Namjae Jeon
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=cover.1791540051.git.metze@samba.org \
--to=metze@samba.org \
--cc=ihopenre@gmail.com \
--cc=linkinjeon@kernel.org \
--cc=linux-cifs@vger.kernel.org \
--cc=pc@manguebit.org \
--cc=samba-technical@lists.samba.org \
--cc=tom@talpey.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox