• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
inc_cgroup_namespaces(struct user_namespace * ns)12 static struct ucounts *inc_cgroup_namespaces(struct user_namespace *ns)
13 {
14 	return inc_ucount(ns, current_euid(), UCOUNT_CGROUP_NAMESPACES);
15 }
16 
dec_cgroup_namespaces(struct ucounts * ucounts)17 static void dec_cgroup_namespaces(struct ucounts *ucounts)
18 {
19 	dec_ucount(ucounts, UCOUNT_CGROUP_NAMESPACES);
20 }
21 
alloc_cgroup_ns(void)22 static 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);
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->count, 1);
36 	new_ns->ns.ops = &cgroupns_operations;
37 	return new_ns;
38 }
39 
free_cgroup_ns(struct cgroup_namespace * ns)40 void 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 }
48 EXPORT_SYMBOL(free_cgroup_ns);
49 
copy_cgroup_ns(unsigned long flags,struct user_namespace * user_ns,struct cgroup_namespace * old_ns)50 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 	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 
to_cg_ns(struct ns_common * ns)93 static inline struct cgroup_namespace *to_cg_ns(struct ns_common *ns)
94 {
95 	return container_of(ns, struct cgroup_namespace, ns);
96 }
97 
cgroupns_install(struct nsproxy * nsproxy,struct ns_common * ns)98 static int cgroupns_install(struct nsproxy *nsproxy, struct ns_common *ns)
99 {
100 	struct cgroup_namespace *cgroup_ns = to_cg_ns(ns);
101 
102 	if (!ns_capable(current_user_ns(), CAP_SYS_ADMIN) ||
103 	    !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 	if (cgroup_ns == nsproxy->cgroup_ns)
108 		return 0;
109 
110 	get_cgroup_ns(cgroup_ns);
111 	put_cgroup_ns(nsproxy->cgroup_ns);
112 	nsproxy->cgroup_ns = cgroup_ns;
113 
114 	return 0;
115 }
116 
cgroupns_get(struct task_struct * task)117 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 	nsproxy = task->nsproxy;
124 	if (nsproxy) {
125 		ns = nsproxy->cgroup_ns;
126 		get_cgroup_ns(ns);
127 	}
128 	task_unlock(task);
129 
130 	return ns ? &ns->ns : NULL;
131 }
132 
cgroupns_put(struct ns_common * ns)133 static void cgroupns_put(struct ns_common *ns)
134 {
135 	put_cgroup_ns(to_cg_ns(ns));
136 }
137 
cgroupns_owner(struct ns_common * ns)138 static struct user_namespace *cgroupns_owner(struct ns_common *ns)
139 {
140 	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 
cgroup_namespaces_init(void)152 static __init int cgroup_namespaces_init(void)
153 {
154 	return 0;
155 }
156 subsys_initcall(cgroup_namespaces_init);
157