[PATCH v6 06/15] VFS: introduce start_creating_noperm() and start_removing_noperm()
Val Packett
val at packett.cool
Sun Nov 30 00:01:05 UTC 2025
Hi,
On 11/12/25 9:18 PM, NeilBrown wrote:
> From: NeilBrown <neil at brown.name>
>
> xfs, fuse, ipc/mqueue need variants of start_creating or start_removing
> which do not check permissions.
> This patch adds _noperm versions of these functions.
> [..]
> diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
> index 316922d5dd13..a0d5b302bcc2 100644
> --- a/fs/fuse/dir.c
> +++ b/fs/fuse/dir.c
> @@ -1397,27 +1397,25 @@ int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid,
> if (!parent)
> return -ENOENT;
>
> - inode_lock_nested(parent, I_MUTEX_PARENT);
> if (!S_ISDIR(parent->i_mode))
> - goto unlock;
> + goto put_parent;
>
> err = -ENOENT;
> dir = d_find_alias(parent);
> if (!dir)
> - goto unlock;
> + goto put_parent;
>
> - name->hash = full_name_hash(dir, name->name, name->len);
> - entry = d_lookup(dir, name);
> + entry = start_removing_noperm(dir, name);
> dput(dir);
> - if (!entry)
> - goto unlock;
> + if (IS_ERR(entry))
> + goto put_parent;
This broke xdg-document-portal (and potentially other FUSE filesystems)
by introducing a massive deadlock.
❯ doas cat /proc/40751/stack # main thread
[<0>] __fuse_simple_request+0x37c/0x5c0 [fuse]
[<0>] fuse_lookup_name+0x12c/0x2a0 [fuse]
[<0>] fuse_lookup+0x9c/0x1e8 [fuse]
[<0>] lookup_one_qstr_excl+0xd4/0x160
[<0>] start_removing_noperm+0x5c/0x90
[<0>] fuse_reverse_inval_entry+0x64/0x1e0 [fuse]
[<0>] fuse_dev_do_write+0x13a8/0x16a8 [fuse]
[<0>] fuse_dev_write+0x64/0xa8 [fuse]
[<0>] do_iter_readv_writev+0x170/0x1d0
[<0>] vfs_writev+0x100/0x2d0
[<0>] do_writev+0x88/0x130
d_lookup which was previously used here —from what I could understand by
reading it— is cache-only and does not call into the FS's lookup at all.
This new start_removing_noperm calls start_dirop which calls
lookup_one_qstr_excl which according to its own comment is the "one and
only case when ->lookup() gets called on non in-lookup dentries". Well,
->lookup() is the request back to the userspace FUSE server.. but the
FUSE server is waiting for the write() to the FUSE device that invokes
this operation to return! We cannot reenter the FUSE server
from fuse_reverse_inval_entry.
x-d-p issue link: https://github.com/flatpak/xdg-desktop-portal/issues/1871
Reverting the fuse/dir.c changes has fixed that for me.
Thanks,
~val
More information about the Linux-security-module-archive
mailing list