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(), type: UCOUNT_CGROUP_NAMESPACES);
15}
16
17static void dec_cgroup_namespaces(struct ucounts *ucounts)
18{
19 dec_ucount(ucounts, type: 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(size: sizeof(struct cgroup_namespace), GFP_KERNEL_ACCOUNT);
28 if (!new_ns)
29 return ERR_PTR(error: -ENOMEM);
30 ret = ns_alloc_inum(ns: &new_ns->ns);
31 if (ret) {
32 kfree(objp: new_ns);
33 return ERR_PTR(error: ret);
34 }
35 refcount_set(r: &new_ns->ns.count, n: 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(cset: ns->root_cset);
43 dec_cgroup_namespaces(ucounts: ns->ucounts);
44 put_user_ns(ns: ns->user_ns);
45 ns_free_inum(&ns->ns);
46 kfree(objp: 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(ns: old_ns);
62 return old_ns;
63 }
64
65 /* Allow only sysadmin to create cgroup namespace. */
66 if (!ns_capable(ns: user_ns, CAP_SYS_ADMIN))
67 return ERR_PTR(error: -EPERM);
68
69 ucounts = inc_cgroup_namespaces(ns: user_ns);
70 if (!ucounts)
71 return ERR_PTR(error: -ENOSPC);
72
73 /* It is not safe to take cgroup_mutex here */
74 spin_lock_irq(lock: &css_set_lock);
75 cset = task_css_set(current);
76 get_css_set(cset);
77 spin_unlock_irq(lock: &css_set_lock);
78
79 new_ns = alloc_cgroup_ns();
80 if (IS_ERR(ptr: 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(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(ns: nsset->cred->user_ns, CAP_SYS_ADMIN) ||
104 !ns_capable(ns: 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(ns: cgroup_ns);
112 put_cgroup_ns(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(p: task);
124 nsproxy = task->nsproxy;
125 if (nsproxy) {
126 ns = nsproxy->cgroup_ns;
127 get_cgroup_ns(ns);
128 }
129 task_unlock(p: task);
130
131 return ns ? &ns->ns : NULL;
132}
133
134static void cgroupns_put(struct ns_common *ns)
135{
136 put_cgroup_ns(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

source code of linux/kernel/cgroup/namespace.c