mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 10:31:33 -04:00
Merge tag 'v7.2-rc5-smb3-server-fixes' of git://git.samba.org/ksmbd
Pull smb server fixes from Steve French: - Use memcmp() when comparing fixed-size binary ClientGUIDs, so embedded NUL bytes are handled correctly - Reject repeated SMB2 NEGOTIATE requests after dialect selection This prevents preauth_info leaks, enforces the SMB2 protocol requirements, and serializes negotiation state updates. - Fix a use-after-free in __close_file_table_ids() by removing the volatile file ID from the owning IDR before dropping the IDR reference * tag 'v7.2-rc5-smb3-server-fixes' of git://git.samba.org/ksmbd: ksmbd: use memcmp() to compare ClientGUIDs ksmbd: reject repeated SMB2 NEGOTIATE requests ksmbd: fix use-after-free in __close_file_table_ids()
This commit is contained in:
@@ -200,6 +200,11 @@ void ksmbd_conn_r_count_dec(struct ksmbd_conn *conn);
|
||||
* This is a hack. We will move status to a proper place once we land
|
||||
* a multi-sessions support.
|
||||
*/
|
||||
static inline bool ksmbd_conn_new(struct ksmbd_conn *conn)
|
||||
{
|
||||
return READ_ONCE(conn->status) == KSMBD_SESS_NEW;
|
||||
}
|
||||
|
||||
static inline bool ksmbd_conn_good(struct ksmbd_conn *conn)
|
||||
{
|
||||
return READ_ONCE(conn->status) == KSMBD_SESS_GOOD;
|
||||
|
||||
@@ -1325,6 +1325,8 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
|
||||
* smb2_handle_negotiate() - handler for smb2 negotiate command
|
||||
* @work: smb work containing smb request buffer
|
||||
*
|
||||
* The caller holds conn->srv_mutex.
|
||||
*
|
||||
* Return: 0
|
||||
*/
|
||||
int smb2_handle_negotiate(struct ksmbd_work *work)
|
||||
@@ -1338,13 +1340,6 @@ int smb2_handle_negotiate(struct ksmbd_work *work)
|
||||
|
||||
ksmbd_debug(SMB, "Received negotiate request\n");
|
||||
conn->need_neg = false;
|
||||
if (ksmbd_conn_good(conn)) {
|
||||
pr_err("conn->tcp_status is already in CifsGood State\n");
|
||||
work->send_no_response = 1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
ksmbd_conn_lock(conn);
|
||||
smb2_buf_len = get_rfc1002_len(work->request_buf);
|
||||
smb2_neg_size = offsetof(struct smb2_negotiate_req, Dialects);
|
||||
if (smb2_neg_size > smb2_buf_len) {
|
||||
@@ -1495,7 +1490,6 @@ int smb2_handle_negotiate(struct ksmbd_work *work)
|
||||
ksmbd_conn_set_need_setup(conn);
|
||||
|
||||
err_out:
|
||||
ksmbd_conn_unlock(conn);
|
||||
if (rc)
|
||||
rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
@@ -1975,7 +1969,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (strncmp(conn->ClientGUID, sess->ClientGUID,
|
||||
if (memcmp(conn->ClientGUID, sess->ClientGUID,
|
||||
SMB2_CLIENT_GUID_SIZE)) {
|
||||
rc = -ENOENT;
|
||||
goto out_err;
|
||||
@@ -8696,7 +8690,7 @@ static int fsctl_validate_negotiate_info(struct ksmbd_conn *conn,
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (strncmp(neg_req->Guid, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE)) {
|
||||
if (memcmp(neg_req->Guid, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE)) {
|
||||
ret = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
@@ -608,23 +608,46 @@ int ksmbd_smb_negotiate_common(struct ksmbd_work *work, unsigned int command)
|
||||
struct ksmbd_conn *conn = work->conn;
|
||||
int ret;
|
||||
|
||||
conn->dialect =
|
||||
ksmbd_negotiate_smb_dialect(work->request_buf);
|
||||
ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect);
|
||||
|
||||
if (command == SMB2_NEGOTIATE_HE) {
|
||||
/*
|
||||
* An SMB2 NEGOTIATE is valid for a new connection, or after an
|
||||
* SMB1 multi-protocol negotiate has selected SMB2. Do not allow
|
||||
* a second SMB2 NEGOTIATE to replace connection-wide state
|
||||
* while a session setup is pending. KSMBD_SESS_NEED_RECONNECT
|
||||
* is a transient session state and does not restart transport
|
||||
* negotiation.
|
||||
*/
|
||||
ksmbd_conn_lock(conn);
|
||||
if (!ksmbd_conn_new(conn) &&
|
||||
!ksmbd_conn_need_negotiate(conn)) {
|
||||
work->send_no_response = 1;
|
||||
ksmbd_conn_set_exiting(conn);
|
||||
ksmbd_conn_unlock(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
conn->dialect =
|
||||
ksmbd_negotiate_smb_dialect(work->request_buf);
|
||||
ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect);
|
||||
ret = smb2_handle_negotiate(work);
|
||||
ksmbd_conn_unlock(conn);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (command == SMB_COM_NEGOTIATE) {
|
||||
ksmbd_conn_lock(conn);
|
||||
conn->dialect =
|
||||
ksmbd_negotiate_smb_dialect(work->request_buf);
|
||||
ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect);
|
||||
if (__smb2_negotiate(conn)) {
|
||||
init_smb3_11_server(conn);
|
||||
init_smb2_neg_rsp(work);
|
||||
ret = init_smb2_neg_rsp(work);
|
||||
ksmbd_debug(SMB, "Upgrade to SMB2 negotiation\n");
|
||||
return 0;
|
||||
} else {
|
||||
ret = smb_handle_negotiate(work);
|
||||
}
|
||||
return smb_handle_negotiate(work);
|
||||
ksmbd_conn_unlock(conn);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pr_err("Unknown SMB negotiation command: %u\n", command);
|
||||
|
||||
@@ -697,6 +697,8 @@ int ksmbd_close_fd(struct ksmbd_work *work, u64 id)
|
||||
fp = NULL;
|
||||
else {
|
||||
fp->f_state = FP_CLOSED;
|
||||
idr_remove(ft->idr, id);
|
||||
fp->volatile_id = KSMBD_NO_FID;
|
||||
closed = true;
|
||||
if (!atomic_dec_and_test(&fp->refcount))
|
||||
fp = NULL;
|
||||
|
||||
Reference in New Issue
Block a user