proc: fix timerslack_ns CAP_SYS_NICE check when adjusting self
[cascardo/linux.git] / kernel / user_namespace.c
index 7d87017..86b7854 100644 (file)
@@ -31,6 +31,15 @@ static bool new_idmap_permitted(const struct file *file,
                                struct uid_gid_map *map);
 static void free_user_ns(struct work_struct *work);
 
+static struct ucounts *inc_user_namespaces(struct user_namespace *ns, kuid_t uid)
+{
+       return inc_ucount(ns, uid, UCOUNT_USER_NAMESPACES);
+}
+
+static void dec_user_namespaces(struct ucounts *ucounts)
+{
+       return dec_ucount(ucounts, UCOUNT_USER_NAMESPACES);
+}
 
 static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
 {
@@ -64,13 +73,15 @@ int create_user_ns(struct cred *new)
        struct user_namespace *ns, *parent_ns = new->user_ns;
        kuid_t owner = new->euid;
        kgid_t group = new->egid;
-       int ret;
+       struct ucounts *ucounts;
+       int ret, i;
 
-       ret = -EUSERS;
+       ret = -ENOSPC;
        if (parent_ns->level > 32)
                goto fail;
 
-       if (!inc_user_namespaces(parent_ns))
+       ucounts = inc_user_namespaces(parent_ns, owner);
+       if (!ucounts)
                goto fail;
 
        /*
@@ -109,7 +120,10 @@ int create_user_ns(struct cred *new)
        ns->owner = owner;
        ns->group = group;
        INIT_WORK(&ns->work, free_user_ns);
-       ns->max_user_namespaces = INT_MAX;
+       for (i = 0; i < UCOUNT_COUNTS; i++) {
+               ns->ucount_max[i] = INT_MAX;
+       }
+       ns->ucounts = ucounts;
 
        /* Inherit USERNS_SETGROUPS_ALLOWED from our parent */
        mutex_lock(&userns_state_mutex);
@@ -133,7 +147,7 @@ fail_keyring:
 fail_free:
        kmem_cache_free(user_ns_cachep, ns);
 fail_dec:
-       dec_user_namespaces(parent_ns);
+       dec_user_namespaces(ucounts);
 fail:
        return ret;
 }
@@ -164,6 +178,7 @@ static void free_user_ns(struct work_struct *work)
                container_of(work, struct user_namespace, work);
 
        do {
+               struct ucounts *ucounts = ns->ucounts;
                parent = ns->parent;
                retire_userns_sysctls(ns);
 #ifdef CONFIG_PERSISTENT_KEYRINGS
@@ -171,7 +186,7 @@ static void free_user_ns(struct work_struct *work)
 #endif
                ns_free_inum(&ns->ns);
                kmem_cache_free(user_ns_cachep, ns);
-               dec_user_namespaces(parent);
+               dec_user_namespaces(ucounts);
                ns = parent;
        } while (atomic_dec_and_test(&parent->count));
 }
@@ -1035,12 +1050,37 @@ 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)
+{
+       struct user_namespace *my_user_ns = current_user_ns();
+       struct user_namespace *owner, *p;
+
+       /* See if the owner is in the current user namespace */
+       owner = p = ns->ops->owner(ns);
+       for (;;) {
+               if (!p)
+                       return ERR_PTR(-EPERM);
+               if (p == my_user_ns)
+                       break;
+               p = p->parent;
+       }
+
+       return &get_user_ns(owner)->ns;
+}
+
+static struct user_namespace *userns_owner(struct ns_common *ns)
+{
+       return to_user_ns(ns)->parent;
+}
+
 const struct proc_ns_operations userns_operations = {
        .name           = "user",
        .type           = CLONE_NEWUSER,
        .get            = userns_get,
        .put            = userns_put,
        .install        = userns_install,
+       .owner          = userns_owner,
+       .get_parent     = ns_get_owner,
 };
 
 static __init int user_namespaces_init(void)