diff options
| author | Gordon Ross <gwr@nexenta.com> | 2016-04-19 01:30:04 -0400 |
|---|---|---|
| committer | Gordon Ross <gwr@nexenta.com> | 2019-06-07 23:01:40 -0400 |
| commit | 6f58980a389cc62f07e5f2673629d9e9a209c2de (patch) | |
| tree | cb89c34f98b3dec1e68a5898fbf973d10bbf692e | |
| parent | 811599a462e8920d70cf548f4002182d3c222d13 (diff) | |
| download | illumos-joyent-6f58980a389cc62f07e5f2673629d9e9a209c2de.tar.gz | |
11012 SMB resilient handle lock replay
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Approved by: Garrett D'Amore <garrett@damore.org>
| -rw-r--r-- | usr/src/uts/common/fs/smbsrv/smb2_lock.c | 120 | ||||
| -rw-r--r-- | usr/src/uts/common/fs/smbsrv/smb_ofile.c | 1 | ||||
| -rw-r--r-- | usr/src/uts/common/smbsrv/smb_ktypes.h | 9 |
3 files changed, 128 insertions, 2 deletions
diff --git a/usr/src/uts/common/fs/smbsrv/smb2_lock.c b/usr/src/uts/common/fs/smbsrv/smb2_lock.c index 91f57dade9..dc888b9e8c 100644 --- a/usr/src/uts/common/fs/smbsrv/smb2_lock.c +++ b/usr/src/uts/common/fs/smbsrv/smb2_lock.c @@ -19,6 +19,12 @@ #include <smbsrv/smb2_kproto.h> +/* + * [MS-SMB2] 2.2.26 LockSequenceIndex, LockSequenceNumber. + */ +#define SMB2_LSN_SHIFT 4 +#define SMB2_LSN_MASK 0xf + typedef struct SMB2_LOCK_ELEMENT { uint64_t Offset; uint64_t Length; @@ -30,6 +36,9 @@ static uint32_t smb2_unlock(smb_request_t *); static uint32_t smb2_locks(smb_request_t *); static smb_sdrc_t smb2_lock_async(smb_request_t *); +static boolean_t smb2_lock_chk_lockseq(smb_ofile_t *, uint32_t); +static void smb2_lock_set_lockseq(smb_ofile_t *, uint32_t); + /* * This is a somewhat arbitrary sanity limit on the length of the * SMB2_LOCK_ELEMENT array. It usually has length one or two. @@ -79,6 +88,26 @@ smb2_lock(smb_request_t *sr) } /* + * Check the LockSequence to determine whether a previous + * lock request succeeded, but the client disconnected + * (retaining a durable or resilient handle). If so, this + * is a lock "replay". We'll find the lock sequence here + * and return success without processing the lock again. + */ + if (sr->session->dialect < SMB_VERS_2_1) + LockSequence = 0; + if ((sr->session->dialect == SMB_VERS_2_1) && + sr->fid_ofile->dh_vers != SMB2_RESILIENT) + LockSequence = 0; + /* dialect 3.0 or later can always use LockSequence */ + + if (LockSequence != 0 && + smb2_lock_chk_lockseq(sr->fid_ofile, LockSequence)) { + status = NT_STATUS_SUCCESS; + goto done; + } + + /* * Parse the array of SMB2_LOCK_ELEMENT structs. * This array is free'd in smb_srm_fini. */ @@ -127,6 +156,7 @@ errout: /* * Encode SMB2 Lock reply (sync) */ +done: (void) smb_mbc_encodef( &sr->reply, "w..", 4); /* StructSize w */ @@ -160,7 +190,9 @@ smb2_unlock(smb_request_t *sr) if (status != 0) break; } - (void) LockSequence; /* todo */ + if (status == 0 && LockSequence != 0) { + smb2_lock_set_lockseq(sr->fid_ofile, LockSequence); + } return (status); } @@ -174,6 +206,7 @@ smb2_locks(smb_request_t *sr) lock_elem_t *lk; lock_elem_t *lvec = sr->arg.lock.lvec; uint32_t LockCount = sr->arg.lock.lcnt; + uint32_t LockSequence = sr->arg.lock.lseq; uint32_t i; uint32_t ltype; uint32_t pid = 0; /* SMB2 ignores lock PIDs */ @@ -236,6 +269,8 @@ end_loop: lk->Offset, lk->Length, pid); } } + if (status == 0 && LockSequence != 0) + smb2_lock_set_lockseq(sr->fid_ofile, LockSequence); return (status); } @@ -249,6 +284,7 @@ smb2_lock_async(smb_request_t *sr) { lock_elem_t *lk = sr->arg.lock.lvec; uint32_t LockCount = sr->arg.lock.lcnt; + uint32_t LockSequence = sr->arg.lock.lseq; uint32_t status; uint32_t ltype; uint32_t pid = 0; /* SMB2 ignores lock PIDs */ @@ -284,6 +320,9 @@ errout: return (SDRC_SUCCESS); } + if (LockSequence != 0) + smb2_lock_set_lockseq(sr->fid_ofile, LockSequence); + /* * SMB2 Lock reply (async) */ @@ -293,3 +332,82 @@ errout: /* reserved .. */ return (SDRC_SUCCESS); } + +/* + * Check whether we've stored a given LockSequence + * + * [MS-SMB2] 3.3.5.14 + * + * The server verifies the LockSequence by performing the following steps: + * + * 1. The server MUST use LockSequenceIndex as an index into the + * Open.LockSequenceArray in order to locate the sequence number entry. + * If the index exceeds the maximum extent of the Open.LockSequenceArray, + * or LockSequenceIndex is 0, or if the sequence number entry is empty, + * the server MUST skip step 2 and continue lock/unlock processing. + * + * 2. The server MUST compare LockSequenceNumber to the SequenceNumber of + * the entry located in step 1. If the sequence numbers are equal, the + * server MUST complete the lock/unlock request with success. Otherwise, + * the server MUST reset the entry value to empty and continue lock/unlock + * processing. + */ +boolean_t +smb2_lock_chk_lockseq(smb_ofile_t *ofile, uint32_t lockseq) +{ + uint32_t lsi; + uint8_t lsn; + boolean_t rv; + + /* + * LockSequenceNumber is the low four bits. + * LockSequenceIndex is the remaining 28 bits. + * valid range is 1..64, which we convert to an + * array index in the range 0..63 + */ + lsn = lockseq & SMB2_LSN_MASK; + lsi = (lockseq >> SMB2_LSN_SHIFT); + if (lsi == 0 || lsi > SMB_OFILE_LSEQ_MAX) + return (B_FALSE); + --lsi; + + mutex_enter(&ofile->f_mutex); + + if (ofile->f_lock_seq[lsi] == lsn) { + rv = B_TRUE; + } else { + ofile->f_lock_seq[lsi] = (uint8_t)-1; /* "Empty" */ + rv = B_FALSE; + } + + mutex_exit(&ofile->f_mutex); + + return (rv); +} + +static void +smb2_lock_set_lockseq(smb_ofile_t *ofile, uint32_t lockseq) +{ + uint32_t lsi; + uint8_t lsn; + + /* + * LockSequenceNumber is the low four bits. + * LockSequenceIndex is the remaining 28 bits. + * valid range is 1..64, which we convert to an + * array index in the range 0..63 + */ + lsn = lockseq & SMB2_LSN_MASK; + lsi = (lockseq >> SMB2_LSN_SHIFT); + if (lsi == 0 || lsi > SMB_OFILE_LSEQ_MAX) { + cmn_err(CE_NOTE, "smb2_lock_set_lockseq, index=%u", lsi); + return; + } + --lsi; + + mutex_enter(&ofile->f_mutex); + + ofile->f_lock_seq[lsi] = lsn; + + mutex_exit(&ofile->f_mutex); +} diff --git a/usr/src/uts/common/fs/smbsrv/smb_ofile.c b/usr/src/uts/common/fs/smbsrv/smb_ofile.c index e7b07732d1..9521d6f277 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_ofile.c +++ b/usr/src/uts/common/fs/smbsrv/smb_ofile.c @@ -342,6 +342,7 @@ smb_ofile_open( crhold(of->f_cr); of->f_server = tree->t_server; of->f_session = tree->t_session; + (void) memset(of->f_lock_seq, -1, SMB_OFILE_LSEQ_MAX); /* * grab a ref for of->f_user and of->f_tree diff --git a/usr/src/uts/common/smbsrv/smb_ktypes.h b/usr/src/uts/common/smbsrv/smb_ktypes.h index 2bf62f6242..edafb04ddc 100644 --- a/usr/src/uts/common/smbsrv/smb_ktypes.h +++ b/usr/src/uts/common/smbsrv/smb_ktypes.h @@ -1325,6 +1325,12 @@ typedef struct smb_opipe { #define SMB_OFILE_VALID(p) \ ASSERT((p != NULL) && ((p)->f_magic == SMB_OFILE_MAGIC)) +/* + * This is the size of the per-handle "Lock Sequence" array. + * See LockSequenceIndex in [MS-SMB2] 2.2.26, and smb2_lock.c + */ +#define SMB_OFILE_LSEQ_MAX 64 + /* {arg_open,ofile}->dh_vers values */ typedef enum { SMB2_NOT_DURABLE = 0, @@ -1387,7 +1393,6 @@ typedef struct smb_ofile { pid_t f_pid; smb_attr_t f_pending_attr; boolean_t f_written; - char f_quota_resume[SMB_SID_STRSZ]; smb_oplock_grant_t f_oplock_grant; smb_notify_t f_notify; @@ -1396,6 +1401,8 @@ typedef struct smb_ofile { hrtime_t dh_expire_time; /* time the handle expires */ boolean_t dh_persist; uint8_t dh_create_guid[16]; + char f_quota_resume[SMB_SID_STRSZ]; + uint8_t f_lock_seq[SMB_OFILE_LSEQ_MAX]; } smb_ofile_t; typedef struct smb_fileinfo { |
