linux/kernel/cgroup/namespace.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include "cgroup-internal.h"
   3
   4#include <linux/sched/task.h>
   5#include <linux/slab.h>
   6#include <linux/nsproxy.h>
   7#include <linux/proc_ns.h>
   8
   9
  10/* cgroup namespaces */
  11
  12static struct ucounts *inc_cgroup_namespaces(struct user_namespace *ns)
  13{
  14        return inc_ucount(ns, current_euid(), UCOUNT_CGROUP_NAMESPACES);
  15}
  16
  17static void dec_cgroup_namespaces(struct ucounts *ucounts)
  18{
  19        dec_ucount(ucounts, UCOUNT_CGROUP_NAMESPACES);
  20}
  21
  22static struct cgroup_namespace *alloc_cgroup_ns(void)
  23{
  24        struct cgroup_namespace *new_ns;
  25        int ret;
  26
  27        new_ns = kzalloc(sizeof(struct cgroup_namespace), GFP_KERNEL_ACCOUNT);
  28        if (!new_ns)
  29                return ERR_PTR(-ENOMEM);
  30        ret = ns_alloc_inum(&new_ns->ns);
  31        if (ret) {
  32                kfree(new_ns);
  33                return ERR_PTR(ret);
  34        }
  35        refcount_set(&new_ns->ns.count, 1);
  36        new_ns->ns.ops = &cgroupns_operations;
  37        return new_ns;
  38}
  39
  40void free_cgroup_ns(struct cgroup_namespace *ns)
  41{
  42        put_css_set(ns->root_cset);
  43        dec_cgroup_namespaces(ns->ucounts);
  44        put_user_ns(ns->user_ns);
  45        ns_free_inum(&ns->ns);
  46        kfree(ns);
  47}
  48EXPORT_SYMBOL(free_cgroup_ns);
  49
  50struct cgroup_namespace *copy_cgroup_ns(unsigned long flags,
  51                                        struct user_namespace *user_ns,
  52                                        struct cgroup_namespace *old_ns)
  53{
  54        struct cgroup_namespace *new_ns;
  55        struct ucounts *ucounts;
  56        struct css_set *cset;
  57
  58        BUG_ON(!old_ns);
  59
  60        if (!(flags & CLONE_NEWCGROUP)) {
  61                get_cgroup_ns(old_ns);
  62                return old_ns;
  63        }
  64
  65        /* Allow only sysadmin to create cgroup namespace. */
  66        if (!ns_capable(user_ns, CAP_SYS_ADMIN))
  67                return ERR_PTR(-EPERM);
  68
  69        ucounts = inc_cgroup_namespaces(user_ns);
  70        if (!ucounts)
  71                return ERR_PTR(-ENOSPC);
  72
  73        /* It is not safe to take cgroup_mutex here */
  74        spin_lock_irq(&css_set_lock);
  75        cset = task_css_set(current);
  76        get_css_set(cset);
  77        spin_unlock_irq(&css_set_lock);
  78
  79        new_ns = alloc_cgroup_ns();
  80        if (IS_ERR(new_ns)) {
  81                put_css_set(cset);
  82                dec_cgroup_namespaces(ucounts);
  83                return new_ns;
  84        }
  85
  86        new_ns->user_ns = get_user_ns(user_ns);
  87        new_ns->ucounts = ucounts;
  88        new_ns->root_cset = cset;
  89
  90        return new_ns;
  91}
  92
  93static inline struct cgroup_namespace *to_cg_ns(struct ns_common *ns)
  94{
  95        return container_of(ns, struct cgroup_namespace, ns);
  96}
  97
  98static int cgroupns_install(struct nsset *nsset, struct ns_common *ns)
  99{
 100        struct nsproxy *nsproxy = nsset->nsproxy;
 101        struct cgroup_namespace *cgroup_ns = to_cg_ns(ns);
 102
 103        if (!ns_capable(nsset->cred->user_ns, CAP_SYS_ADMIN) ||
 104            !ns_capable(cgroup_ns->user_ns, CAP_SYS_ADMIN))
 105                return -EPERM;
 106
 107        /* Don't need to do anything if we are attaching to our own cgroupns. */
 108        if (cgroup_ns == nsproxy->cgroup_ns)
 109                return 0;
 110
 111        get_cgroup_ns(cgroup_ns);
 112        put_cgroup_ns(nsproxy->cgroup_ns);
 113        nsproxy->cgroup_ns = cgroup_ns;
 114
 115        return 0;
 116}
 117
 118static struct ns_common *cgroupns_get(struct task_struct *task)
 119{
 120        struct cgroup_namespace *ns = NULL;
 121        struct nsproxy *nsproxy;
 122
 123        task_lock(task);
 124        nsproxy = task->nsproxy;
 125        if (nsproxy) {
 126                ns = nsproxy->cgroup_ns;
 127                get_cgroup_ns(ns);
 128        }
 129        task_unlock(task);
 130
 131        return ns ? &ns->ns : NULL;
 132}
 133
 134static void cgroupns_put(struct ns_common *ns)
 135{
 136        put_cgroup_ns(to_cg_ns(ns));
 137}
 138
 139static struct user_namespace *cgroupns_owner(struct ns_common *ns)
 140{
 141        return to_cg_ns(ns)->user_ns;
 142}
 143
 144const struct proc_ns_operations cgroupns_operations = {
 145        .name           = "cgroup",
 146        .type           = CLONE_NEWCGROUP,
 147        .get            = cgroupns_get,
 148        .put            = cgroupns_put,
 149        .install        = cgroupns_install,
 150        .owner          = cgroupns_owner,
 151};
 152
 153static __init int cgroup_namespaces_init(void)
 154{
 155        return 0;
 156}
 157subsys_initcall(cgroup_namespaces_init);
 158