mirror of
https://github.com/torvalds/linux.git
synced 2026-10-07 19:16:02 +02:00
ksmbd: recognize replayed SMB2 lock sequences
A server returns success without processing a lock request when a valid LockSequenceArray entry contains the same sequence number. The current verifier only invalidates mismatched entries, so matching requests are submitted to the VFS again and recorded as duplicate locks. Make the verifier report matching sequences and skip lock processing for those replays. Also correct the field comment to describe the sequence and index bit layout used by the implementation and the protocol. Use the capabilities advertised by the server when deciding whether lock sequence verification applies to a multichannel connection. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
This commit is contained in:
parent
54d90311f9
commit
5ce5227cd6
|
|
@ -847,8 +847,8 @@ struct smb2_lock_req {
|
|||
__le16 StructureSize; /* Must be 48 */
|
||||
__le16 LockCount;
|
||||
/*
|
||||
* The least significant four bits are the index, the other 28 bits are
|
||||
* the lock sequence number (0 to 64). See MS-SMB2 2.2.26
|
||||
* The least significant four bits are the lock sequence number. The
|
||||
* other 28 bits are the index (0 to 64). See MS-SMB2 2.2.26.
|
||||
*/
|
||||
__le32 LockSequenceNumber;
|
||||
__u64 PersistentFileId;
|
||||
|
|
|
|||
|
|
@ -787,31 +787,38 @@ static bool smb2_lock_sequence_applicable(struct ksmbd_work *work,
|
|||
{
|
||||
return fp->is_resilient || fp->is_durable || fp->is_persistent ||
|
||||
(work->conn->dialect >= SMB30_PROT_ID &&
|
||||
(work->conn->cli_cap & SMB2_GLOBAL_CAP_MULTI_CHANNEL));
|
||||
(work->conn->vals->req_capabilities &
|
||||
SMB2_GLOBAL_CAP_MULTI_CHANNEL));
|
||||
}
|
||||
|
||||
static void smb2_verify_lock_sequence(struct ksmbd_work *work,
|
||||
struct ksmbd_file *fp,
|
||||
struct smb2_lock_req *req)
|
||||
static bool smb2_verify_lock_sequence(struct ksmbd_work *work,
|
||||
struct ksmbd_file *fp,
|
||||
struct smb2_lock_req *req)
|
||||
{
|
||||
u32 val, index;
|
||||
u8 sequence;
|
||||
bool replay = false;
|
||||
|
||||
if (work->conn->dialect == SMB20_PROT_ID ||
|
||||
!smb2_lock_sequence_applicable(work, fp))
|
||||
return;
|
||||
return false;
|
||||
|
||||
val = le32_to_cpu(req->LockSequenceNumber);
|
||||
sequence = val & 0xf;
|
||||
index = val >> 4;
|
||||
if (!index || index > KSMBD_LOCK_SEQ_ARRAY_SIZE)
|
||||
return;
|
||||
return false;
|
||||
|
||||
spin_lock(&fp->f_lock);
|
||||
if (fp->lock_seq[index - 1].valid &&
|
||||
fp->lock_seq[index - 1].sequence != sequence)
|
||||
fp->lock_seq[index - 1].valid = false;
|
||||
if (fp->lock_seq[index - 1].valid) {
|
||||
if (fp->lock_seq[index - 1].sequence == sequence)
|
||||
replay = true;
|
||||
else
|
||||
fp->lock_seq[index - 1].valid = false;
|
||||
}
|
||||
spin_unlock(&fp->f_lock);
|
||||
|
||||
return replay;
|
||||
}
|
||||
|
||||
static void smb2_update_lock_sequence(struct ksmbd_work *work,
|
||||
|
|
@ -9194,6 +9201,7 @@ int smb2_lock(struct ksmbd_work *work)
|
|||
LIST_HEAD(rollback_list);
|
||||
int prior_lock = 0, bkt;
|
||||
unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;
|
||||
bool lock_replayed;
|
||||
|
||||
WORK_BUFFERS(work, req, rsp);
|
||||
|
||||
|
|
@ -9226,7 +9234,9 @@ int smb2_lock(struct ksmbd_work *work)
|
|||
if (err)
|
||||
goto out2;
|
||||
|
||||
smb2_verify_lock_sequence(work, fp, req);
|
||||
lock_replayed = smb2_verify_lock_sequence(work, fp, req);
|
||||
if (lock_replayed)
|
||||
goto lock_success;
|
||||
|
||||
filp = fp->filp;
|
||||
lock_count = le16_to_cpu(req->LockCount);
|
||||
|
|
@ -9493,6 +9503,7 @@ int smb2_lock(struct ksmbd_work *work)
|
|||
if (atomic_read(&fp->f_ci->op_count) > 1)
|
||||
smb_break_all_oplock(work, fp);
|
||||
|
||||
lock_success:
|
||||
rsp->StructureSize = cpu_to_le16(4);
|
||||
ksmbd_debug(SMB, "successful in taking lock\n");
|
||||
rsp->hdr.Status = STATUS_SUCCESS;
|
||||
|
|
@ -9500,7 +9511,8 @@ int smb2_lock(struct ksmbd_work *work)
|
|||
err = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_lock_rsp));
|
||||
if (err)
|
||||
goto out;
|
||||
smb2_update_lock_sequence(work, fp, req);
|
||||
if (!lock_replayed)
|
||||
smb2_update_lock_sequence(work, fp, req);
|
||||
|
||||
ksmbd_fd_put(work, fp);
|
||||
return 0;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user