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 --- 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