Andrey Vagin [off-list ref] writes:
quoted hunk
Return -EPERM if an owning user namespace is outside of a process
current user namespace.
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index a5bc78c..6382e5e 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -994,6 +994,30 @@ static int userns_install(struct nsproxy *nsproxy, struct ns_common *ns)
return commit_creds(cred);
}
+struct ns_common *ns_get_owner(struct ns_common *ns)
+{
+ const struct cred *cred = current_cred();
+ struct user_namespace *user_ns, *p;
+
+ user_ns = p = ns->user_ns;
+ if (user_ns == NULL) { /* ns is init_user_ns */
+ /* Unprivileged user should not know that it's init_user_ns. */
+ if (capable(CAP_SYS_ADMIN))
+ return ERR_PTR(-ENOENT);
+ return ERR_PTR(-EPERM);
+ }
This permission check is not what I meant to request. This does not
handle nested user namespaces.
quoted hunk
+ for (;;) {
+ if (p == cred->user_ns)
+ break;
+ if (p == &init_user_ns)
+ return ERR_PTR(-EPERM);
+ p = p->parent;
+ }
+
The permission check really needs to be down here. And be:
if (!ns_capable(user_ns, CAP_SYS_ADMIN))
return ERR_PTR(-EPERM).
That cleanly and easily handles more than a depth of a single user
namespace.
quoted hunk
+ return &get_user_ns(user_ns)->ns;
+}
+
const struct proc_ns_operations userns_operations = {
.name = "user",
.type = CLONE_NEWUSER,
Eric