Merge remote-tracking branch 'spi/for-5.7' into spi-linus
[linux-2.6-microblaze.git] / kernel / cgroup / namespace.c
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
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;
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
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
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
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
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
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
133 static void cgroupns_put(struct ns_common *ns)
134 {
135         put_cgroup_ns(to_cg_ns(ns));
136 }
137
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
152 static __init int cgroup_namespaces_init(void)
153 {
154         return 0;
155 }
156 subsys_initcall(cgroup_namespaces_init);