[PATCH RFC v3 23/90] nsproxy: build the nsproxy the tasks of a cell share

From: Josef Bacik

Date: Thu Nov 05 2026 - 10:04:17 EST


The namespaces of a cell are a property of the cell, not of its tasks. A
task of a cell can call neither unshare() nor setns(). So a single
nsproxy, created when the cell is sealed, can serve every task that the
cell will ever have.

Add cell_create_nsproxy(), which builds that nsproxy from the namespaces
in the slots of the cell. The uts and ipc namespaces are always new.
Objects in a shared ipc namespace would be owned by ids of the cell and
could outlive the cell. The time namespace is that of the builder.

Signed-off-by: Josef Bacik <josef@xxxxxxxxxxxxxx>
---
include/linux/nsproxy.h | 9 +++++++
kernel/nsproxy.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 76 insertions(+)

diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h
index dc2447f5f092..02101d96e4dd 100644
--- a/include/linux/nsproxy.h
+++ b/include/linux/nsproxy.h
@@ -12,6 +12,9 @@ struct ipc_namespace;
struct pid_namespace;
struct cgroup_namespace;
struct fs_struct;
+struct cell;
+struct net;
+struct user_namespace;

/*
* A structure to contain pointers to all per-process
@@ -101,6 +104,12 @@ void switch_task_namespaces(struct task_struct *tsk, struct nsproxy *new);
int exec_task_namespaces(void);
void deactivate_nsproxy(struct nsproxy *ns);
void nsproxy_free(struct nsproxy *ns);
+struct nsproxy *cell_create_nsproxy(struct user_namespace *user_ns,
+ struct mnt_namespace *mnt_ns,
+ struct pid_namespace *pid_ns,
+ struct net *net,
+ struct cgroup_namespace *cgroup_ns,
+ const char *hostname);
int unshare_nsproxy_namespaces(unsigned long, struct nsproxy **,
struct cred *, struct fs_struct *);
int __init nsproxy_cache_init(void);
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
index 2dcf105e8ee2..bfdd392f4007 100644
--- a/kernel/nsproxy.c
+++ b/kernel/nsproxy.c
@@ -28,6 +28,7 @@
#include <linux/cgroup.h>
#include <linux/perf_event.h>
#include <linux/nstree.h>
+#include <linux/cell.h>

static struct kmem_cache *nsproxy_cachep;

@@ -242,6 +243,72 @@ int unshare_nsproxy_namespaces(unsigned long unshare_flags,
return err;
}

+#ifdef CONFIG_CELLS
+/**
+ * cell_create_nsproxy - make the nsproxy every task of a cell shares
+ * @user_ns: the user namespace of the cell
+ * @mnt_ns: its mount namespace
+ * @pid_ns: its pid namespace
+ * @net: its network namespace
+ * @cgroup_ns: its cgroup namespace
+ * @hostname: its hostname
+ *
+ * The nsproxy never changes: a task of a cell can neither unshare() nor
+ * setns(). It takes its own references. The uts and ipc namespaces are always
+ * fresh, the time namespace is the caller's.
+ *
+ * Return: the nsproxy, active and with a reference for put_nsproxy(), or an
+ * ERR_PTR().
+ */
+struct nsproxy *cell_create_nsproxy(struct user_namespace *user_ns,
+ struct mnt_namespace *mnt_ns,
+ struct pid_namespace *pid_ns,
+ struct net *net,
+ struct cgroup_namespace *cgroup_ns,
+ const char *hostname)
+{
+ struct nsproxy *cur = current->nsproxy;
+ struct nsproxy *nsp;
+ int err;
+
+ nsp = create_nsproxy();
+ if (!nsp)
+ return ERR_PTR(-ENOMEM);
+
+ nsp->uts_ns = copy_utsname(CLONE_NEWUTS, user_ns, cur->uts_ns);
+ if (IS_ERR(nsp->uts_ns)) {
+ err = PTR_ERR(nsp->uts_ns);
+ goto out_free;
+ }
+ /* Nobody else can see it yet. */
+ strscpy_pad(nsp->uts_ns->name.nodename, hostname);
+ strscpy_pad(nsp->uts_ns->name.domainname, "(none)");
+
+ nsp->ipc_ns = copy_ipcs(CLONE_NEWIPC, user_ns, cur->ipc_ns);
+ if (IS_ERR(nsp->ipc_ns)) {
+ err = PTR_ERR(nsp->ipc_ns);
+ goto out_uts;
+ }
+
+ nsp->mnt_ns = mnt_ns_get_from_common(from_mnt_ns(mnt_ns));
+ nsp->pid_ns_for_children = get_pid_ns(pid_ns);
+ nsp->net_ns = get_net(net);
+ get_cgroup_ns(cgroup_ns);
+ nsp->cgroup_ns = cgroup_ns;
+ nsp->time_ns = get_time_ns(cur->time_ns);
+ nsp->time_ns_for_children = get_time_ns(cur->time_ns);
+
+ nsproxy_ns_active_get(nsp);
+ return nsp;
+
+out_uts:
+ put_uts_ns(nsp->uts_ns);
+out_free:
+ kmem_cache_free(nsproxy_cachep, nsp);
+ return ERR_PTR(err);
+}
+#endif
+
void switch_task_namespaces(struct task_struct *p, struct nsproxy *new)
{
struct nsproxy *ns;

--
2.55.0