ksmbd: fix racy issue from session lookup and expire

commit b95629435b84b9ecc0c765995204a4d8a913ed52 upstream.

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: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Namjae Jeon 2024-12-05 21:38:47 +09:00 committed by Greg Kroah-Hartman
parent 9245459a99
commit 37a0e2b362
4 changed files with 23 additions and 16 deletions

View File

@ -1010,6 +1010,8 @@ static int ksmbd_get_encryption_key(struct ksmbd_work *work, __u64 ses_id,
ses_enc_key = enc ? sess->smb3encryptionkey : ses_enc_key = enc ? sess->smb3encryptionkey :
sess->smb3decryptionkey; sess->smb3decryptionkey;
if (enc)
ksmbd_user_session_get(sess);
memcpy(key, ses_enc_key, SMB3_ENC_DEC_KEY_SIZE); memcpy(key, ses_enc_key, SMB3_ENC_DEC_KEY_SIZE);
return 0; return 0;

View File

@ -262,8 +262,10 @@ struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
down_read(&conn->session_lock); down_read(&conn->session_lock);
sess = xa_load(&conn->sessions, id); sess = xa_load(&conn->sessions, id);
if (sess) if (sess) {
sess->last_active = jiffies; sess->last_active = jiffies;
ksmbd_user_session_get(sess);
}
up_read(&conn->session_lock); up_read(&conn->session_lock);
return sess; return sess;
} }
@ -274,6 +276,8 @@ struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)
down_read(&sessions_table_lock); down_read(&sessions_table_lock);
sess = __session_lookup(id); sess = __session_lookup(id);
if (sess)
ksmbd_user_session_get(sess);
up_read(&sessions_table_lock); up_read(&sessions_table_lock);
return sess; return sess;

View File

@ -241,14 +241,14 @@ send:
if (work->tcon) if (work->tcon)
ksmbd_tree_connect_put(work->tcon); ksmbd_tree_connect_put(work->tcon);
smb3_preauth_hash_rsp(work); smb3_preauth_hash_rsp(work);
if (work->sess)
ksmbd_user_session_put(work->sess);
if (work->sess && work->sess->enc && work->encrypted && if (work->sess && work->sess->enc && work->encrypted &&
conn->ops->encrypt_resp) { conn->ops->encrypt_resp) {
rc = conn->ops->encrypt_resp(work); rc = conn->ops->encrypt_resp(work);
if (rc < 0) if (rc < 0)
conn->ops->set_rsp_status(work, STATUS_DATA_ERROR); conn->ops->set_rsp_status(work, STATUS_DATA_ERROR);
} }
if (work->sess)
ksmbd_user_session_put(work->sess);
ksmbd_conn_write(work); ksmbd_conn_write(work);
} }

View File

@ -66,8 +66,10 @@ static inline bool check_session_id(struct ksmbd_conn *conn, u64 id)
return false; return false;
sess = ksmbd_session_lookup_all(conn, id); sess = ksmbd_session_lookup_all(conn, id);
if (sess) if (sess) {
ksmbd_user_session_put(sess);
return true; return true;
}
pr_err("Invalid user session id: %llu\n", id); pr_err("Invalid user session id: %llu\n", id);
return false; return false;
} }
@ -604,10 +606,8 @@ int smb2_check_user_session(struct ksmbd_work *work)
/* Check for validity of user session */ /* Check for validity of user session */
work->sess = ksmbd_session_lookup_all(conn, sess_id); work->sess = ksmbd_session_lookup_all(conn, sess_id);
if (work->sess) { if (work->sess)
ksmbd_user_session_get(work->sess);
return 1; return 1;
}
ksmbd_debug(SMB, "Invalid user session, Uid %llu\n", sess_id); ksmbd_debug(SMB, "Invalid user session, Uid %llu\n", sess_id);
return -ENOENT; return -ENOENT;
} }
@ -1720,29 +1720,35 @@ int smb2_sess_setup(struct ksmbd_work *work)
if (conn->dialect != sess->dialect) { if (conn->dialect != sess->dialect) {
rc = -EINVAL; rc = -EINVAL;
ksmbd_user_session_put(sess);
goto out_err; goto out_err;
} }
if (!(req->hdr.Flags & SMB2_FLAGS_SIGNED)) { if (!(req->hdr.Flags & SMB2_FLAGS_SIGNED)) {
rc = -EINVAL; rc = -EINVAL;
ksmbd_user_session_put(sess);
goto out_err; goto out_err;
} }
if (strncmp(conn->ClientGUID, sess->ClientGUID, if (strncmp(conn->ClientGUID, sess->ClientGUID,
SMB2_CLIENT_GUID_SIZE)) { SMB2_CLIENT_GUID_SIZE)) {
rc = -ENOENT; rc = -ENOENT;
ksmbd_user_session_put(sess);
goto out_err; goto out_err;
} }
if (sess->state == SMB2_SESSION_IN_PROGRESS) { if (sess->state == SMB2_SESSION_IN_PROGRESS) {
rc = -EACCES; rc = -EACCES;
ksmbd_user_session_put(sess);
goto out_err; goto out_err;
} }
if (sess->state == SMB2_SESSION_EXPIRED) { if (sess->state == SMB2_SESSION_EXPIRED) {
rc = -EFAULT; rc = -EFAULT;
ksmbd_user_session_put(sess);
goto out_err; goto out_err;
} }
ksmbd_user_session_put(sess);
if (ksmbd_conn_need_reconnect(conn)) { if (ksmbd_conn_need_reconnect(conn)) {
rc = -EFAULT; rc = -EFAULT;
@ -1750,7 +1756,8 @@ int smb2_sess_setup(struct ksmbd_work *work)
goto out_err; goto out_err;
} }
if (ksmbd_session_lookup(conn, sess_id)) { sess = ksmbd_session_lookup(conn, sess_id);
if (!sess) {
rc = -EACCES; rc = -EACCES;
goto out_err; goto out_err;
} }
@ -1761,7 +1768,6 @@ int smb2_sess_setup(struct ksmbd_work *work)
} }
conn->binding = true; conn->binding = true;
ksmbd_user_session_get(sess);
} else if ((conn->dialect < SMB30_PROT_ID || } else if ((conn->dialect < SMB30_PROT_ID ||
server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) && server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) &&
(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) { (req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {
@ -1788,7 +1794,6 @@ int smb2_sess_setup(struct ksmbd_work *work)
} }
conn->binding = false; conn->binding = false;
ksmbd_user_session_get(sess);
} }
work->sess = sess; work->sess = sess;
@ -2207,9 +2212,9 @@ err_out:
int smb2_session_logoff(struct ksmbd_work *work) int smb2_session_logoff(struct ksmbd_work *work)
{ {
struct ksmbd_conn *conn = work->conn; struct ksmbd_conn *conn = work->conn;
struct ksmbd_session *sess = work->sess;
struct smb2_logoff_req *req; struct smb2_logoff_req *req;
struct smb2_logoff_rsp *rsp; struct smb2_logoff_rsp *rsp;
struct ksmbd_session *sess;
u64 sess_id; u64 sess_id;
int err; int err;
@ -2231,11 +2236,6 @@ int smb2_session_logoff(struct ksmbd_work *work)
ksmbd_close_session_fds(work); ksmbd_close_session_fds(work);
ksmbd_conn_wait_idle(conn, sess_id); 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)) { if (ksmbd_tree_conn_session_logoff(sess)) {
ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId);
rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
@ -8682,6 +8682,7 @@ int smb3_decrypt_req(struct ksmbd_work *work)
le64_to_cpu(tr_hdr->SessionId)); le64_to_cpu(tr_hdr->SessionId));
return -ECONNABORTED; return -ECONNABORTED;
} }
ksmbd_user_session_put(sess);
iov[0].iov_base = buf; iov[0].iov_base = buf;
iov[0].iov_len = sizeof(struct smb2_transform_hdr) + 4; iov[0].iov_len = sizeof(struct smb2_transform_hdr) + 4;