[PATCH RFC v3 49/90] nsproxy: refuse to enter a namespace of a cell
From: Josef Bacik
Date: Thu Nov 05 2026 - 10:29:27 EST
No existing task can enter a cell. Refuse setns() into any namespace that
is owned by the user namespace of a cell.
This also applies while the cell is still being built. A task that entered
the pid namespace at that point could become the init of the cell while it
has the credentials of the host. Or it could hold on to the namespace and
fork into the cell later.
The mount namespace of a cell is owned by the user namespace of the
builder, and has its own protection, see mnt_ns_seal_for_cell(). The
network namespace is also owned by the user namespace of the builder. It
stays accessible to whoever set it up.
Signed-off-by: Josef Bacik <josef@xxxxxxxxxxxxxx>
---
kernel/nsproxy.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
index 5d6cec2dc4ce..6b9b220a2bae 100644
--- a/kernel/nsproxy.c
+++ b/kernel/nsproxy.c
@@ -467,8 +467,21 @@ static int prepare_nsset(unsigned flags, struct nsset *nsset)
static inline int validate_ns(struct nsset *nsset, struct ns_common *ns)
{
+ struct user_namespace *owner = ns->ops->owner ? ns->ops->owner(ns) : NULL;
int ret;
+ /*
+ * Nobody enters a cell, and not while it is being built either. Whoever
+ * got into the pid namespace then could become the init of the cell, or
+ * fork into it later.
+ *
+ * The mount namespace belongs to the user namespace of whoever built the
+ * cell and looks after itself, see mnt_ns_seal_for_cell(). So does the
+ * network namespace, and whoever set that up may go on doing so.
+ */
+ if (owner && userns_is_cell(owner))
+ return -EPERM;
+
ret = security_namespace_install(nsset, ns);
if (ret)
return ret;
--
2.55.0