]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ksmbd: fix multichannel connection failure
authorNamjae Jeon <linkinjeon@kernel.org>
Mon, 24 Mar 2025 11:19:20 +0000 (20:19 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 10 Apr 2025 12:32:02 +0000 (14:32 +0200)
[ Upstream commit c1883049aa9b2b7dffd3a68c5fc67fa92c174bd9 ]

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/ksmbd/mgmt/user_session.c
fs/ksmbd/mgmt/user_session.h
fs/ksmbd/smb2pdu.c

index 1cee9733bdac548db6a21afb24a0a85b6bce033c..f59714bfc819b72dd134f594ac6361e4c5596f13 100644 (file)
@@ -250,6 +250,22 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
        up_write(&conn->session_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 ce91b1d698e710d3583decc61d7ce19a9f94e843..f4da293c4dbb2cc63191740af58507bb9c9825e8 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 82b6be188ad4a695919fbdef9829b703d89cc618..3dfe0acf21a5daf60d5d1fa1fd056787a018e996 100644 (file)
@@ -1725,44 +1725,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;
                }
@@ -1928,6 +1922,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);