]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - kernel/cgroup/namespace.c
UBUNTU: SAUCE: media: uvcvideo: Support realtek's UVC 1.5 device
[mirror_ubuntu-artful-kernel.git] / kernel / cgroup / namespace.c
CommitLineData
dcfe149b
TH
1#include "cgroup-internal.h"
2
56cd6973 3#include <linux/sched/task.h>
dcfe149b
TH
4#include <linux/slab.h>
5#include <linux/nsproxy.h>
6#include <linux/proc_ns.h>
7
8
9/* cgroup namespaces */
10
11static struct ucounts *inc_cgroup_namespaces(struct user_namespace *ns)
12{
13 return inc_ucount(ns, current_euid(), UCOUNT_CGROUP_NAMESPACES);
14}
15
16static void dec_cgroup_namespaces(struct ucounts *ucounts)
17{
18 dec_ucount(ucounts, UCOUNT_CGROUP_NAMESPACES);
19}
20
21static 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 }
387ad967 34 refcount_set(&new_ns->count, 1);
dcfe149b
TH
35 new_ns->ns.ops = &cgroupns_operations;
36 return new_ns;
37}
38
39void 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}
47EXPORT_SYMBOL(free_cgroup_ns);
48
49struct 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
92static inline struct cgroup_namespace *to_cg_ns(struct ns_common *ns)
93{
94 return container_of(ns, struct cgroup_namespace, ns);
95}
96
97static 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
116static 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
132static void cgroupns_put(struct ns_common *ns)
133{
134 put_cgroup_ns(to_cg_ns(ns));
135}
136
137static struct user_namespace *cgroupns_owner(struct ns_common *ns)
138{
139 return to_cg_ns(ns)->user_ns;
140}
141
142const 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
151static __init int cgroup_namespaces_init(void)
152{
153 return 0;
154}
155subsys_initcall(cgroup_namespaces_init);