Blame view

kernel/nsproxy.c 12.9 KB
b886d83c5   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
ab516013a   Serge E. Hallyn   [PATCH] namespace...
2
3
4
5
6
  /*
   *  Copyright (C) 2006 IBM Corporation
   *
   *  Author: Serge Hallyn <serue@us.ibm.com>
   *
25b21cb2f   Kirill Korotaev   [PATCH] IPC names...
7
8
9
   *  Jun 2006 - namespaces support
   *             OpenVZ, SWsoft Inc.
   *             Pavel Emelianov <xemul@openvz.org>
ab516013a   Serge E. Hallyn   [PATCH] namespace...
10
   */
5a0e3ad6a   Tejun Heo   include cleanup: ...
11
  #include <linux/slab.h>
9984de1a5   Paul Gortmaker   kernel: Map most ...
12
  #include <linux/export.h>
ab516013a   Serge E. Hallyn   [PATCH] namespace...
13
  #include <linux/nsproxy.h>
0437eb594   Serge E. Hallyn   [PATCH] nsproxy: ...
14
  #include <linux/init_task.h>
6b3286ed1   Kirill Korotaev   [PATCH] rename st...
15
  #include <linux/mnt_namespace.h>
4865ecf13   Serge E. Hallyn   [PATCH] namespace...
16
  #include <linux/utsname.h>
9a575a92d   Cedric Le Goater   [PATCH] to nsproxy
17
  #include <linux/pid_namespace.h>
9dd776b6d   Eric W. Biederman   [NET]: Add networ...
18
  #include <net/net_namespace.h>
ae5e1b22f   Pavel Emelyanov   namespaces: move ...
19
  #include <linux/ipc_namespace.h>
769071ac9   Andrei Vagin   ns: Introduce Tim...
20
  #include <linux/time_namespace.h>
f2a8d52e0   Christian Brauner   nsproxy: add stru...
21
  #include <linux/fs_struct.h>
303cc571d   Christian Brauner   nsproxy: attach t...
22
  #include <linux/proc_fs.h>
0bb80f240   David Howells   proc: Split the n...
23
  #include <linux/proc_ns.h>
0663c6f8f   Eric W. Biederman   ns: Introduce the...
24
25
  #include <linux/file.h>
  #include <linux/syscalls.h>
a79a908fd   Aditya Kali   cgroup: introduce...
26
  #include <linux/cgroup.h>
e42226732   Hari Bathini   perf: Add PERF_RE...
27
  #include <linux/perf_event.h>
0437eb594   Serge E. Hallyn   [PATCH] nsproxy: ...
28

98c0d07cb   Cedric Le Goater   add a kmem_cache ...
29
  static struct kmem_cache *nsproxy_cachep;
8467005da   Alexey Dobriyan   nsproxy: remove I...
30
  struct nsproxy init_nsproxy = {
c2b1df2eb   Andy Lutomirski   Rename nsproxy.pi...
31
32
  	.count			= ATOMIC_INIT(1),
  	.uts_ns			= &init_uts_ns,
8467005da   Alexey Dobriyan   nsproxy: remove I...
33
  #if defined(CONFIG_POSIX_MQUEUE) || defined(CONFIG_SYSVIPC)
c2b1df2eb   Andy Lutomirski   Rename nsproxy.pi...
34
  	.ipc_ns			= &init_ipc_ns,
8467005da   Alexey Dobriyan   nsproxy: remove I...
35
  #endif
c2b1df2eb   Andy Lutomirski   Rename nsproxy.pi...
36
37
  	.mnt_ns			= NULL,
  	.pid_ns_for_children	= &init_pid_ns,
8467005da   Alexey Dobriyan   nsproxy: remove I...
38
  #ifdef CONFIG_NET
c2b1df2eb   Andy Lutomirski   Rename nsproxy.pi...
39
  	.net_ns			= &init_net,
8467005da   Alexey Dobriyan   nsproxy: remove I...
40
  #endif
a79a908fd   Aditya Kali   cgroup: introduce...
41
42
43
  #ifdef CONFIG_CGROUPS
  	.cgroup_ns		= &init_cgroup_ns,
  #endif
769071ac9   Andrei Vagin   ns: Introduce Tim...
44
45
46
47
  #ifdef CONFIG_TIME_NS
  	.time_ns		= &init_time_ns,
  	.time_ns_for_children	= &init_time_ns,
  #endif
8467005da   Alexey Dobriyan   nsproxy: remove I...
48
  };
ab516013a   Serge E. Hallyn   [PATCH] namespace...
49

90af90d7d   Alexey Dobriyan   nsproxy: extract ...
50
  static inline struct nsproxy *create_nsproxy(void)
ab516013a   Serge E. Hallyn   [PATCH] namespace...
51
  {
90af90d7d   Alexey Dobriyan   nsproxy: extract ...
52
  	struct nsproxy *nsproxy;
ab516013a   Serge E. Hallyn   [PATCH] namespace...
53

90af90d7d   Alexey Dobriyan   nsproxy: extract ...
54
55
56
57
  	nsproxy = kmem_cache_alloc(nsproxy_cachep, GFP_KERNEL);
  	if (nsproxy)
  		atomic_set(&nsproxy->count, 1);
  	return nsproxy;
ab516013a   Serge E. Hallyn   [PATCH] namespace...
58
59
60
  }
  
  /*
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
61
62
63
   * Create new nsproxy and all of its the associated namespaces.
   * Return the newly created nsproxy.  Do not attach this to the task,
   * leave it to the caller to do proper locking and attach it to task.
ab516013a   Serge E. Hallyn   [PATCH] namespace...
64
   */
213dd266d   Eric W. Biederman   namespace: ensure...
65
  static struct nsproxy *create_new_namespaces(unsigned long flags,
bcf58e725   Eric W. Biederman   userns: Make crea...
66
67
  	struct task_struct *tsk, struct user_namespace *user_ns,
  	struct fs_struct *new_fs)
ab516013a   Serge E. Hallyn   [PATCH] namespace...
68
  {
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
69
  	struct nsproxy *new_nsp;
467e9f4b5   Cedric Le Goater   fix create_new_na...
70
  	int err;
ab516013a   Serge E. Hallyn   [PATCH] namespace...
71

90af90d7d   Alexey Dobriyan   nsproxy: extract ...
72
  	new_nsp = create_nsproxy();
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
73
74
  	if (!new_nsp)
  		return ERR_PTR(-ENOMEM);
1651e14e2   Serge E. Hallyn   [PATCH] namespace...
75

bcf58e725   Eric W. Biederman   userns: Make crea...
76
  	new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, user_ns, new_fs);
467e9f4b5   Cedric Le Goater   fix create_new_na...
77
78
  	if (IS_ERR(new_nsp->mnt_ns)) {
  		err = PTR_ERR(new_nsp->mnt_ns);
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
79
  		goto out_ns;
467e9f4b5   Cedric Le Goater   fix create_new_na...
80
  	}
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
81

bcf58e725   Eric W. Biederman   userns: Make crea...
82
  	new_nsp->uts_ns = copy_utsname(flags, user_ns, tsk->nsproxy->uts_ns);
467e9f4b5   Cedric Le Goater   fix create_new_na...
83
84
  	if (IS_ERR(new_nsp->uts_ns)) {
  		err = PTR_ERR(new_nsp->uts_ns);
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
85
  		goto out_uts;
467e9f4b5   Cedric Le Goater   fix create_new_na...
86
  	}
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
87

bcf58e725   Eric W. Biederman   userns: Make crea...
88
  	new_nsp->ipc_ns = copy_ipcs(flags, user_ns, tsk->nsproxy->ipc_ns);
467e9f4b5   Cedric Le Goater   fix create_new_na...
89
90
  	if (IS_ERR(new_nsp->ipc_ns)) {
  		err = PTR_ERR(new_nsp->ipc_ns);
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
91
  		goto out_ipc;
467e9f4b5   Cedric Le Goater   fix create_new_na...
92
  	}
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
93

c2b1df2eb   Andy Lutomirski   Rename nsproxy.pi...
94
95
96
97
  	new_nsp->pid_ns_for_children =
  		copy_pid_ns(flags, user_ns, tsk->nsproxy->pid_ns_for_children);
  	if (IS_ERR(new_nsp->pid_ns_for_children)) {
  		err = PTR_ERR(new_nsp->pid_ns_for_children);
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
98
  		goto out_pid;
467e9f4b5   Cedric Le Goater   fix create_new_na...
99
  	}
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
100

a79a908fd   Aditya Kali   cgroup: introduce...
101
102
103
104
105
106
  	new_nsp->cgroup_ns = copy_cgroup_ns(flags, user_ns,
  					    tsk->nsproxy->cgroup_ns);
  	if (IS_ERR(new_nsp->cgroup_ns)) {
  		err = PTR_ERR(new_nsp->cgroup_ns);
  		goto out_cgroup;
  	}
bcf58e725   Eric W. Biederman   userns: Make crea...
107
  	new_nsp->net_ns = copy_net_ns(flags, user_ns, tsk->nsproxy->net_ns);
9dd776b6d   Eric W. Biederman   [NET]: Add networ...
108
109
110
111
  	if (IS_ERR(new_nsp->net_ns)) {
  		err = PTR_ERR(new_nsp->net_ns);
  		goto out_net;
  	}
769071ac9   Andrei Vagin   ns: Introduce Tim...
112
113
114
115
116
117
118
  	new_nsp->time_ns_for_children = copy_time_ns(flags, user_ns,
  					tsk->nsproxy->time_ns_for_children);
  	if (IS_ERR(new_nsp->time_ns_for_children)) {
  		err = PTR_ERR(new_nsp->time_ns_for_children);
  		goto out_time;
  	}
  	new_nsp->time_ns = get_time_ns(tsk->nsproxy->time_ns);
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
119
  	return new_nsp;
769071ac9   Andrei Vagin   ns: Introduce Tim...
120
121
  out_time:
  	put_net(new_nsp->net_ns);
9dd776b6d   Eric W. Biederman   [NET]: Add networ...
122
  out_net:
a79a908fd   Aditya Kali   cgroup: introduce...
123
124
  	put_cgroup_ns(new_nsp->cgroup_ns);
  out_cgroup:
c2b1df2eb   Andy Lutomirski   Rename nsproxy.pi...
125
126
  	if (new_nsp->pid_ns_for_children)
  		put_pid_ns(new_nsp->pid_ns_for_children);
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
127
128
129
130
131
132
133
134
135
136
  out_pid:
  	if (new_nsp->ipc_ns)
  		put_ipc_ns(new_nsp->ipc_ns);
  out_ipc:
  	if (new_nsp->uts_ns)
  		put_uts_ns(new_nsp->uts_ns);
  out_uts:
  	if (new_nsp->mnt_ns)
  		put_mnt_ns(new_nsp->mnt_ns);
  out_ns:
98c0d07cb   Cedric Le Goater   add a kmem_cache ...
137
  	kmem_cache_free(nsproxy_cachep, new_nsp);
467e9f4b5   Cedric Le Goater   fix create_new_na...
138
  	return ERR_PTR(err);
ab516013a   Serge E. Hallyn   [PATCH] namespace...
139
140
141
142
143
144
  }
  
  /*
   * called from clone.  This now handles copy for nsproxy and all
   * namespaces therein.
   */
213dd266d   Eric W. Biederman   namespace: ensure...
145
  int copy_namespaces(unsigned long flags, struct task_struct *tsk)
ab516013a   Serge E. Hallyn   [PATCH] namespace...
146
147
  {
  	struct nsproxy *old_ns = tsk->nsproxy;
b33c77ef2   Eric W. Biederman   userns: Allow unp...
148
  	struct user_namespace *user_ns = task_cred_xxx(tsk, user_ns);
1651e14e2   Serge E. Hallyn   [PATCH] namespace...
149
  	struct nsproxy *new_ns;
769071ac9   Andrei Vagin   ns: Introduce Tim...
150
  	int ret;
ab516013a   Serge E. Hallyn   [PATCH] namespace...
151

dbef0c1c4   Eric W. Biederman   namespaces: Simpl...
152
  	if (likely(!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
a79a908fd   Aditya Kali   cgroup: introduce...
153
  			      CLONE_NEWPID | CLONE_NEWNET |
769071ac9   Andrei Vagin   ns: Introduce Tim...
154
155
156
157
158
159
  			      CLONE_NEWCGROUP | CLONE_NEWTIME)))) {
  		if (likely(old_ns->time_ns_for_children == old_ns->time_ns)) {
  			get_nsproxy(old_ns);
  			return 0;
  		}
  	} else if (!ns_capable(user_ns, CAP_SYS_ADMIN))
dbef0c1c4   Eric W. Biederman   namespaces: Simpl...
160
  		return -EPERM;
02fdb36ae   Serge E. Hallyn   ipc: sysvsem: ref...
161
162
163
164
165
166
167
  	/*
  	 * CLONE_NEWIPC must detach from the undolist: after switching
  	 * to a new ipc namespace, the semaphore arrays from the old
  	 * namespace are unreachable.  In clone parlance, CLONE_SYSVSEM
  	 * means share undolist with parent, so we must forbid using
  	 * it along with CLONE_NEWIPC.
  	 */
21e851943   Raphael S.Carvalho   kernel/nsproxy.c:...
168
  	if ((flags & (CLONE_NEWIPC | CLONE_SYSVSEM)) ==
dbef0c1c4   Eric W. Biederman   namespaces: Simpl...
169
170
  		(CLONE_NEWIPC | CLONE_SYSVSEM)) 
  		return -EINVAL;
02fdb36ae   Serge E. Hallyn   ipc: sysvsem: ref...
171

d7d48f621   Yuanhan Liu   kernel/nsproxy.c:...
172
  	new_ns = create_new_namespaces(flags, tsk, user_ns, tsk->fs);
dbef0c1c4   Eric W. Biederman   namespaces: Simpl...
173
174
  	if (IS_ERR(new_ns))
  		return  PTR_ERR(new_ns);
9a575a92d   Cedric Le Goater   [PATCH] to nsproxy
175

769071ac9   Andrei Vagin   ns: Introduce Tim...
176
177
178
179
180
  	ret = timens_on_fork(new_ns, tsk);
  	if (ret) {
  		free_nsproxy(new_ns);
  		return ret;
  	}
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
181
  	tsk->nsproxy = new_ns;
dbef0c1c4   Eric W. Biederman   namespaces: Simpl...
182
  	return 0;
ab516013a   Serge E. Hallyn   [PATCH] namespace...
183
184
185
186
  }
  
  void free_nsproxy(struct nsproxy *ns)
  {
9a575a92d   Cedric Le Goater   [PATCH] to nsproxy
187
188
189
190
191
192
  	if (ns->mnt_ns)
  		put_mnt_ns(ns->mnt_ns);
  	if (ns->uts_ns)
  		put_uts_ns(ns->uts_ns);
  	if (ns->ipc_ns)
  		put_ipc_ns(ns->ipc_ns);
c2b1df2eb   Andy Lutomirski   Rename nsproxy.pi...
193
194
  	if (ns->pid_ns_for_children)
  		put_pid_ns(ns->pid_ns_for_children);
769071ac9   Andrei Vagin   ns: Introduce Tim...
195
196
197
198
  	if (ns->time_ns)
  		put_time_ns(ns->time_ns);
  	if (ns->time_ns_for_children)
  		put_time_ns(ns->time_ns_for_children);
a79a908fd   Aditya Kali   cgroup: introduce...
199
  	put_cgroup_ns(ns->cgroup_ns);
9dd776b6d   Eric W. Biederman   [NET]: Add networ...
200
  	put_net(ns->net_ns);
98c0d07cb   Cedric Le Goater   add a kmem_cache ...
201
  	kmem_cache_free(nsproxy_cachep, ns);
ab516013a   Serge E. Hallyn   [PATCH] namespace...
202
  }
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
203
204
205
  
  /*
   * Called from unshare. Unshare all the namespaces part of nsproxy.
4e71e474c   Cedric Le Goater   fix refcounting o...
206
   * On success, returns the new nsproxy.
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
207
208
   */
  int unshare_nsproxy_namespaces(unsigned long unshare_flags,
b2e0d9870   Eric W. Biederman   userns: Implement...
209
  	struct nsproxy **new_nsp, struct cred *new_cred, struct fs_struct *new_fs)
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
210
  {
bcf58e725   Eric W. Biederman   userns: Make crea...
211
  	struct user_namespace *user_ns;
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
212
  	int err = 0;
77ec739d8   Serge E. Hallyn   user namespace: a...
213
  	if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
769071ac9   Andrei Vagin   ns: Introduce Tim...
214
215
  			       CLONE_NEWNET | CLONE_NEWPID | CLONE_NEWCGROUP |
  			       CLONE_NEWTIME)))
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
216
  		return 0;
b2e0d9870   Eric W. Biederman   userns: Implement...
217
218
  	user_ns = new_cred ? new_cred->user_ns : current_user_ns();
  	if (!ns_capable(user_ns, CAP_SYS_ADMIN))
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
219
  		return -EPERM;
bcf58e725   Eric W. Biederman   userns: Make crea...
220
  	*new_nsp = create_new_namespaces(unshare_flags, current, user_ns,
b2e0d9870   Eric W. Biederman   userns: Implement...
221
  					 new_fs ? new_fs : current->fs);
858d72ead   Serge E. Hallyn   cgroups: implemen...
222
  	if (IS_ERR(*new_nsp)) {
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
223
  		err = PTR_ERR(*new_nsp);
858d72ead   Serge E. Hallyn   cgroups: implemen...
224
225
  		goto out;
  	}
858d72ead   Serge E. Hallyn   cgroups: implemen...
226
  out:
e3222c4ec   Badari Pulavarty   Merge sys_clone()...
227
228
  	return err;
  }
98c0d07cb   Cedric Le Goater   add a kmem_cache ...
229

cf7b708c8   Pavel Emelyanov   Make access to ta...
230
231
232
233
234
  void switch_task_namespaces(struct task_struct *p, struct nsproxy *new)
  {
  	struct nsproxy *ns;
  
  	might_sleep();
728dba3a3   Eric W. Biederman   namespaces: Use t...
235
  	task_lock(p);
cf7b708c8   Pavel Emelyanov   Make access to ta...
236
  	ns = p->nsproxy;
728dba3a3   Eric W. Biederman   namespaces: Use t...
237
238
  	p->nsproxy = new;
  	task_unlock(p);
cf7b708c8   Pavel Emelyanov   Make access to ta...
239

728dba3a3   Eric W. Biederman   namespaces: Use t...
240
  	if (ns && atomic_dec_and_test(&ns->count))
cf7b708c8   Pavel Emelyanov   Make access to ta...
241
  		free_nsproxy(ns);
cf7b708c8   Pavel Emelyanov   Make access to ta...
242
243
244
245
246
247
  }
  
  void exit_task_namespaces(struct task_struct *p)
  {
  	switch_task_namespaces(p, NULL);
  }
303cc571d   Christian Brauner   nsproxy: attach t...
248
249
250
  static int check_setns_flags(unsigned long flags)
  {
  	if (!flags || (flags & ~(CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
76c12881a   Christian Brauner   nsproxy: support ...
251
252
  				 CLONE_NEWNET | CLONE_NEWTIME | CLONE_NEWUSER |
  				 CLONE_NEWPID | CLONE_NEWCGROUP)))
303cc571d   Christian Brauner   nsproxy: attach t...
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
  		return -EINVAL;
  
  #ifndef CONFIG_USER_NS
  	if (flags & CLONE_NEWUSER)
  		return -EINVAL;
  #endif
  #ifndef CONFIG_PID_NS
  	if (flags & CLONE_NEWPID)
  		return -EINVAL;
  #endif
  #ifndef CONFIG_UTS_NS
  	if (flags & CLONE_NEWUTS)
  		return -EINVAL;
  #endif
  #ifndef CONFIG_IPC_NS
  	if (flags & CLONE_NEWIPC)
  		return -EINVAL;
  #endif
  #ifndef CONFIG_CGROUPS
  	if (flags & CLONE_NEWCGROUP)
  		return -EINVAL;
  #endif
  #ifndef CONFIG_NET_NS
  	if (flags & CLONE_NEWNET)
  		return -EINVAL;
  #endif
76c12881a   Christian Brauner   nsproxy: support ...
279
280
281
282
  #ifndef CONFIG_TIME_NS
  	if (flags & CLONE_NEWTIME)
  		return -EINVAL;
  #endif
303cc571d   Christian Brauner   nsproxy: attach t...
283
284
285
  
  	return 0;
  }
f2a8d52e0   Christian Brauner   nsproxy: add stru...
286
287
288
289
290
291
  static void put_nsset(struct nsset *nsset)
  {
  	unsigned flags = nsset->flags;
  
  	if (flags & CLONE_NEWUSER)
  		put_cred(nsset_cred(nsset));
303cc571d   Christian Brauner   nsproxy: attach t...
292
293
294
295
296
297
  	/*
  	 * We only created a temporary copy if we attached to more than just
  	 * the mount namespace.
  	 */
  	if (nsset->fs && (flags & CLONE_NEWNS) && (flags & ~CLONE_NEWNS))
  		free_fs_struct(nsset->fs);
f2a8d52e0   Christian Brauner   nsproxy: add stru...
298
299
300
  	if (nsset->nsproxy)
  		free_nsproxy(nsset->nsproxy);
  }
303cc571d   Christian Brauner   nsproxy: attach t...
301
  static int prepare_nsset(unsigned flags, struct nsset *nsset)
f2a8d52e0   Christian Brauner   nsproxy: add stru...
302
303
304
305
306
307
  {
  	struct task_struct *me = current;
  
  	nsset->nsproxy = create_new_namespaces(0, me, current_user_ns(), me->fs);
  	if (IS_ERR(nsset->nsproxy))
  		return PTR_ERR(nsset->nsproxy);
303cc571d   Christian Brauner   nsproxy: attach t...
308
  	if (flags & CLONE_NEWUSER)
f2a8d52e0   Christian Brauner   nsproxy: add stru...
309
310
311
312
313
  		nsset->cred = prepare_creds();
  	else
  		nsset->cred = current_cred();
  	if (!nsset->cred)
  		goto out;
303cc571d   Christian Brauner   nsproxy: attach t...
314
315
  	/* Only create a temporary copy of fs_struct if we really need to. */
  	if (flags == CLONE_NEWNS) {
f2a8d52e0   Christian Brauner   nsproxy: add stru...
316
  		nsset->fs = me->fs;
303cc571d   Christian Brauner   nsproxy: attach t...
317
318
319
320
321
  	} else if (flags & CLONE_NEWNS) {
  		nsset->fs = copy_fs_struct(me->fs);
  		if (!nsset->fs)
  			goto out;
  	}
f2a8d52e0   Christian Brauner   nsproxy: add stru...
322

303cc571d   Christian Brauner   nsproxy: attach t...
323
  	nsset->flags = flags;
f2a8d52e0   Christian Brauner   nsproxy: add stru...
324
325
326
327
328
329
  	return 0;
  
  out:
  	put_nsset(nsset);
  	return -ENOMEM;
  }
303cc571d   Christian Brauner   nsproxy: attach t...
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
  static inline int validate_ns(struct nsset *nsset, struct ns_common *ns)
  {
  	return ns->ops->install(nsset, ns);
  }
  
  /*
   * This is the inverse operation to unshare().
   * Ordering is equivalent to the standard ordering used everywhere else
   * during unshare and process creation. The switch to the new set of
   * namespaces occurs at the point of no return after installation of
   * all requested namespaces was successful in commit_nsset().
   */
  static int validate_nsset(struct nsset *nsset, struct pid *pid)
  {
  	int ret = 0;
  	unsigned flags = nsset->flags;
  	struct user_namespace *user_ns = NULL;
  	struct pid_namespace *pid_ns = NULL;
  	struct nsproxy *nsp;
  	struct task_struct *tsk;
  
  	/* Take a "snapshot" of the target task's namespaces. */
  	rcu_read_lock();
  	tsk = pid_task(pid, PIDTYPE_PID);
  	if (!tsk) {
  		rcu_read_unlock();
  		return -ESRCH;
  	}
  
  	if (!ptrace_may_access(tsk, PTRACE_MODE_READ_REALCREDS)) {
  		rcu_read_unlock();
  		return -EPERM;
  	}
  
  	task_lock(tsk);
  	nsp = tsk->nsproxy;
  	if (nsp)
  		get_nsproxy(nsp);
  	task_unlock(tsk);
  	if (!nsp) {
  		rcu_read_unlock();
  		return -ESRCH;
  	}
  
  #ifdef CONFIG_PID_NS
  	if (flags & CLONE_NEWPID) {
  		pid_ns = task_active_pid_ns(tsk);
  		if (unlikely(!pid_ns)) {
  			rcu_read_unlock();
  			ret = -ESRCH;
  			goto out;
  		}
  		get_pid_ns(pid_ns);
  	}
  #endif
  
  #ifdef CONFIG_USER_NS
  	if (flags & CLONE_NEWUSER)
  		user_ns = get_user_ns(__task_cred(tsk)->user_ns);
  #endif
  	rcu_read_unlock();
  
  	/*
  	 * Install requested namespaces. The caller will have
  	 * verified earlier that the requested namespaces are
  	 * supported on this kernel. We don't report errors here
  	 * if a namespace is requested that isn't supported.
  	 */
  #ifdef CONFIG_USER_NS
  	if (flags & CLONE_NEWUSER) {
  		ret = validate_ns(nsset, &user_ns->ns);
  		if (ret)
  			goto out;
  	}
  #endif
  
  	if (flags & CLONE_NEWNS) {
  		ret = validate_ns(nsset, from_mnt_ns(nsp->mnt_ns));
  		if (ret)
  			goto out;
  	}
  
  #ifdef CONFIG_UTS_NS
  	if (flags & CLONE_NEWUTS) {
  		ret = validate_ns(nsset, &nsp->uts_ns->ns);
  		if (ret)
  			goto out;
  	}
  #endif
  
  #ifdef CONFIG_IPC_NS
  	if (flags & CLONE_NEWIPC) {
  		ret = validate_ns(nsset, &nsp->ipc_ns->ns);
  		if (ret)
  			goto out;
  	}
  #endif
  
  #ifdef CONFIG_PID_NS
  	if (flags & CLONE_NEWPID) {
  		ret = validate_ns(nsset, &pid_ns->ns);
  		if (ret)
  			goto out;
  	}
  #endif
  
  #ifdef CONFIG_CGROUPS
  	if (flags & CLONE_NEWCGROUP) {
  		ret = validate_ns(nsset, &nsp->cgroup_ns->ns);
  		if (ret)
  			goto out;
  	}
  #endif
  
  #ifdef CONFIG_NET_NS
  	if (flags & CLONE_NEWNET) {
  		ret = validate_ns(nsset, &nsp->net_ns->ns);
  		if (ret)
  			goto out;
  	}
  #endif
76c12881a   Christian Brauner   nsproxy: support ...
451
452
453
454
455
456
457
  #ifdef CONFIG_TIME_NS
  	if (flags & CLONE_NEWTIME) {
  		ret = validate_ns(nsset, &nsp->time_ns->ns);
  		if (ret)
  			goto out;
  	}
  #endif
303cc571d   Christian Brauner   nsproxy: attach t...
458
459
460
461
462
463
464
465
466
  out:
  	if (pid_ns)
  		put_pid_ns(pid_ns);
  	if (nsp)
  		put_nsproxy(nsp);
  	put_user_ns(user_ns);
  
  	return ret;
  }
f2a8d52e0   Christian Brauner   nsproxy: add stru...
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
  /*
   * This is the point of no return. There are just a few namespaces
   * that do some actual work here and it's sufficiently minimal that
   * a separate ns_common operation seems unnecessary for now.
   * Unshare is doing the same thing. If we'll end up needing to do
   * more in a given namespace or a helper here is ultimately not
   * exported anymore a simple commit handler for each namespace
   * should be added to ns_common.
   */
  static void commit_nsset(struct nsset *nsset)
  {
  	unsigned flags = nsset->flags;
  	struct task_struct *me = current;
  
  #ifdef CONFIG_USER_NS
  	if (flags & CLONE_NEWUSER) {
  		/* transfer ownership */
  		commit_creds(nsset_cred(nsset));
  		nsset->cred = NULL;
  	}
  #endif
303cc571d   Christian Brauner   nsproxy: attach t...
488
489
490
491
492
  	/* We only need to commit if we have used a temporary fs_struct. */
  	if ((flags & CLONE_NEWNS) && (flags & ~CLONE_NEWNS)) {
  		set_fs_root(me->fs, &nsset->fs->root);
  		set_fs_pwd(me->fs, &nsset->fs->pwd);
  	}
f2a8d52e0   Christian Brauner   nsproxy: add stru...
493
494
495
496
  #ifdef CONFIG_IPC_NS
  	if (flags & CLONE_NEWIPC)
  		exit_sem(me);
  #endif
76c12881a   Christian Brauner   nsproxy: support ...
497
498
499
500
  #ifdef CONFIG_TIME_NS
  	if (flags & CLONE_NEWTIME)
  		timens_commit(me, nsset->nsproxy->time_ns);
  #endif
f2a8d52e0   Christian Brauner   nsproxy: add stru...
501
502
503
504
  	/* transfer ownership */
  	switch_task_namespaces(me, nsset->nsproxy);
  	nsset->nsproxy = NULL;
  }
303cc571d   Christian Brauner   nsproxy: attach t...
505
  SYSCALL_DEFINE2(setns, int, fd, int, flags)
0663c6f8f   Eric W. Biederman   ns: Introduce the...
506
  {
0663c6f8f   Eric W. Biederman   ns: Introduce the...
507
  	struct file *file;
303cc571d   Christian Brauner   nsproxy: attach t...
508
  	struct ns_common *ns = NULL;
f2a8d52e0   Christian Brauner   nsproxy: add stru...
509
  	struct nsset nsset = {};
303cc571d   Christian Brauner   nsproxy: attach t...
510
  	int err = 0;
0663c6f8f   Eric W. Biederman   ns: Introduce the...
511

303cc571d   Christian Brauner   nsproxy: attach t...
512
513
514
515
516
517
518
519
520
521
522
523
  	file = fget(fd);
  	if (!file)
  		return -EBADF;
  
  	if (proc_ns_file(file)) {
  		ns = get_proc_ns(file_inode(file));
  		if (flags && (ns->ops->type != flags))
  			err = -EINVAL;
  		flags = ns->ops->type;
  	} else if (!IS_ERR(pidfd_pid(file))) {
  		err = check_setns_flags(flags);
  	} else {
e571d4ee3   Christian Brauner   nsproxy: restore ...
524
  		err = -EINVAL;
303cc571d   Christian Brauner   nsproxy: attach t...
525
526
  	}
  	if (err)
0663c6f8f   Eric W. Biederman   ns: Introduce the...
527
  		goto out;
303cc571d   Christian Brauner   nsproxy: attach t...
528
  	err = prepare_nsset(flags, &nsset);
f2a8d52e0   Christian Brauner   nsproxy: add stru...
529
  	if (err)
0663c6f8f   Eric W. Biederman   ns: Introduce the...
530
  		goto out;
0663c6f8f   Eric W. Biederman   ns: Introduce the...
531

303cc571d   Christian Brauner   nsproxy: attach t...
532
533
534
535
  	if (proc_ns_file(file))
  		err = validate_ns(&nsset, ns);
  	else
  		err = validate_nsset(&nsset, file->private_data);
f2a8d52e0   Christian Brauner   nsproxy: add stru...
536
537
538
  	if (!err) {
  		commit_nsset(&nsset);
  		perf_event_namespaces(current);
0663c6f8f   Eric W. Biederman   ns: Introduce the...
539
  	}
f2a8d52e0   Christian Brauner   nsproxy: add stru...
540
  	put_nsset(&nsset);
0663c6f8f   Eric W. Biederman   ns: Introduce the...
541
542
543
544
  out:
  	fput(file);
  	return err;
  }
665771939   Al Viro   make sure that ns...
545
  int __init nsproxy_cache_init(void)
98c0d07cb   Cedric Le Goater   add a kmem_cache ...
546
  {
db8906da5   Pavel Emelyanov   Use KMEM_CACHE ma...
547
  	nsproxy_cachep = KMEM_CACHE(nsproxy, SLAB_PANIC);
98c0d07cb   Cedric Le Goater   add a kmem_cache ...
548
549
  	return 0;
  }