Re: [RFC] Null Namespaces

Andy Lutomirski <[email protected]> Sat, 18 Jul 2026 12:39:39 -0700
Newsgroups org.kernel.vger.linux-api,org.kernel.vger.linux-arch,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel
Message-ID <CALCETrVjDtBmB+boCUgd069UpZGUB1TCbEn3k1HZQex-_dPgbQ@mail.gmail.com>
On Mon, Jul 6, 2026 at 8:31=E2=80=AFAM Christian Brauner <[email protected]=
g> wrote:
>
> On Thu, Jul 02, 2026 at 11:34:01AM +0200, Christian Brauner wrote:
> > On Mon, Jun 29, 2026 at 02:06:55PM -0700, Andy Lutomirski wrote:
> > > On Mon, Jun 29, 2026 at 4:45=E2=80=AFAM Christian Brauner <brauner@ke=
rnel.org> wrote:
> > > >
> > >
> > > > But I guess the even simpler model would be to copy what I've been =
doing
> > > > for pidfs:
> > > >
> > > > +static struct path nullfs_root_path =3D {};
> > > > +
> > > > +void nullfs_get_root(struct path *path)
> > > > +{
> > > > +       *path =3D nullfs_root_path;
> > > > +       path_get(path);
> > > > +}
> > > > +
> > > >  static void __init init_mount_tree(void)
> > > >  {
> > > >         struct vfsmount *mnt, *nullfs_mnt;
> > > > @@ -6209,6 +6217,8 @@ static void __init init_mount_tree(void)
> > > >         /* Mount mutable rootfs on top of nullfs. */
> > > >         root.mnt                =3D nullfs_mnt;
> > > >         root.dentry             =3D nullfs_mnt->mnt_root;
> > > > +       nullfs_root_path.mnt    =3D nullfs_mnt;
> > > > +       pidfs_root_path.dentry  =3D nullfs_mnt->mnt_root;
> > > >
> > > >         LOCK_MOUNT_EXACT(mp, &root);
> > > >         if (unlikely(IS_ERR(mp.parent)))
> > > > diff --git a/include/uapi/linux/fcntl.h b/include/uapi/linux/fcntl.=
h
> > > > index aadfbf6e0cb3..f55c87c70b78 100644
> > > > --- a/include/uapi/linux/fcntl.h
> > > > +++ b/include/uapi/linux/fcntl.h
> > > > @@ -124,6 +124,7 @@ struct delegation {
> > > >
> > > >  #define FD_PIDFS_ROOT                  -10002 /* Root of the pidfs=
 filesystem */
> > > >  #define FD_NSFS_ROOT                   -10003 /* Root of the nsfs =
filesystem */
> > > > +#define FD_NULLFS_ROOT                 -10004 /* Root of the nullf=
s filesystem */
> > > >  #define FD_INVALID                     -10009 /* Invalid file desc=
riptor: -10000 - EBADF =3D -10009 */
> > > >
> > > >  /* Generic flags for the *at(2) family of syscalls. */
> > > >
> > > > we then add fchroot() (overdue anyway) and then teach both fchdir()=
 and
> > > > fchroot() to honor FD_NULLFS_ROOT. Then a process may shed its fs s=
tate
> > > > and move itself into nullfs. Restrict *chdir() and *chroot() for sa=
id
> > > > process via seccomp and it's locked in forever as well.
> > > >
> > >
> > > One thing comes to mind that might need a bit of care: this would giv=
e
> > > an API for any task to get an fd to a directory that lives in the ini=
t
> > > mount namespace.  It's not at all obvious to me that this is dangerou=
s
> > > or even observable (you're not about to find a setuid program in
> > > nullfs), but I think it's at least worth a tiny bit of consideration.
> >
> > Yes, I thought about this as well. But it doesn't have to be this way.
> > Every mount namespaces has nullfs as it's root ever since I introduced
> > it. Which means FD_NULLFS_ROOT can also just mean "nullfs within that
> > specific mount namespace". That's fine.
> >
> > For my FD_FAILFS_ROOT proposal it would be enough if we make failfs
> > SB_KERNMOUNT which means it's logically distinct from every mount
> > namespace. I think that might be the right thing to do. I need to spend
> > one or more brain cycles on this though.
>
> I had to take a long drive on Sunday and I kept thinking about both
> FD_NULLFS_ROOT and FD_FAILFS_ROOT and ofc there are some things to
> consider/discuss.
>
> I think the straightforward solution to FD_NULLFS_ROOT would be to just:
>
> - make it always available
> - refer to the caller's mount namespace nullfs
> - work with fchroot()/fchdir()
>
> So I considered two chroot() use-cases for the sake of simplicity:
>
> (1) You want to isolate yourself for the sake of lookup
>
> (2) You want to isolate yourself to assemble a "private mount tree" but
>     not really be in a separate namespace (very odd use-case... but it
>     helps to make a point).
>
> The problem with this approach is that everyone who chroots into the
> nullfs root would suffer from the problem that any mount on top of it is
> still visible. So that kinda makes it pointless for both (1) and (2).
>
> Also all mounts that someone else would do would also be visible
> allowing multiple chroot()ers to affect each others state. That also
> would somewhat defeat the purpose of the chroot(). So I'm not convinced
> this is what we should do.
>

After some contemplation and a long place flight: are we talking about
nullfs or failfs?  Because I would expect that it's entirely
impossible to mount anything on top of failfs.  So failfs would be
useless for #2 but would still solve #1.

--Andy