]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
ksmbd: fix racy issue from session lookup and expire
authorNamjae Jeon <linkinjeon@kernel.org>
Thu, 5 Dec 2024 12:38:47 +0000 (21:38 +0900)
committerSteve French <stfrench@microsoft.com>
Tue, 10 Dec 2024 23:48:06 +0000 (17:48 -0600)
Increment the session reference count within the lock for lookup to avoid
racy issue with session expire.

Cc: stable@vger.kernel.org
Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-25737
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/server/auth.c
fs/smb/server/mgmt/user_session.c
fs/smb/server/server.c
fs/smb/server/smb2pdu.c

index 1d1ffd0acaca275984d94a6aa1a58e13bc71aa09..2a5b4a96bf99383f82cd6ec2d9b30eb961064905 100644 (file)
@@ -1016,6 +1016,8 @@ static int ksmbd_get_encryption_key(struct ksmbd_work *work, __u64 ses_id,
 
        ses_enc_key = enc ? sess->smb3encryptionkey :
                sess->smb3decryptionkey;
+       if (enc)
+               ksmbd_user_session_get(sess);
        memcpy(key, ses_enc_key, SMB3_ENC_DEC_KEY_SIZE);
 
        return 0;
index df92d746e89cabf8a0d82f5d6ee495513582403e..71c6939dfbf13bdcd113b9c7bd155e86b1242172 100644 (file)
@@ -263,8 +263,10 @@ struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
 
        down_read(&conn->session_lock);
        sess = xa_load(&conn->sessions, id);
-       if (sess)
+       if (sess) {
                sess->last_active = jiffies;
+               ksmbd_user_session_get(sess);
+       }
        up_read(&conn->session_lock);
        return sess;
 }
@@ -275,6 +277,8 @@ struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)
 
        down_read(&sessions_table_lock);
        sess = __session_lookup(id);
+       if (sess)
+               ksmbd_user_session_get(sess);
        up_read(&sessions_table_lock);
 
        return sess;
index 930d7566b52efdd624051b1cf0a0cc06be0254ce..3ba95bd8edeb230dc259c0bffe1623d87491c718 100644 (file)
@@ -241,14 +241,14 @@ send:
        if (work->tcon)
                ksmbd_tree_connect_put(work->tcon);
        smb3_preauth_hash_rsp(work);
-       if (work->sess)
-               ksmbd_user_session_put(work->sess);
        if (work->sess && work->sess->enc && work->encrypted &&
            conn->ops->encrypt_resp) {
                rc = conn->ops->encrypt_resp(work);
                if (rc < 0)
                        conn->ops->set_rsp_status(work, STATUS_DATA_ERROR);
        }
+       if (work->sess)
+               ksmbd_user_session_put(work->sess);
 
        ksmbd_conn_write(work);
 }
index 558ebb2ba0fd2bc0b8f93b065ae568a2972c1e37..5a70df87074cd4b8d42d9721bb8f8b3022638aef 100644 (file)
@@ -67,8 +67,10 @@ static inline bool check_session_id(struct ksmbd_conn *conn, u64 id)
                return false;
 
        sess = ksmbd_session_lookup_all(conn, id);
-       if (sess)
+       if (sess) {
+               ksmbd_user_session_put(sess);
                return true;
+       }
        pr_err("Invalid user session id: %llu\n", id);
        return false;
 }
@@ -605,10 +607,8 @@ int smb2_check_user_session(struct ksmbd_work *work)
 
        /* Check for validity of user session */
        work->sess = ksmbd_session_lookup_all(conn, sess_id);
-       if (work->sess) {
-               ksmbd_user_session_get(work->sess);
+       if (work->sess)
                return 1;
-       }
        ksmbd_debug(SMB, "Invalid user session, Uid %llu\n", sess_id);
        return -ENOENT;
 }
@@ -1701,29 +1701,35 @@ 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;
@@ -1731,7 +1737,8 @@ int smb2_sess_setup(struct ksmbd_work *work)
                        goto out_err;
                }
 
-               if (ksmbd_session_lookup(conn, sess_id)) {
+               sess = ksmbd_session_lookup(conn, sess_id);
+               if (!sess) {
                        rc = -EACCES;
                        goto out_err;
                }
@@ -1742,7 +1749,6 @@ int smb2_sess_setup(struct ksmbd_work *work)
                }
 
                conn->binding = true;
-               ksmbd_user_session_get(sess);
        } else if ((conn->dialect < SMB30_PROT_ID ||
                    server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) &&
                   (req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {
@@ -1769,7 +1775,6 @@ int smb2_sess_setup(struct ksmbd_work *work)
                }
 
                conn->binding = false;
-               ksmbd_user_session_get(sess);
        }
        work->sess = sess;
 
@@ -2197,9 +2202,9 @@ err_out:
 int smb2_session_logoff(struct ksmbd_work *work)
 {
        struct ksmbd_conn *conn = work->conn;
+       struct ksmbd_session *sess = work->sess;
        struct smb2_logoff_req *req;
        struct smb2_logoff_rsp *rsp;
-       struct ksmbd_session *sess;
        u64 sess_id;
        int err;
 
@@ -2221,11 +2226,6 @@ int smb2_session_logoff(struct ksmbd_work *work)
        ksmbd_close_session_fds(work);
        ksmbd_conn_wait_idle(conn);
 
-       /*
-        * Re-lookup session to validate if session is deleted
-        * while waiting request complete
-        */
-       sess = ksmbd_session_lookup_all(conn, sess_id);
        if (ksmbd_tree_conn_session_logoff(sess)) {
                ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId);
                rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
@@ -8992,6 +8992,7 @@ int smb3_decrypt_req(struct ksmbd_work *work)
                       le64_to_cpu(tr_hdr->SessionId));
                return -ECONNABORTED;
        }
+       ksmbd_user_session_put(sess);
 
        iov[0].iov_base = buf;
        iov[0].iov_len = sizeof(struct smb2_transform_hdr) + 4;