• 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