]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
ksmbd: fix multichannel connection failure
authorNamjae Jeon <linkinjeon@kernel.org>
Mon, 24 Mar 2025 11:19:20 +0000 (20:19 +0900)
committerSteve French <stfrench@microsoft.com>
Fri, 28 Mar 2025 00:12:00 +0000 (19:12 -0500)
ksmbd check that the session of second channel is in the session list of
first connection. If it is in session list, multichannel connection
should not be allowed.

Fixes: b95629435b84 ("ksmbd: fix racy issue from session lookup and expire")
Reported-by: Sean Heelan <seanheelan@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/server/mgmt/user_session.c
fs/smb/server/mgmt/user_session.h
fs/smb/server/smb2pdu.c

index 1ecca6785ed0ca1ed86507b479e217d0ae8d4f10..53d308f331af82137ca5478eed25988677b471cf 100644 (file)
@@ -259,6 +259,22 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
        up_write(&sessions_table_lock);
 }
 
+bool is_ksmbd_session_in_connection(struct ksmbd_conn *conn,
+                                  unsigned long long id)
+{
+       struct ksmbd_session *sess;
+
+       down_read(&conn->session_lock);
+       sess = xa_load(&conn->sessions, id);
+       if (sess) {
+               up_read(&conn->session_lock);
+               return true;
+       }
+       up_read(&conn->session_lock);
+
+       return false;
+}
+
 struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
                                           unsigned long long id)
 {
index c1c4b20bd5c6cfd2f95b6fdf08fe4309fc9029f1..f21348381d5984fd02b77c4eefbfd02ef02a5f25 100644 (file)
@@ -87,6 +87,8 @@ void ksmbd_session_destroy(struct ksmbd_session *sess);
 struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id);
 struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
                                           unsigned long long id);
+bool is_ksmbd_session_in_connection(struct ksmbd_conn *conn,
+                                    unsigned long long id);
 int ksmbd_session_register(struct ksmbd_conn *conn,
                           struct ksmbd_session *sess);
 void ksmbd_sessions_deregister(struct ksmbd_conn *conn);
index 7717d81d3f9bebc4543993f281e24fe79bb9a889..4ddf4300371b8ed5b1261b0771012755f6cc31cf 100644 (file)
@@ -1707,44 +1707,38 @@ int smb2_sess_setup(struct ksmbd_work *work)
 
                if (conn->dialect != sess->dialect) {
                        rc = -EINVAL;
-                       ksmbd_user_session_put(sess);
                        goto out_err;
                }
 
                if (!(req->hdr.Flags & SMB2_FLAGS_SIGNED)) {
                        rc = -EINVAL;
-                       ksmbd_user_session_put(sess);
                        goto out_err;
                }
 
                if (strncmp(conn->ClientGUID, sess->ClientGUID,
                            SMB2_CLIENT_GUID_SIZE)) {
                        rc = -ENOENT;
-                       ksmbd_user_session_put(sess);
                        goto out_err;
                }
 
                if (sess->state == SMB2_SESSION_IN_PROGRESS) {
                        rc = -EACCES;
-                       ksmbd_user_session_put(sess);
                        goto out_err;
                }
 
                if (sess->state == SMB2_SESSION_EXPIRED) {
                        rc = -EFAULT;
-                       ksmbd_user_session_put(sess);
                        goto out_err;
                }
-               ksmbd_user_session_put(sess);
 
                if (ksmbd_conn_need_reconnect(conn)) {
                        rc = -EFAULT;
+                       ksmbd_user_session_put(sess);
                        sess = NULL;
                        goto out_err;
                }
 
-               sess = ksmbd_session_lookup(conn, sess_id);
-               if (!sess) {
+               if (is_ksmbd_session_in_connection(conn, sess_id)) {
                        rc = -EACCES;
                        goto out_err;
                }
@@ -1910,6 +1904,8 @@ out_err:
 
                        sess->last_active = jiffies;
                        sess->state = SMB2_SESSION_EXPIRED;
+                       ksmbd_user_session_put(sess);
+                       work->sess = NULL;
                        if (try_delay) {
                                ksmbd_conn_set_need_reconnect(conn);
                                ssleep(5);