Re: setns(2) vs. pivot_root(2) (was Re: [PATCH v2] audit: Avoid excessive dput/dget in audit_context setup and reset paths)

Al Viro <[email protected]>
Newsgroups org.kernel.vger.audit,org.kernel.vger.linux-kernel
Message-ID <20260206210916.GD3183987@ZenIV>
On Fri, Feb 06, 2026 at 08:58:04PM +0000, Al Viro wrote:
> On Fri, Feb 06, 2026 at 08:29:33PM +0000, Al Viro wrote:
> 
> > Look: the case where we might get passed current->fs down there is real.
> > It can happen in one and only one situation - CLONE_NEWNS in unshare(2)
> > arguments *and* current->fs->users being 1.
> > 
> > It wouldn't suffice, since there's chroot_fs_refs() that doesn't give
> > a rat's arse for task->fs being ours - it goes and replaces every
> > ->fs->pwd or ->fs->root that happens to point to old_root.
> > 
> > It's still not a real race, though - both chroot_fs_refs() and that area
> > in copy_mnt_ns() are serialized on namespace_sem.
> > 
> > And yes, it's obscenely byzantine.  It gets even worse when you consider
> > the fact that pivot_root(2) does not break only because the refcount
> > drops in chroot_fs_refs() are guaranteed not to reach 0 - the caller is
> > holding its own references to old_root.{mnt,dentry} and *thar* does not
> > get dropped until we drop namespace_sem.
> > 
> > IOW, that shit is actually safe, but man, has its correctness grown fucking
> > convoluted...
> > 
> > Grabbing fs->seq in copy_mnt_ns() wouldn't make the things better, though -
> > it seriously relies upon the same exclusion with chroot_fs_refs() for
> > correctness; unless you are willing to hold it over the entire walk through
> > the mount tree, the proof of correctness doesn't get any simpler.
> 
> Speaking of the race that _is_ there: pidfd setns() vs. pivot_root().
> pivot_root() (well, chroot_fs_refs()) goes over all threads and flips their
> ->fs->{root,pwd} for the ones that used to be at old_root.  The trouble is,
> in case where we have setns() with more than just CLONE_NEWNS in flags, we
> end up creating a temporary fs_struct, passing that to mntns_install() and
> then copying its pwd and root back to the caller's if everything goes well.
> 
> That temporary is _not_ going to be found by chroot_fs_refs(), though, so
> it misses the update by pivot_root().

BTW, in the same case of setns(2) (e.g. CLONE_NEWNS | CLONE_NEWUTS in flags)
we end up defeating the check for fs->users == 1 in mntns_install() - for
the temporary fs_struct it will always be true.  Unless I'm missing something
elsewhere...  Christian?  Looks like that went in with 303cc571d107 ("nsproxy:
attach to namespaces via pidfds")...
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.