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