mount: refuse setns() with a shared fs_struct again

mntns_install() refuses to switch the mount namespace of a task that
shares its fs_struct, since root and cwd of the others would move to a
namespace they are not in.  It looks at nsset->fs for that.  If more
than the mount namespace is asked for, that is a private copy made by
prepare_nsset(), which has one user by definition; commit_nsset() then
writes root and cwd of the copy to the fs_struct of the task.

A thread of a process with two threads, pidfd of a task in another
mount namespace:

	setns(pidfd, CLONE_NEWNS)			-EINVAL
	setns(pidfd, CLONE_NEWNS | CLONE_NEWUTS)	0

and after the second call the other thread, still in the old mount
namespace, has lost its cwd (/tmp became /) and sees the mounts of the
other namespace under /.

Look at the fs_struct that is going to be changed.  The second call then
fails with -EINVAL like the first one.

Fixes: 303cc571d1 ("nsproxy: attach to namespaces via pidfds")
Cc: stable@vger.kernel.org # v5.8+
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
Josef Bacik 2026-10-08 09:33:33 +00:00 committed by Christian Brauner
parent e227cdac03
commit 948e604aca
No known key found for this signature in database
GPG Key ID: 91C61BC06578DCA2

View File

@ -6727,7 +6727,7 @@ static int mntns_install(struct nsset *nsset, struct ns_common *ns)
if (is_anon_ns(mnt_ns))
return -EINVAL;
if (fs->users != 1)
if (current->fs->users != 1)
return -EINVAL;
get_mnt_ns(mnt_ns);