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