[PATCH] smb: client: reject lease breaks with reserved NewLeaseState bits set
Frank Sorenson <[email protected]>
| Newsgroups | org.kernel.vger.linux-cifs |
|---|---|
| Message-ID | <[email protected]> |
smb2_tcon_has_lease() and smb2_tcon_find_pending_open_lease() assign the
server-supplied __le32 NewLeaseState field directly to a __u8 local
variable, silently dropping bits 8-31. Valid SMB2 lease-state values use
only the lower three bits (READ_CACHING=0x01, HANDLE_CACHING=0x02,
WRITE_CACHING=0x04); a server that sets reserved upper bits would have
those bits silently discarded, causing the client to record an incorrect
lease state and potentially miss cache invalidations.
Decode NewLeaseState to a u32 first and reject the response if any
reserved bits are set before narrowing to __u8.
Fixes: ab14cb0cae99 ("CIFS: Fix missing lease break")
Signed-off-by: Frank Sorenson <[email protected]>
---
fs/smb/client/smb2misc.c | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c
index 9068175e57cd..1e1d915c4377 100644
--- a/fs/smb/client/smb2misc.c
+++ b/fs/smb/client/smb2misc.c
@@ -570,12 +570,20 @@ static bool
smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp)
{
__u8 lease_state;
+ u32 ls;
struct cifsFileInfo *cfile;
struct cifsInodeInfo *cinode;
int ack_req = le32_to_cpu(rsp->Flags &
SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED);
- lease_state = le32_to_cpu(rsp->NewLeaseState);
+ ls = le32_to_cpu(rsp->NewLeaseState);
+ if (ls & ~(SMB2_LEASE_READ_CACHING_HE | SMB2_LEASE_HANDLE_CACHING_HE |
+ SMB2_LEASE_WRITE_CACHING_HE)) {
+ cifs_dbg(VFS | ONCE, "%s: invalid NewLeaseState 0x%x\n",
+ __func__, ls);
+ return false;
+ }
+ lease_state = (__u8)ls;
list_for_each_entry(cfile, &tcon->openFileList, tlist) {
cinode = CIFS_I(d_inode(cfile->dentry));
@@ -609,11 +617,20 @@ static struct cifs_pending_open *
smb2_tcon_find_pending_open_lease(struct cifs_tcon *tcon,
struct smb2_lease_break *rsp)
{
- __u8 lease_state = le32_to_cpu(rsp->NewLeaseState);
+ u32 ls = le32_to_cpu(rsp->NewLeaseState);
int ack_req = le32_to_cpu(rsp->Flags &
SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED);
struct cifs_pending_open *open;
struct cifs_pending_open *found = NULL;
+ __u8 lease_state;
+
+ if (ls & ~(SMB2_LEASE_READ_CACHING_HE | SMB2_LEASE_HANDLE_CACHING_HE |
+ SMB2_LEASE_WRITE_CACHING_HE)) {
+ cifs_dbg(VFS | ONCE, "%s: invalid NewLeaseState 0x%x\n",
+ __func__, ls);
+ return NULL;
+ }
+ lease_state = (__u8)ls;
list_for_each_entry(open, &tcon->pending_opens, olist) {
if (memcmp(open->lease_key, rsp->LeaseKey,
--
2.55.0