6.18-stable review patch. If anyone has any objections, please let me know. ------------------ From: Christian Brauner commit b138e16fb1e81376cea89f727dda7bfccd140de4 upstream. d_alloc_pseudo() hands out dentries for pipes, sockets and other files that are never anyone's child or parent. They carry DCACHE_NORCU and dentry_free() frees them right away because no lockless path walk can ever reach them. That holds as long as such a dentry isn't the root of a mount. But bind mounting /proc/self/fd/ of such a file does exactly that. Most callers of alloc_file_pseudo() put their files on kernel-internal mounts and may_copy_tree() refuses those. bpf_token_create() doesn't. It places the token file on the bpffs mount the caller handed it and that mount is in the caller's mount namespace so the clone goes through: mount --bind /proc/self/fd/ open_tree(tokfd, "", AT_EMPTY_PATH | OPEN_TREE_CLONE) + move_mount() __follow_mount_rcu() then loads ->mnt_root of that mount, reads d_seq and d_flags of the dentry and only then checks mount_lock. The dentry can be gone by then. The final mntput() of an unmounted parent unhooks a child that stayed attached to it under mount_lock alone. When the child's holder does the final put right after that the root is dput() and freed immediately while a walker that found the mount hashed still looks at it. Refuse to clone a mount with a DCACHE_NORCU dentry as its root. Nothing sensible can be done with a bind mount of a bpf token anyway. Fixes: 35f96de04127 ("bpf: Introduce BPF token object") Cc: stable@vger.kernel.org # v6.9+ Link: https://patch.msgid.link/20260930-work-mount-fixes-3-v1-17-be34c83956ae@kernel.org Signed-off-by: Christian Brauner (Amutable) Signed-off-by: Greg Kroah-Hartman --- fs/namespace.c | 4 ++++ 1 file changed, 4 insertions(+) --- a/fs/namespace.c +++ b/fs/namespace.c @@ -2971,6 +2971,10 @@ static struct mount *__do_loopback(const if (!may_copy_tree(old_path)) return ERR_PTR(-EINVAL); + /* a pseudo dentry is freed without an RCU delay, no walk may find it */ + if (old_path->dentry->d_flags & DCACHE_NORCU) + return ERR_PTR(-EINVAL); + if (recurse && !old->mnt_ns) return ERR_PTR(-EINVAL);