summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2026-01-14 15:53:38 +0100
committerChristian Brauner <brauner@kernel.org>2026-01-16 19:15:14 +0100
commitcb8d2bdcb8241b66ca4ac4868f20e12cd6881ebc (patch)
tree97daf2e5dbd891c4c3ea6d38a775077ca2f08bc3
parent4973d95679fb4f8bb4413dcb3bce435ef848285d (diff)
fuse: fix race when disposing stale dentries
In fuse_dentry_tree_work() just before d_dispose_if_unused() the dentry could get evicted, resulting in UAF. Move unlocking dentry_hash[i].lock to after the dispose. To do this, fuse_dentry_tree_del_node() needs to be moved from fuse_dentry_prune() to fuse_dentry_release() to prevent an ABBA deadlock. The lock ordering becomes: -> dentry_bucket.lock -> dentry.d_lock Reported-by: Al Viro <viro@zeniv.linux.org.uk> Closes: https://lore.kernel.org/all/20251206014242.GO1712166@ZenIV/ Fixes: ab84ad597386 ("fuse: new work queue to periodically invalidate expired dentries") Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Link: https://patch.msgid.link/20260114145344.468856-2-mszeredi@redhat.com Signed-off-by: Christian Brauner <brauner@kernel.org>
-rw-r--r--fs/fuse/dir.c11
1 files changed, 2 insertions, 9 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index dbb55bad5476..ea90dd682bc3 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -172,8 +172,8 @@ static void fuse_dentry_tree_work(struct work_struct *work)
if (time_after64(get_jiffies_64(), fd->time)) {
rb_erase(&fd->node, &dentry_hash[i].tree);
RB_CLEAR_NODE(&fd->node);
- spin_unlock(&dentry_hash[i].lock);
d_dispose_if_unused(fd->dentry, &dispose);
+ spin_unlock(&dentry_hash[i].lock);
cond_resched();
spin_lock(&dentry_hash[i].lock);
} else
@@ -479,18 +479,12 @@ static int fuse_dentry_init(struct dentry *dentry)
return 0;
}
-static void fuse_dentry_prune(struct dentry *dentry)
+static void fuse_dentry_release(struct dentry *dentry)
{
struct fuse_dentry *fd = dentry->d_fsdata;
if (!RB_EMPTY_NODE(&fd->node))
fuse_dentry_tree_del_node(dentry);
-}
-
-static void fuse_dentry_release(struct dentry *dentry)
-{
- struct fuse_dentry *fd = dentry->d_fsdata;
-
kfree_rcu(fd, rcu);
}
@@ -527,7 +521,6 @@ const struct dentry_operations fuse_dentry_operations = {
.d_revalidate = fuse_dentry_revalidate,
.d_delete = fuse_dentry_delete,
.d_init = fuse_dentry_init,
- .d_prune = fuse_dentry_prune,
.d_release = fuse_dentry_release,
.d_automount = fuse_dentry_automount,
};