]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ksmbd: reset rcount per connection in ksmbd_conn_wait_idle_sess_id()
authorDaeMyung Kang <charsyam@gmail.com>
Sat, 18 Apr 2026 17:28:44 +0000 (02:28 +0900)
committerSteve French <stfrench@microsoft.com>
Wed, 22 Apr 2026 13:11:23 +0000 (08:11 -0500)
rcount is intended to be connection-specific: 2 for curr_conn, 1 for
every other connection sharing the same session.  However, it is
initialised only once before the hash iteration and is never reset.
After the loop visits curr_conn, later sibling connections are also
checked against rcount == 2, so a sibling with req_running == 1 is
incorrectly treated as idle.  This makes the outcome depend on the
hash iteration order: whether a given sibling is checked against the
loose (< 2) or the strict (< 1) threshold is decided by whether it
happens to be visited before or after curr_conn.

The function's contract is "wait until every connection sharing this
session is idle" so that destroy_previous_session() can safely tear
the session down.  The latched rcount violates that contract and
reopens the teardown race window the wait logic was meant to close:
destroy_previous_session() may proceed before sibling channels have
actually quiesced, overlapping session teardown with in-flight work
on those connections.

Recompute rcount inside the loop so each connection is compared
against its own threshold regardless of iteration order.

This is a code-inspection fix for an iteration-order-dependent logic
error; a targeted reproducer would require SMB3 multichannel with
in-flight work on a sibling channel landing after curr_conn in hash
order, which is not something that can be triggered reliably.

Fixes: 76e98a158b20 ("ksmbd: fix race condition between destroy_previous_session() and smb2 operations()")
Cc: stable@vger.kernel.org
Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/server/connection.c

index a26899d12df17bb1435cb9f01b04c460e59bf0e3..b5e077f272cffc920b0b0442299377b8bba89eab 100644 (file)
@@ -237,7 +237,7 @@ int ksmbd_conn_wait_idle_sess_id(struct ksmbd_conn *curr_conn, u64 sess_id)
 {
        struct ksmbd_conn *conn;
        int rc, retry_count = 0, max_timeout = 120;
-       int rcount = 1, bkt;
+       int rcount, bkt;
 
 retry_idle:
        if (retry_count >= max_timeout)
@@ -246,8 +246,7 @@ retry_idle:
        down_read(&conn_list_lock);
        hash_for_each(conn_list, bkt, conn, hlist) {
                if (conn->binding || xa_load(&conn->sessions, sess_id)) {
-                       if (conn == curr_conn)
-                               rcount = 2;
+                       rcount = (conn == curr_conn) ? 2 : 1;
                        if (atomic_read(&conn->req_running) >= rcount) {
                                rc = wait_event_timeout(conn->req_running_q,
                                        atomic_read(&conn->req_running) < rcount,