Branch data 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 : : 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 : : struct cgroup_namespace *new_ns; 25 : : int ret; 26 : : 27 : 0 : new_ns = kzalloc(sizeof(struct cgroup_namespace), GFP_KERNEL); 28 : 0 : if (!new_ns) 29 : : return ERR_PTR(-ENOMEM); 30 : : ret = ns_alloc_inum(&new_ns->ns); 31 : 0 : if (ret) { 32 : 0 : kfree(new_ns); 33 : 0 : return ERR_PTR(ret); 34 : : } 35 : : refcount_set(&new_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 : 3 : struct 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 : 3 : BUG_ON(!old_ns); 59 : : 60 : 3 : if (!(flags & CLONE_NEWCGROUP)) { 61 : : get_cgroup_ns(old_ns); 62 : 3 : return old_ns; 63 : : } 64 : : 65 : : /* Allow only sysadmin to create cgroup namespace. */ 66 : 0 : if (!ns_capable(user_ns, CAP_SYS_ADMIN)) 67 : : return ERR_PTR(-EPERM); 68 : : 69 : 0 : ucounts = inc_cgroup_namespaces(user_ns); 70 : 0 : 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 : 0 : cset = task_css_set(current); 76 : : get_css_set(cset); 77 : : 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 : : 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 : : 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 nsproxy *nsproxy, struct ns_common *ns) 99 : : { 100 : : struct cgroup_namespace *cgroup_ns = to_cg_ns(ns); 101 : : 102 : 0 : if (!ns_capable(current_user_ns(), CAP_SYS_ADMIN) || 103 : 0 : !ns_capable(cgroup_ns->user_ns, CAP_SYS_ADMIN)) 104 : : return -EPERM; 105 : : 106 : : /* Don't need to do anything if we are attaching to our own cgroupns. */ 107 : 0 : if (cgroup_ns == nsproxy->cgroup_ns) 108 : : return 0; 109 : : 110 : : get_cgroup_ns(cgroup_ns); 111 : 0 : put_cgroup_ns(nsproxy->cgroup_ns); 112 : 0 : nsproxy->cgroup_ns = cgroup_ns; 113 : : 114 : 0 : return 0; 115 : : } 116 : : 117 : 0 : static struct ns_common *cgroupns_get(struct task_struct *task) 118 : : { 119 : : struct cgroup_namespace *ns = NULL; 120 : : struct nsproxy *nsproxy; 121 : : 122 : : task_lock(task); 123 : 0 : nsproxy = task->nsproxy; 124 : 0 : if (nsproxy) { 125 : 0 : ns = nsproxy->cgroup_ns; 126 : : get_cgroup_ns(ns); 127 : : } 128 : : task_unlock(task); 129 : : 130 : 0 : return ns ? &ns->ns : NULL; 131 : : } 132 : : 133 : 0 : static void cgroupns_put(struct ns_common *ns) 134 : : { 135 : 0 : put_cgroup_ns(to_cg_ns(ns)); 136 : 0 : } 137 : : 138 : 0 : static struct user_namespace *cgroupns_owner(struct ns_common *ns) 139 : : { 140 : 0 : return to_cg_ns(ns)->user_ns; 141 : : } 142 : : 143 : : const struct proc_ns_operations cgroupns_operations = { 144 : : .name = "cgroup", 145 : : .type = CLONE_NEWCGROUP, 146 : : .get = cgroupns_get, 147 : : .put = cgroupns_put, 148 : : .install = cgroupns_install, 149 : : .owner = cgroupns_owner, 150 : : }; 151 : : 152 : 3 : static __init int cgroup_namespaces_init(void) 153 : : { 154 : 3 : return 0; 155 : : } 156 : : subsys_initcall(cgroup_namespaces_init);