From: Joanne Koong <joannelkoong@gmail.com>
To: miklos@szeredi.hu, fuse-devel@lists.linux.dev
Subject: [PATCH v1 01/13] fuse: fix missing forget requests in error paths
Date: Thu, 23 Apr 2026 18:16:34 -0700 [thread overview]
Message-ID: <20260424011646.457682-2-joannelkoong@gmail.com> (raw)
In-Reply-To: <20260424011646.457682-1-joannelkoong@gmail.com>
If the server returned a valid nodeid but invalid attributes, the kernel
needs to send a forget request to tell the server to release its
reference, else this leads to server-side leaks. These paths only
trigger with a misbehaving server returning invalid attributes, so the
real-world impact is minimal, but forgets should be sent.
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
fs/fuse/dir.c | 52 ++++++++++++++++++++++++++++++---------------------
1 file changed, 31 insertions(+), 21 deletions(-)
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index be41c14ef329..6ab05d7d297d 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -583,7 +583,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name
err = -EIO;
if (fuse_invalid_attr(&outarg->attr))
- goto out_put_forget;
+ goto out_queue_forget;
if (outarg->nodeid == FUSE_ROOT_ID && outarg->generation != 0) {
pr_warn_once("root generation should be zero\n");
outarg->generation = 0;
@@ -593,16 +593,18 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name
&outarg->attr, ATTR_TIMEOUT(outarg),
attr_version, evict_ctr);
err = -ENOMEM;
- if (!*inode) {
- fuse_chan_queue_forget(fm->fc->chan, forget, outarg->nodeid, 1);
- goto out;
- }
+ if (!*inode)
+ goto out_queue_forget;
err = 0;
out_put_forget:
kfree(forget);
out:
return err;
+
+out_queue_forget:
+ fuse_chan_queue_forget(fm->fc->chan, forget, outarg->nodeid, 1);
+ return err;
}
static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
@@ -882,22 +884,21 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir,
goto out_free_ff;
err = -EIO;
- if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid) ||
- fuse_invalid_attr(&outentry.attr))
+ if (invalid_nodeid(outentry.nodeid))
goto out_free_ff;
ff->fh = outopenp->fh;
ff->nodeid = outentry.nodeid;
ff->open_flags = outopenp->open_flags;
+
+ if (!S_ISREG(outentry.attr.mode) || fuse_invalid_attr(&outentry.attr))
+ goto out_forget;
+
inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
&outentry.attr, ATTR_TIMEOUT(&outentry), 0, 0);
- if (!inode) {
- flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
- fuse_sync_release(NULL, ff, flags);
- fuse_chan_queue_forget(fm->fc->chan, forget, outentry.nodeid, 1);
- err = -ENOMEM;
- goto out_err;
- }
+ err = -ENOMEM;
+ if (!inode)
+ goto out_forget;
kfree(forget);
d_instantiate(entry, inode);
entry->d_time = epoch;
@@ -925,6 +926,11 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir,
kfree(forget);
out_err:
return err;
+out_forget:
+ flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
+ fuse_sync_release(NULL, ff, flags);
+ fuse_chan_queue_forget(fm->fc->chan, forget, outentry.nodeid, 1);
+ return err;
}
static int fuse_mknod(struct mnt_idmap *, struct inode *, struct dentry *,
@@ -1010,18 +1016,18 @@ static struct dentry *create_new_entry(struct mnt_idmap *idmap, struct fuse_moun
goto out_put_forget_req;
err = -EIO;
- if (invalid_nodeid(outarg.nodeid) || fuse_invalid_attr(&outarg.attr))
+ if (invalid_nodeid(outarg.nodeid))
goto out_put_forget_req;
- if ((outarg.attr.mode ^ mode) & S_IFMT)
- goto out_put_forget_req;
+ if (fuse_invalid_attr(&outarg.attr) || (outarg.attr.mode ^ mode) & S_IFMT)
+ goto out_forget;
inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
&outarg.attr, ATTR_TIMEOUT(&outarg), 0, 0);
- if (!inode) {
- fuse_chan_queue_forget(fm->fc->chan, forget, outarg.nodeid, 1);
- return ERR_PTR(-ENOMEM);
- }
+ err = -ENOMEM;
+ if (!inode)
+ goto out_forget;
+
kfree(forget);
d_drop(entry);
@@ -1044,6 +1050,10 @@ static struct dentry *create_new_entry(struct mnt_idmap *idmap, struct fuse_moun
fuse_invalidate_entry(entry);
kfree(forget);
return ERR_PTR(err);
+
+out_forget:
+ fuse_chan_queue_forget(fm->fc->chan, forget, outarg.nodeid, 1);
+ return ERR_PTR(err);
}
static int create_new_nondir(struct mnt_idmap *idmap, struct fuse_mount *fm,
--
2.52.0
next prev parent reply other threads:[~2026-04-24 1:17 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-24 1:16 [PATCH v1 00/13] fuse: dir.c cleanups Joanne Koong
2026-04-24 1:16 ` Joanne Koong [this message]
2026-04-24 8:18 ` [PATCH v1 01/13] fuse: fix missing forget requests in error paths Amir Goldstein
2026-04-24 17:43 ` Joanne Koong
2026-04-24 1:16 ` [PATCH v1 02/13] fuse: clean up fuse_lookup_name() Joanne Koong
2026-04-24 1:16 ` [PATCH v1 03/13] fuse: clean up fuse_lookup() Joanne Koong
2026-04-24 1:16 ` [PATCH v1 04/13] fuse: clean up fuse_dentry_revalidate() Joanne Koong
2026-04-24 8:20 ` Amir Goldstein
2026-04-24 1:16 ` [PATCH v1 05/13] fuse: clean up fuse_create_open() Joanne Koong
2026-04-24 1:16 ` [PATCH v1 06/13] fuse: clean up fuse_rename2() Joanne Koong
2026-04-24 1:16 ` [PATCH v1 07/13] fuse: clean up fuse_time_to_jiffies() Joanne Koong
2026-04-24 1:16 ` [PATCH v1 08/13] fuse: clean up fuse_link() Joanne Koong
2026-04-24 1:16 ` [PATCH v1 09/13] fuse: clean up fuse_do_getattr() Joanne Koong
2026-04-24 1:16 ` [PATCH v1 10/13] fuse: clean up fuse_update_get_attr() Joanne Koong
2026-04-24 1:16 ` [PATCH v1 11/13] fuse: clean up fuse_get_link() Joanne Koong
2026-04-24 1:16 ` [PATCH v1 12/13] fuse: clean up fuse_dir_open() Joanne Koong
2026-04-24 1:16 ` [PATCH v1 13/13] fuse: clean up setattr() Joanne Koong
2026-04-24 7:51 ` [PATCH v1 00/13] fuse: dir.c cleanups Amir Goldstein
2026-04-24 17:27 ` Joanne Koong
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=20260424011646.457682-2-joannelkoong@gmail.com \
--to=joannelkoong@gmail.com \
--cc=fuse-devel@lists.linux.dev \
--cc=miklos@szeredi.hu \
/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