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:
Linus Torvalds
2026-07-31 17:35:17 -07:00
4 changed files with 41 additions and 17 deletions

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;