Blob Blame History Raw
From: Paulo Alcantara <palcantara@suse.de>
Date: Thu, 16 Mar 2023 16:03:13 -0300
Subject: [PATCH] cifs: fix open leaks in open_cached_dir()
Patch-mainline: Never, fixed upstream by unsupported feature (ebe98f1447bb)
References: bsc#1209342

When calling open_cached_dir(), we send a compounded
SMB2_CREATE+SMB2_QUERY_INFO request when we don't have a cached root
directory handle, but if a concurrent process was able to open and
cache it (e.g. tcon->crfid.is_valid was set after unblocking from
tcon->crfid.fid_mutex), we ended up

	(1) leaking open file handles as the fid assignment was done
	only after tcon->crfid.is_valid check

	(2) sending close requests to already-closed files due to
	uninitialised fid

Fix this by moving the fid assignment up and have it set prior to
checking for concurrent opens and close extra handle accordingly.

Signed-off-by: Paulo Alcantara <palcantara@suse.de>
Acked-by: Paulo Alcantara <palcantara@suse.de>
---
 fs/cifs/smb2ops.c | 40 ++++++++++++++++++----------------------
 1 file changed, 18 insertions(+), 22 deletions(-)

diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 90c063ff3095..016d15dab956 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -801,6 +801,22 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
 
 	rc = compound_send_recv(xid, ses, flags, 2, rqst,
 				resp_buftype, rsp_iov);
+	if (rc) {
+		if (rc == -EREMCHG) {
+			tcon->need_reconnect = true;
+			printk_once(KERN_WARNING "server share %s deleted\n",
+				    tcon->treeName);
+		}
+		goto oshr_free;
+	}
+
+	o_rsp = (struct smb2_create_rsp *)rsp_iov[0].iov_base;
+	oparms.fid->persistent_fid = o_rsp->PersistentFileId;
+	oparms.fid->volatile_fid = o_rsp->VolatileFileId;
+#ifdef CONFIG_CIFS_DEBUG2
+	oparms.fid->mid = le64_to_cpu(o_rsp->sync_hdr.MessageId);
+#endif /* CIFS_DEBUG2 */
+
 	mutex_lock(&tcon->crfid.fid_mutex);
 
 	/*
@@ -825,34 +841,14 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
 
 		mutex_unlock(&tcon->crfid.fid_mutex);
 
-		if (rc == 0) {
-			/* close extra handle outside of crit sec */
-			SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
-		}
-		rc = 0;
+		/* close extra handle outside of crit sec */
+		SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
 		goto oshr_free;
 	}
 
 	/* Cached root is still invalid, continue normaly */
-
-	if (rc) {
-		if (rc == -EREMCHG) {
-			tcon->need_reconnect = true;
-			printk_once(KERN_WARNING "server share %s deleted\n",
-				    tcon->treeName);
-		}
-		goto oshr_exit;
-	}
-
 	atomic_inc(&tcon->num_remote_opens);
 
-	o_rsp = (struct smb2_create_rsp *)rsp_iov[0].iov_base;
-	oparms.fid->persistent_fid = o_rsp->PersistentFileId;
-	oparms.fid->volatile_fid = o_rsp->VolatileFileId;
-#ifdef CONFIG_CIFS_DEBUG2
-	oparms.fid->mid = le64_to_cpu(o_rsp->sync_hdr.MessageId);
-#endif /* CIFS_DEBUG2 */
-
 	tcon->crfid.tcon = tcon;
 	tcon->crfid.is_valid = true;
 	tcon->crfid.dentry = dentry;
-- 
2.39.2