From: Sasha Levin <sashal@kernel.org>
To: stable@vger.kernel.org
Cc: Namjae Jeon <linkinjeon@kernel.org>,
Paulo Alcantara <pc@manguebit.org>,
Sasha Levin <sashal@kernel.org>
Subject: [PATCH 6.1.y] smb: client: use finish_no_open() for non-regular inodes
Date: Wed, 30 Sep 2026 12:34:15 -0400 [thread overview]
Message-ID: <20260930163415.3202882-1-sashal@kernel.org> (raw)
In-Reply-To: <2026092923-stuffed-sift-28b2@gregkh>
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit e66cf1625ec4a3fe68346119f371def713fd0a4d ]
An O_CREAT open can find an existing symlink or another non-regular
inode. cifs_atomic_open() calls finish_open() on it and attaches a
cifsFileInfo. Symlink inodes have no CIFS release operation, so the
dentry reference held by cifsFileInfo is leaked. FMODE_OPENED also
prevents the VFS from following the symlink.
Track whether cifs_do_create() returned an open server handle. For
non-regular inodes, close the handle if present, remove the pending
open, and call finish_no_open() so the VFS can continue the lookup.
Do not set FMODE_CREATED unless a regular file was opened. For
O_NOFOLLOW with __O_REGULAR, return -ELOOP before the VFS's
-EFTYPE check.
Defer closing a legacy POSIX handle on a non-regular inode until
after inode lookup. This avoids closing it again if lookup fails.
Fixes: d2c127197dfc ("cifs: implement i_op->atomic_open()")
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Paulo Alcantara <pc@manguebit.org>
Cc: stable@vger.kernel.org
[ replaced S_ISREG(inode->i_mode) with d_is_reg(direntry) because the older cifs_do_create() already attaches the inode. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/client/dir.c | 39 +++++++++++++++++++++++++++++----------
1 file changed, 29 insertions(+), 10 deletions(-)
diff --git a/fs/smb/client/dir.c b/fs/smb/client/dir.c
index b5b64b061b715..d34230b8e1246 100644
--- a/fs/smb/client/dir.c
+++ b/fs/smb/client/dir.c
@@ -176,7 +176,8 @@ check_name(struct dentry *direntry, struct cifs_tcon *tcon)
static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
struct tcon_link *tlink, unsigned int oflags, umode_t mode, __u32 *oplock,
- struct cifs_fid *fid, struct cifs_open_info_data *buf)
+ struct cifs_fid *fid, struct cifs_open_info_data *buf,
+ bool *opened)
{
int rc = -ENOENT;
int create_options = CREATE_NOT_DIR;
@@ -191,6 +192,7 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned
struct cifs_open_parms oparms;
int rdwr_for_fscache = 0;
+ *opened = false;
*oplock = 0;
if (tcon->ses->server->oplocks)
*oplock = REQ_OPLOCK;
@@ -213,6 +215,7 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned
oflags, oplock, &fid->netfid, xid);
switch (rc) {
case 0:
+ *opened = true;
if (newinode == NULL) {
/* query inode info */
goto cifs_create_get_file_info;
@@ -229,11 +232,9 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned
/*
* The server may allow us to open things like
* FIFOs, but the client isn't set up to deal
- * with that. If it's not a regular file, just
- * close it and proceed as if it were a normal
- * lookup.
+ * with that. Keep the handle until the caller
+ * can finish the lookup.
*/
- CIFSSMBClose(xid, tcon, fid->netfid);
goto cifs_create_get_file_info;
}
/* success, no need to query */
@@ -333,6 +334,7 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned
}
goto out;
}
+ *opened = true;
if (rdwr_for_fscache == 2)
cifs_invalidate_cache(inode, FSCACHE_INVAL_DIO_WRITE);
@@ -423,7 +425,7 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned
return rc;
out_err:
- if (server->ops->close)
+ if (*opened && server->ops->close)
server->ops->close(xid, tcon, fid);
if (newinode)
iput(newinode);
@@ -442,6 +444,8 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
struct cifs_fid fid = {};
struct cifs_pending_open open;
__u32 oplock;
+ bool is_regular;
+ bool opened;
struct cifsFileInfo *file_info;
struct cifs_open_info_data buf = {};
@@ -501,15 +505,28 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
cifs_add_pending_open(&fid, tlink, &open);
rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
- &oplock, &fid, &buf);
+ &oplock, &fid, &buf, &opened);
if (rc) {
cifs_del_pending_open(&open);
goto out;
}
- if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+ is_regular = d_is_reg(direntry);
+ if (!is_regular || !opened) {
+ if (opened && server->ops->close)
+ server->ops->close(xid, tcon, &fid);
+ cifs_del_pending_open(&open);
+ }
+
+ if (is_regular && opened &&
+ (oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
file->f_mode |= FMODE_CREATED;
+ if (!is_regular || !opened) {
+ rc = finish_no_open(file, NULL);
+ goto out;
+ }
+
rc = finish_open(file, direntry, generic_file_open);
if (rc) {
if (server->ops->close)
@@ -564,6 +581,7 @@ int cifs_create(struct user_namespace *mnt_userns, struct inode *inode,
struct TCP_Server_Info *server;
struct cifs_fid fid;
__u32 oplock;
+ bool opened;
struct cifs_open_info_data buf = {};
cifs_dbg(FYI, "cifs_create parent inode = 0x%p name is: %pd and dentry = 0x%p\n",
@@ -585,8 +603,9 @@ int cifs_create(struct user_namespace *mnt_userns, struct inode *inode,
if (server->ops->new_lease_key)
server->ops->new_lease_key(&fid);
- rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, &oplock, &fid, &buf);
- if (!rc && server->ops->close)
+ rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
+ &oplock, &fid, &buf, &opened);
+ if (!rc && opened && server->ops->close)
server->ops->close(xid, tcon, &fid);
cifs_free_open_info(&buf);
--
2.53.0
prev parent reply other threads:[~2026-09-30 16:34 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-29 11:51 FAILED: patch "[PATCH] smb: client: use finish_no_open() for non-regular inodes" failed to apply to 6.1-stable tree gregkh
2026-09-30 16:34 ` Sasha Levin [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260930163415.3202882-1-sashal@kernel.org \
--to=sashal@kernel.org \
--cc=linkinjeon@kernel.org \
--cc=pc@manguebit.org \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox