[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.