Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/kernel/cgroup/namespace.c
29278 views
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
#include <linux/nstree.h>
9
10
/* cgroup namespaces */
11
12
static struct ucounts *inc_cgroup_namespaces(struct user_namespace *ns)
13
{
14
return inc_ucount(ns, current_euid(), UCOUNT_CGROUP_NAMESPACES);
15
}
16
17
static void dec_cgroup_namespaces(struct ucounts *ucounts)
18
{
19
dec_ucount(ucounts, UCOUNT_CGROUP_NAMESPACES);
20
}
21
22
static struct cgroup_namespace *alloc_cgroup_ns(void)
23
{
24
struct cgroup_namespace *new_ns __free(kfree) = NULL;
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_common_init(new_ns);
31
if (ret)
32
return ERR_PTR(ret);
33
ns_tree_add(new_ns);
34
return no_free_ptr(new_ns);
35
}
36
37
void free_cgroup_ns(struct cgroup_namespace *ns)
38
{
39
ns_tree_remove(ns);
40
put_css_set(ns->root_cset);
41
dec_cgroup_namespaces(ns->ucounts);
42
put_user_ns(ns->user_ns);
43
ns_common_free(ns);
44
/* Concurrent nstree traversal depends on a grace period. */
45
kfree_rcu(ns, ns.ns_rcu);
46
}
47
EXPORT_SYMBOL(free_cgroup_ns);
48
49
struct cgroup_namespace *copy_cgroup_ns(u64 flags,
50
struct user_namespace *user_ns,
51
struct cgroup_namespace *old_ns)
52
{
53
struct cgroup_namespace *new_ns;
54
struct ucounts *ucounts;
55
struct css_set *cset;
56
57
BUG_ON(!old_ns);
58
59
if (!(flags & CLONE_NEWCGROUP)) {
60
get_cgroup_ns(old_ns);
61
return old_ns;
62
}
63
64
/* Allow only sysadmin to create cgroup namespace. */
65
if (!ns_capable(user_ns, CAP_SYS_ADMIN))
66
return ERR_PTR(-EPERM);
67
68
ucounts = inc_cgroup_namespaces(user_ns);
69
if (!ucounts)
70
return ERR_PTR(-ENOSPC);
71
72
/* It is not safe to take cgroup_mutex here */
73
spin_lock_irq(&css_set_lock);
74
cset = task_css_set(current);
75
get_css_set(cset);
76
spin_unlock_irq(&css_set_lock);
77
78
new_ns = alloc_cgroup_ns();
79
if (IS_ERR(new_ns)) {
80
put_css_set(cset);
81
dec_cgroup_namespaces(ucounts);
82
return new_ns;
83
}
84
85
new_ns->user_ns = get_user_ns(user_ns);
86
new_ns->ucounts = ucounts;
87
new_ns->root_cset = cset;
88
89
return new_ns;
90
}
91
92
static int cgroupns_install(struct nsset *nsset, struct ns_common *ns)
93
{
94
struct nsproxy *nsproxy = nsset->nsproxy;
95
struct cgroup_namespace *cgroup_ns = to_cg_ns(ns);
96
97
if (!ns_capable(nsset->cred->user_ns, CAP_SYS_ADMIN) ||
98
!ns_capable(cgroup_ns->user_ns, CAP_SYS_ADMIN))
99
return -EPERM;
100
101
/* Don't need to do anything if we are attaching to our own cgroupns. */
102
if (cgroup_ns == nsproxy->cgroup_ns)
103
return 0;
104
105
get_cgroup_ns(cgroup_ns);
106
put_cgroup_ns(nsproxy->cgroup_ns);
107
nsproxy->cgroup_ns = cgroup_ns;
108
109
return 0;
110
}
111
112
static struct ns_common *cgroupns_get(struct task_struct *task)
113
{
114
struct cgroup_namespace *ns = NULL;
115
struct nsproxy *nsproxy;
116
117
task_lock(task);
118
nsproxy = task->nsproxy;
119
if (nsproxy) {
120
ns = nsproxy->cgroup_ns;
121
get_cgroup_ns(ns);
122
}
123
task_unlock(task);
124
125
return ns ? &ns->ns : NULL;
126
}
127
128
static void cgroupns_put(struct ns_common *ns)
129
{
130
put_cgroup_ns(to_cg_ns(ns));
131
}
132
133
static struct user_namespace *cgroupns_owner(struct ns_common *ns)
134
{
135
return to_cg_ns(ns)->user_ns;
136
}
137
138
const struct proc_ns_operations cgroupns_operations = {
139
.name = "cgroup",
140
.get = cgroupns_get,
141
.put = cgroupns_put,
142
.install = cgroupns_install,
143
.owner = cgroupns_owner,
144
};
145
146