diff options
Diffstat (limited to 'kernel/nsproxy.c')
-rw-r--r-- | kernel/nsproxy.c | 62 |
1 files changed, 46 insertions, 16 deletions
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index 049e7c0ac566..79f871bc0ef4 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c | |||
@@ -26,19 +26,6 @@ static struct kmem_cache *nsproxy_cachep; | |||
26 | 26 | ||
27 | struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); | 27 | struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); |
28 | 28 | ||
29 | static inline void get_nsproxy(struct nsproxy *ns) | ||
30 | { | ||
31 | atomic_inc(&ns->count); | ||
32 | } | ||
33 | |||
34 | void get_task_namespaces(struct task_struct *tsk) | ||
35 | { | ||
36 | struct nsproxy *ns = tsk->nsproxy; | ||
37 | if (ns) { | ||
38 | get_nsproxy(ns); | ||
39 | } | ||
40 | } | ||
41 | |||
42 | /* | 29 | /* |
43 | * creates a copy of "orig" with refcount 1. | 30 | * creates a copy of "orig" with refcount 1. |
44 | */ | 31 | */ |
@@ -87,7 +74,7 @@ static struct nsproxy *create_new_namespaces(unsigned long flags, | |||
87 | goto out_ipc; | 74 | goto out_ipc; |
88 | } | 75 | } |
89 | 76 | ||
90 | new_nsp->pid_ns = copy_pid_ns(flags, tsk->nsproxy->pid_ns); | 77 | new_nsp->pid_ns = copy_pid_ns(flags, task_active_pid_ns(tsk)); |
91 | if (IS_ERR(new_nsp->pid_ns)) { | 78 | if (IS_ERR(new_nsp->pid_ns)) { |
92 | err = PTR_ERR(new_nsp->pid_ns); | 79 | err = PTR_ERR(new_nsp->pid_ns); |
93 | goto out_pid; | 80 | goto out_pid; |
@@ -142,7 +129,8 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk) | |||
142 | 129 | ||
143 | get_nsproxy(old_ns); | 130 | get_nsproxy(old_ns); |
144 | 131 | ||
145 | if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWUSER | CLONE_NEWNET))) | 132 | if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | |
133 | CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNET))) | ||
146 | return 0; | 134 | return 0; |
147 | 135 | ||
148 | if (!capable(CAP_SYS_ADMIN)) { | 136 | if (!capable(CAP_SYS_ADMIN)) { |
@@ -156,7 +144,14 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk) | |||
156 | goto out; | 144 | goto out; |
157 | } | 145 | } |
158 | 146 | ||
147 | err = ns_cgroup_clone(tsk); | ||
148 | if (err) { | ||
149 | put_nsproxy(new_ns); | ||
150 | goto out; | ||
151 | } | ||
152 | |||
159 | tsk->nsproxy = new_ns; | 153 | tsk->nsproxy = new_ns; |
154 | |||
160 | out: | 155 | out: |
161 | put_nsproxy(old_ns); | 156 | put_nsproxy(old_ns); |
162 | return err; | 157 | return err; |
@@ -196,11 +191,46 @@ int unshare_nsproxy_namespaces(unsigned long unshare_flags, | |||
196 | 191 | ||
197 | *new_nsp = create_new_namespaces(unshare_flags, current, | 192 | *new_nsp = create_new_namespaces(unshare_flags, current, |
198 | new_fs ? new_fs : current->fs); | 193 | new_fs ? new_fs : current->fs); |
199 | if (IS_ERR(*new_nsp)) | 194 | if (IS_ERR(*new_nsp)) { |
200 | err = PTR_ERR(*new_nsp); | 195 | err = PTR_ERR(*new_nsp); |
196 | goto out; | ||
197 | } | ||
198 | |||
199 | err = ns_cgroup_clone(current); | ||
200 | if (err) | ||
201 | put_nsproxy(*new_nsp); | ||
202 | |||
203 | out: | ||
201 | return err; | 204 | return err; |
202 | } | 205 | } |
203 | 206 | ||
207 | void switch_task_namespaces(struct task_struct *p, struct nsproxy *new) | ||
208 | { | ||
209 | struct nsproxy *ns; | ||
210 | |||
211 | might_sleep(); | ||
212 | |||
213 | ns = p->nsproxy; | ||
214 | |||
215 | rcu_assign_pointer(p->nsproxy, new); | ||
216 | |||
217 | if (ns && atomic_dec_and_test(&ns->count)) { | ||
218 | /* | ||
219 | * wait for others to get what they want from this nsproxy. | ||
220 | * | ||
221 | * cannot release this nsproxy via the call_rcu() since | ||
222 | * put_mnt_ns() will want to sleep | ||
223 | */ | ||
224 | synchronize_rcu(); | ||
225 | free_nsproxy(ns); | ||
226 | } | ||
227 | } | ||
228 | |||
229 | void exit_task_namespaces(struct task_struct *p) | ||
230 | { | ||
231 | switch_task_namespaces(p, NULL); | ||
232 | } | ||
233 | |||
204 | static int __init nsproxy_cache_init(void) | 234 | static int __init nsproxy_cache_init(void) |
205 | { | 235 | { |
206 | nsproxy_cachep = KMEM_CACHE(nsproxy, SLAB_PANIC); | 236 | nsproxy_cachep = KMEM_CACHE(nsproxy, SLAB_PANIC); |