Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include "cgroup-internal.h"
0003 
0004 #include <linux/sched/task.h>
0005 #include <linux/slab.h>
0006 #include <linux/nsproxy.h>
0007 #include <linux/proc_ns.h>
0008 
0009 
0010 /* cgroup namespaces */
0011 
0012 static struct ucounts *inc_cgroup_namespaces(struct user_namespace *ns)
0013 {
0014     return inc_ucount(ns, current_euid(), UCOUNT_CGROUP_NAMESPACES);
0015 }
0016 
0017 static void dec_cgroup_namespaces(struct ucounts *ucounts)
0018 {
0019     dec_ucount(ucounts, UCOUNT_CGROUP_NAMESPACES);
0020 }
0021 
0022 static struct cgroup_namespace *alloc_cgroup_ns(void)
0023 {
0024     struct cgroup_namespace *new_ns;
0025     int ret;
0026 
0027     new_ns = kzalloc(sizeof(struct cgroup_namespace), GFP_KERNEL_ACCOUNT);
0028     if (!new_ns)
0029         return ERR_PTR(-ENOMEM);
0030     ret = ns_alloc_inum(&new_ns->ns);
0031     if (ret) {
0032         kfree(new_ns);
0033         return ERR_PTR(ret);
0034     }
0035     refcount_set(&new_ns->ns.count, 1);
0036     new_ns->ns.ops = &cgroupns_operations;
0037     return new_ns;
0038 }
0039 
0040 void free_cgroup_ns(struct cgroup_namespace *ns)
0041 {
0042     put_css_set(ns->root_cset);
0043     dec_cgroup_namespaces(ns->ucounts);
0044     put_user_ns(ns->user_ns);
0045     ns_free_inum(&ns->ns);
0046     kfree(ns);
0047 }
0048 EXPORT_SYMBOL(free_cgroup_ns);
0049 
0050 struct cgroup_namespace *copy_cgroup_ns(unsigned long flags,
0051                     struct user_namespace *user_ns,
0052                     struct cgroup_namespace *old_ns)
0053 {
0054     struct cgroup_namespace *new_ns;
0055     struct ucounts *ucounts;
0056     struct css_set *cset;
0057 
0058     BUG_ON(!old_ns);
0059 
0060     if (!(flags & CLONE_NEWCGROUP)) {
0061         get_cgroup_ns(old_ns);
0062         return old_ns;
0063     }
0064 
0065     /* Allow only sysadmin to create cgroup namespace. */
0066     if (!ns_capable(user_ns, CAP_SYS_ADMIN))
0067         return ERR_PTR(-EPERM);
0068 
0069     ucounts = inc_cgroup_namespaces(user_ns);
0070     if (!ucounts)
0071         return ERR_PTR(-ENOSPC);
0072 
0073     /* It is not safe to take cgroup_mutex here */
0074     spin_lock_irq(&css_set_lock);
0075     cset = task_css_set(current);
0076     get_css_set(cset);
0077     spin_unlock_irq(&css_set_lock);
0078 
0079     new_ns = alloc_cgroup_ns();
0080     if (IS_ERR(new_ns)) {
0081         put_css_set(cset);
0082         dec_cgroup_namespaces(ucounts);
0083         return new_ns;
0084     }
0085 
0086     new_ns->user_ns = get_user_ns(user_ns);
0087     new_ns->ucounts = ucounts;
0088     new_ns->root_cset = cset;
0089 
0090     return new_ns;
0091 }
0092 
0093 static inline struct cgroup_namespace *to_cg_ns(struct ns_common *ns)
0094 {
0095     return container_of(ns, struct cgroup_namespace, ns);
0096 }
0097 
0098 static int cgroupns_install(struct nsset *nsset, struct ns_common *ns)
0099 {
0100     struct nsproxy *nsproxy = nsset->nsproxy;
0101     struct cgroup_namespace *cgroup_ns = to_cg_ns(ns);
0102 
0103     if (!ns_capable(nsset->cred->user_ns, CAP_SYS_ADMIN) ||
0104         !ns_capable(cgroup_ns->user_ns, CAP_SYS_ADMIN))
0105         return -EPERM;
0106 
0107     /* Don't need to do anything if we are attaching to our own cgroupns. */
0108     if (cgroup_ns == nsproxy->cgroup_ns)
0109         return 0;
0110 
0111     get_cgroup_ns(cgroup_ns);
0112     put_cgroup_ns(nsproxy->cgroup_ns);
0113     nsproxy->cgroup_ns = cgroup_ns;
0114 
0115     return 0;
0116 }
0117 
0118 static struct ns_common *cgroupns_get(struct task_struct *task)
0119 {
0120     struct cgroup_namespace *ns = NULL;
0121     struct nsproxy *nsproxy;
0122 
0123     task_lock(task);
0124     nsproxy = task->nsproxy;
0125     if (nsproxy) {
0126         ns = nsproxy->cgroup_ns;
0127         get_cgroup_ns(ns);
0128     }
0129     task_unlock(task);
0130 
0131     return ns ? &ns->ns : NULL;
0132 }
0133 
0134 static void cgroupns_put(struct ns_common *ns)
0135 {
0136     put_cgroup_ns(to_cg_ns(ns));
0137 }
0138 
0139 static struct user_namespace *cgroupns_owner(struct ns_common *ns)
0140 {
0141     return to_cg_ns(ns)->user_ns;
0142 }
0143 
0144 const struct proc_ns_operations cgroupns_operations = {
0145     .name       = "cgroup",
0146     .type       = CLONE_NEWCGROUP,
0147     .get        = cgroupns_get,
0148     .put        = cgroupns_put,
0149     .install    = cgroupns_install,
0150     .owner      = cgroupns_owner,
0151 };
0152 
0153 static __init int cgroup_namespaces_init(void)
0154 {
0155     return 0;
0156 }
0157 subsys_initcall(cgroup_namespaces_init);