From: Christian Brauner <brauner@kernel.org>
To: John Ericson <mail@johnericson.me>
Cc: Li Chen <me@linux.beauty>, Cong Wang <cwang@multikernel.io>,
linux-arch@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-fsdevel@vger.kernel.org, linux-api@vger.kernel.org,
Arnd Bergmann <arnd@arndb.de>, Andy Lutomirski <luto@kernel.org>,
Thomas Gleixner <tglx@kernel.org>,
Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>,
Dave Hansen <dave.hansen@linux.intel.com>,
"H. Peter Anvin" <hpa@zytor.com>, Jan Kara <jack@suse.cz>,
Jonathan Corbet <corbet@lwn.net>,
Shuah Khan <skhan@linuxfoundation.org>,
Alexander Viro <viro@zeniv.linux.org.uk>,
Kees Cook <kees@kernel.org>,
Sergei Zimmerman <sergei@zimmerman.foo>,
Farid Zakaria <farid.m.zakaria@gmail.com>
Subject: Re: [RFC] Null Namespaces
Date: Mon, 29 Jun 2026 13:45:24 +0200 [thread overview]
Message-ID: <20260629-hauer-erhitzen-sobald-96d3dff68707@brauner> (raw)
In-Reply-To: <a49ce818-f38d-41b0-bbf7-80b8aad998b1@app.fastmail.com>
On Wed, Jun 24, 2026 at 06:51:47PM -0400, John Ericson wrote:
> Hello, I am hoping to discuss an idea I've had for a while, that I am
> calling "null namespaces" that has become more relevant with some recent
> other discussions. First I'll discuss null namespaces in general terms,
> and then I'll link those recent discussions and relate null namespaces
> to them.
>
> ### Null namespaces
>
> The essence of null namespaces is trying to give processes as little
> ambient authority as possible, so they are lighter weight and allowed to
> do even less than fully unshared processes today.
>
> Namespaces as they exist today are frequently described as an isolation
> mechanism, but I think this is the conflation of two different things.
> *Removing* a new process from its parent's namespaces unquestionably is
> increasing isolation --- no disagreement there. But putting the process
> in new namespaces is something else; I would call it supporting
> "delusions of grandeur" of that process. For example, namespaces allow a
> process to do mounts, have `CAP_SYS_ADMIN`, create network interfaces,
> look up other processes by PID, etc.
>
> Conceptually, to remove a process from one ambient authority scope (the
> very name "namespaces" indicates they are about ambient authority)
> should not require putting it in some ambient authority scope. Just
> because, for example, the process cannot see one mount tree, doesn't
> mean it needs to see another.
>
> Here's what I am thinking would happen concretely:
>
> First, the simpler cases:
>
> #### Null mount namespace
>
> - requires:
>
> - null root file system: absolute paths don't work.
>
> - null current working directory: relative paths with traditional,
> non-`*at` system calls (and `*at` ones using `AT_FDCWD`) don't work.
>
> - All operations relating to the "ambient" mount tree don't work.
>
> - `*at` operations with a file descriptor do work.
>
> - The new fd-based mount APIs with detached mounts do work, modulo
> the calling process having enough permissions (as usual).
Nothing here requires you to NULL anything and I oppose this on code
sanity reasons alone. We shoud absolutely not start to stash any NULL
pointers in core kernel objects such as struct path that are used
everywhere.
So I've added nullfs a few releases back. It's currently not mountable
from userspace but I've already mentioned in the commit message that
this is going to change. But I also added:
unshare(UNSHARE_EMPTY_MNTNS)
clone3(CLONE_EMPTY_MNTNS)
In both cases the process is placed into a completely empty mount
namespace with nullfs as it's root and cwd. If you're in a new mount
namespace with CAP_SYS_ADMIN thrown away it means you're going to be in
nullfs forever.
It's possible we can come up with:
unshare(UNSHARE_FS_EMPTY)
clone3(CLONE_FS_EMPTY)
which just moves the task into an isolated nullfs instance (it would
need some thinking about interactions with chroot()).
But I guess the even simpler model would be to copy what I've been doing
for pidfs:
+static struct path nullfs_root_path = {};
+
+void nullfs_get_root(struct path *path)
+{
+ *path = 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 = nullfs_mnt;
root.dentry = nullfs_mnt->mnt_root;
+ nullfs_root_path.mnt = nullfs_mnt;
+ pidfs_root_path.dentry = 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 nullfs filesystem */
#define FD_INVALID -10009 /* Invalid file descriptor: -10000 - EBADF = -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 state
and move itself into nullfs. Restrict *chdir() and *chroot() for said
process via seccomp and it's locked in forever as well.
next prev parent reply other threads:[~2026-06-29 11:45 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-24 22:51 [RFC] Null Namespaces John Ericson
2026-06-24 23:06 ` Andy Lutomirski
2026-06-24 23:20 ` Andy Lutomirski
2026-06-24 23:53 ` John Ericson
2026-06-25 1:10 ` Al Viro
2026-06-25 3:41 ` John Ericson
2026-06-25 15:51 ` Andy Lutomirski
2026-06-25 18:21 ` John Ericson
2026-06-26 0:15 ` Al Viro
2026-06-26 16:26 ` John Ericson
2026-06-29 10:31 ` Christian Brauner
2026-06-24 23:12 ` Al Viro
2026-06-25 21:00 ` H. Peter Anvin
2026-06-25 21:50 ` John Ericson
2026-06-25 23:09 ` Andy Lutomirski
2026-06-26 8:27 ` David Laight
2026-06-26 17:23 ` John Ericson
2026-06-29 10:39 ` Christian Brauner
2026-07-01 9:49 ` Jori Koolstra
2026-07-02 21:28 ` H. Peter Anvin
2026-06-29 11:45 ` Christian Brauner [this message]
2026-06-29 21:06 ` Andy Lutomirski
2026-06-30 4:25 ` John Ericson
2026-07-02 9:34 ` Christian Brauner
2026-07-02 15:43 ` John Ericson
2026-07-03 8:59 ` Christian Brauner
2026-07-03 17:35 ` Directory capability brain dump (Re: [RFC] Null Namespaces) Andy Lutomirski
2026-07-06 14:52 ` [RFC] Null Namespaces Christian Brauner
2026-07-06 16:32 ` Jann Horn
2026-07-06 17:10 ` Andy Lutomirski
2026-07-06 17:04 ` Andy Lutomirski
2026-06-30 2:50 ` John Ericson
2026-06-30 7:14 ` Christian Brauner
2026-06-30 17:20 ` John Ericson
2026-06-30 17:41 ` Andy Lutomirski
2026-07-02 9:29 ` Christian Brauner
2026-06-30 18:05 ` H. Peter Anvin
2026-07-04 13:20 ` Li Chen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260629-hauer-erhitzen-sobald-96d3dff68707@brauner \
--to=brauner@kernel.org \
--cc=arnd@arndb.de \
--cc=bp@alien8.de \
--cc=corbet@lwn.net \
--cc=cwang@multikernel.io \
--cc=dave.hansen@linux.intel.com \
--cc=farid.m.zakaria@gmail.com \
--cc=hpa@zytor.com \
--cc=jack@suse.cz \
--cc=kees@kernel.org \
--cc=linux-api@vger.kernel.org \
--cc=linux-arch@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=luto@kernel.org \
--cc=mail@johnericson.me \
--cc=me@linux.beauty \
--cc=mingo@redhat.com \
--cc=sergei@zimmerman.foo \
--cc=skhan@linuxfoundation.org \
--cc=tglx@kernel.org \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox