diff options
| author | Miklos Szeredi <mszeredi@redhat.com> | 2026-01-14 15:53:38 +0100 |
|---|---|---|
| committer | Christian Brauner <brauner@kernel.org> | 2026-01-16 19:15:14 +0100 |
| commit | cb8d2bdcb8241b66ca4ac4868f20e12cd6881ebc (patch) | |
| tree | 97daf2e5dbd891c4c3ea6d38a775077ca2f08bc3 | |
| parent | 4973d95679fb4f8bb4413dcb3bce435ef848285d (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.c | 11 |
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, }; |
