From: Shao Mingyin statmount() and listmount() on a foreign mount namespace fail with -ENOENT when nothing is mounted on top of the namespace root. That is the case for an empty mount namespace created by unshare(UNSHARE_EMPTY_MNTNS) or clone3(CLONE_EMPTY_MNTNS): its only mount is the namespace root, a nullfs mount, and no rootfs is mounted on it. Both syscalls resolve the path anchor for a foreign namespace in grab_requested_root(). It starts at ns->root and looks for a mount whose parent is that root, i.e. the mount covering the namespace root: for (child = node_to_mount(ns->mnt_first_node); child; child = listmnt_next(child, false)) { if (child != first && child->mnt_parent == first) break; } if (!child) return -ENOENT; When nothing is mounted on the root the loop finds no candidate, so the whole syscall fails although the mount id the caller asks about exists in that namespace. statmount() issued from inside the same namespace succeeds, which shows that the mount is fine. Fall back to the namespace root itself in that case. Inside such a namespace the root mount is what the members' root and cwd point at, so it is the correct anchor; paths below it are resolved relative to "/". The same condition also occurs for an anonymous namespace created by fsmount() or open_tree(OPEN_TREE_CLONE): it contains only the root mount itself, and statmount(STATMOUNT_BY_FD) on such a mount fd failed with -ENOENT for the same reason. Fixes: 71aacb4c8c3d ("fs: Allow statmount() in foreign mount namespace") Signed-off-by: Shao Mingyin --- Tested on 7.3.0-next-20261030 (x86_64 QEMU/TCG guest, defconfig plus KASAN, no extra hardware). A child process unshares into an empty mount namespace (unshare(UNSHARE_EMPTY_MNTNS)), reads the unique mount ID of its root with statx("/", STATX_MNT_ID_UNIQUE) and then blocks. The parent opens /proc//ns/mnt and queries that namespace by mount ID. The mount ID is valid: statmount() from inside the child's own namespace returns fs_type=nullfs on both kernels. unpatched patched statmount() ret=-1 errno=2 (ENOENT) statmount() ret=0, mask=STATMOUNT_MNT_BASIC| STATMOUNT_FS_TYPE listmount() ret=-1 errno=2 (ENOENT) listmount() ret=1, id= The patched kernel also still returns the mount for statmount(STATMOUNT_BY_FD) on a mount fd obtained with open_tree(OPEN_TREE_CLONE), i.e. for the anonymous namespace case. Both kernels are otherwise clean: no KASAN report, no Oops, no WARN. --- diff --git a/fs/namespace.c b/fs/namespace.c index 25e196c05126..8a101a8c48f7 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -5888,8 +5888,14 @@ static int grab_requested_root(struct mnt_namespace *ns, struct path *root) if (child != first && child->mnt_parent == first) break; } + /* + * Nothing mounted on the root of the namespace: an empty mount + * namespace (CLONE_EMPTY_MNTNS) or an anonymous namespace from + * fsmount()/open_tree(OPEN_TREE_CLONE). Use the namespace root + * itself as the anchor then; there is no child covering it. + */ if (!child) - return -ENOENT; + child = first; root->mnt = mntget(&child->mnt); root->dentry = dget(root->mnt->mnt_root);