]> git.ipfire.org Git - thirdparty/kernel/stable.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)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 9 Jan 2025 12:28:41 +0000 (13:28 +0100)
[ Upstream commit b95629435b84b9ecc0c765995204a4d8a913ed52 ]

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

index 9a08e6a90b94d0df821b870b3c3358714c0b6a5b..3b776b5de7db6c43a656f6e96ee07371c3b4590a 100644 (file)
@@ -1010,6 +1010,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 844db95e66511c872dece9cdcc985cebf371e675..1cee9733bdac548db6a21afb24a0a85b6bce033c 100644 (file)
@@ -257,8 +257,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;
 }
@@ -269,6 +271,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 da5b9678ad05a01f21b4f3e70f3742082220900f..27d8d6c6fdacd90fe5b1e9099eabc01bef73587b 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 0f97830d1ebcbb19f274fc35311e36b4ffe54bc5..7f9297a5f3ef55e996248559821c1647edf53b97 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;
 }
@@ -606,10 +608,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;
 }
@@ -1722,29 +1722,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;
@@ -1752,7 +1758,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;
                }
@@ -1763,7 +1770,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)) {
@@ -1790,7 +1796,6 @@ int smb2_sess_setup(struct ksmbd_work *work)
                }
 
                conn->binding = false;
-               ksmbd_user_session_get(sess);
        }
        work->sess = sess;
 
@@ -2202,9 +2207,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;
 
@@ -2226,11 +2231,6 @@ int smb2_session_logoff(struct ksmbd_work *work)
        ksmbd_close_session_fds(work);
        ksmbd_conn_wait_idle(conn, sess_id);
 
-       /*
-        * 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;
@@ -8660,6 +8660,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;