66129eb4371d124f97c2a3233549be3673bd93ca
[sfrench/cifs-2.6.git] / kernel / cgroup / namespace.c
1 #include "cgroup-internal.h"
2
3 #include <linux/sched/task.h>
4 #include <linux/slab.h>
5 #include <linux/nsproxy.h>
6 #include <linux/proc_ns.h>
7
8
9 /* cgroup namespaces */
10
11 static struct ucounts *inc_cgroup_namespaces(struct user_namespace *ns)
12 {
13         return inc_ucount(ns, current_euid(), UCOUNT_CGROUP_NAMESPACES);
14 }
15
16 static void dec_cgroup_namespaces(struct ucounts *ucounts)
17 {
18         dec_ucount(ucounts, UCOUNT_CGROUP_NAMESPACES);
19 }
20
21 static struct cgroup_namespace *alloc_cgroup_ns(void)
22 {
23         struct cgroup_namespace *new_ns;
24         int ret;
25
26         new_ns = kzalloc(sizeof(struct cgroup_namespace), GFP_KERNEL);
27         if (!new_ns)
28                 return ERR_PTR(-ENOMEM);
29         ret = ns_alloc_inum(&new_ns->ns);
30         if (ret) {
31                 kfree(new_ns);
32                 return ERR_PTR(ret);
33         }
34         refcount_set(&new_ns->count, 1);
35         new_ns->ns.ops = &cgroupns_operations;
36         return new_ns;
37 }
38
39 void free_cgroup_ns(struct cgroup_namespace *ns)
40 {
41         put_css_set(ns->root_cset);
42         dec_cgroup_namespaces(ns->ucounts);
43         put_user_ns(ns->user_ns);
44         ns_free_inum(&ns->ns);
45         kfree(ns);
46 }
47 EXPORT_SYMBOL(free_cgroup_ns);
48
49 struct cgroup_namespace *copy_cgroup_ns(unsigned long 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 inline struct cgroup_namespace *to_cg_ns(struct ns_common *ns)
93 {
94         return container_of(ns, struct cgroup_namespace, ns);
95 }
96
97 static int cgroupns_install(struct nsproxy *nsproxy, struct ns_common *ns)
98 {
99         struct cgroup_namespace *cgroup_ns = to_cg_ns(ns);
100
101         if (!ns_capable(current_user_ns(), CAP_SYS_ADMIN) ||
102             !ns_capable(cgroup_ns->user_ns, CAP_SYS_ADMIN))
103                 return -EPERM;
104
105         /* Don't need to do anything if we are attaching to our own cgroupns. */
106         if (cgroup_ns == nsproxy->cgroup_ns)
107                 return 0;
108
109         get_cgroup_ns(cgroup_ns);
110         put_cgroup_ns(nsproxy->cgroup_ns);
111         nsproxy->cgroup_ns = cgroup_ns;
112
113         return 0;
114 }
115
116 static struct ns_common *cgroupns_get(struct task_struct *task)
117 {
118         struct cgroup_namespace *ns = NULL;
119         struct nsproxy *nsproxy;
120
121         task_lock(task);
122         nsproxy = task->nsproxy;
123         if (nsproxy) {
124                 ns = nsproxy->cgroup_ns;
125                 get_cgroup_ns(ns);
126         }
127         task_unlock(task);
128
129         return ns ? &ns->ns : NULL;
130 }
131
132 static void cgroupns_put(struct ns_common *ns)
133 {
134         put_cgroup_ns(to_cg_ns(ns));
135 }
136
137 static struct user_namespace *cgroupns_owner(struct ns_common *ns)
138 {
139         return to_cg_ns(ns)->user_ns;
140 }
141
142 const struct proc_ns_operations cgroupns_operations = {
143         .name           = "cgroup",
144         .type           = CLONE_NEWCGROUP,
145         .get            = cgroupns_get,
146         .put            = cgroupns_put,
147         .install        = cgroupns_install,
148         .owner          = cgroupns_owner,
149 };
150
151 static __init int cgroup_namespaces_init(void)
152 {
153         return 0;
154 }
155 subsys_initcall(cgroup_namespaces_init);