Blame view

net/core/net_namespace.c 32.4 KB
457c89965   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
e005d193d   Joe Perches   net: core: Use pr...
2
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
5f256becd   Eric W. Biederman   [NET]: Basic netw...
3
4
5
6
7
8
  #include <linux/workqueue.h>
  #include <linux/rtnetlink.h>
  #include <linux/cache.h>
  #include <linux/slab.h>
  #include <linux/list.h>
  #include <linux/delay.h>
9dd776b6d   Eric W. Biederman   [NET]: Add networ...
9
  #include <linux/sched.h>
c93cf61fd   Pavel Emelyanov   [NETNS]: The net-...
10
  #include <linux/idr.h>
11a28d373   Johannes Berg   net: make namespa...
11
  #include <linux/rculist.h>
30ffee848   Johannes Berg   net: move and exp...
12
  #include <linux/nsproxy.h>
0bb80f240   David Howells   proc: Split the n...
13
14
  #include <linux/fs.h>
  #include <linux/proc_ns.h>
f06305294   Eric W. Biederman   net: Allow settin...
15
  #include <linux/file.h>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
16
  #include <linux/export.h>
038e7332b   Eric W. Biederman   userns: make each...
17
  #include <linux/user_namespace.h>
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
18
  #include <linux/net_namespace.h>
f719ff9bc   Ingo Molnar   sched/headers: Pr...
19
  #include <linux/sched/task.h>
fbdeaed40   Tyler Hicks   net: create reusa...
20
  #include <linux/uidgid.h>
92acdc58a   Daniel Borkmann   bpf, net: Rework ...
21
  #include <linux/cookie.h>
f719ff9bc   Ingo Molnar   sched/headers: Pr...
22

0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
23
24
  #include <net/sock.h>
  #include <net/netlink.h>
5f256becd   Eric W. Biederman   [NET]: Basic netw...
25
  #include <net/net_namespace.h>
dec827d17   Pavel Emelyanov   [NETNS]: The gene...
26
  #include <net/netns/generic.h>
5f256becd   Eric W. Biederman   [NET]: Basic netw...
27
28
29
30
31
32
33
  
  /*
   *	Our network namespace constructor/destructor lists
   */
  
  static LIST_HEAD(pernet_list);
  static struct list_head *first_device = &pernet_list;
5f256becd   Eric W. Biederman   [NET]: Basic netw...
34

5f256becd   Eric W. Biederman   [NET]: Basic netw...
35
  LIST_HEAD(net_namespace_list);
b76a461f1   Alexey Dobriyan   netns: export net...
36
  EXPORT_SYMBOL_GPL(net_namespace_list);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
37

f0b07bb15   Kirill Tkhai   net: Introduce ne...
38
39
40
  /* Protects net_namespace_list. Nests iside rtnl_lock() */
  DECLARE_RWSEM(net_rwsem);
  EXPORT_SYMBOL_GPL(net_rwsem);
9b2426105   David Howells   keys: Network nam...
41
42
43
  #ifdef CONFIG_KEYS
  static struct key_tag init_net_key_domain = { .usage = REFCOUNT_INIT(1) };
  #endif
734b65417   Rustad, Mark D   net: Statically i...
44
  struct net init_net = {
273c28bc5   Kirill Tkhai   net: Convert atom...
45
  	.count		= REFCOUNT_INIT(1),
b5082df80   David Howells   net: Initialise i...
46
  	.dev_base_head	= LIST_HEAD_INIT(init_net.dev_base_head),
9b2426105   David Howells   keys: Network nam...
47
48
49
  #ifdef CONFIG_KEYS
  	.key_domain	= &init_net_key_domain,
  #endif
734b65417   Rustad, Mark D   net: Statically i...
50
  };
ff4b95027   Denis V. Lunev   [NETNS]: Re-expor...
51
  EXPORT_SYMBOL(init_net);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
52

f8c46cb39   Dmitry Torokhov   netns: do not cal...
53
  static bool init_net_initialized;
1a57feb84   Kirill Tkhai   net: Introduce ne...
54
  /*
4420bf21f   Kirill Tkhai   net: Rename net_s...
55
   * pernet_ops_rwsem: protects: pernet_list, net_generic_ids,
1a57feb84   Kirill Tkhai   net: Introduce ne...
56
   * init_net_initialized and first_device pointer.
8518e9bb9   Kirill Tkhai   net: Add more com...
57
58
   * This is internal net namespace object. Please, don't use it
   * outside.
1a57feb84   Kirill Tkhai   net: Introduce ne...
59
   */
4420bf21f   Kirill Tkhai   net: Rename net_s...
60
  DECLARE_RWSEM(pernet_ops_rwsem);
554873e51   Kirill Tkhai   net: Do not take ...
61
  EXPORT_SYMBOL_GPL(pernet_ops_rwsem);
f8c46cb39   Dmitry Torokhov   netns: do not cal...
62

6af2d5fff   Alexey Dobriyan   netns: fix net_ge...
63
64
  #define MIN_PERNET_OPS_ID	\
  	((sizeof(struct net_generic) + sizeof(void *) - 1) / sizeof(void *))
dec827d17   Pavel Emelyanov   [NETNS]: The gene...
65
  #define INITIAL_NET_GEN_PTRS	13 /* +1 for len +2 for rcu_head */
073862ba5   Eric Dumazet   netns: fix net_al...
66
  static unsigned int max_gen_ptrs = INITIAL_NET_GEN_PTRS;
92acdc58a   Daniel Borkmann   bpf, net: Rework ...
67
  DEFINE_COOKIE(net_cookie);
f318903c0   Daniel Borkmann   bpf: Add netns co...
68

92acdc58a   Daniel Borkmann   bpf, net: Rework ...
69
  u64 __net_gen_cookie(struct net *net)
f318903c0   Daniel Borkmann   bpf: Add netns co...
70
71
72
73
74
75
  {
  	while (1) {
  		u64 res = atomic64_read(&net->net_cookie);
  
  		if (res)
  			return res;
92acdc58a   Daniel Borkmann   bpf, net: Rework ...
76
  		res = gen_cookie_next(&net_cookie);
f318903c0   Daniel Borkmann   bpf: Add netns co...
77
78
79
  		atomic64_cmpxchg(&net->net_cookie, 0, res);
  	}
  }
073862ba5   Eric Dumazet   netns: fix net_al...
80
81
82
  static struct net_generic *net_alloc_generic(void)
  {
  	struct net_generic *ng;
6af2d5fff   Alexey Dobriyan   netns: fix net_ge...
83
  	unsigned int generic_size = offsetof(struct net_generic, ptr[max_gen_ptrs]);
073862ba5   Eric Dumazet   netns: fix net_al...
84
85
86
  
  	ng = kzalloc(generic_size, GFP_KERNEL);
  	if (ng)
9bfc7b996   Alexey Dobriyan   netns: add dummy ...
87
  		ng->s.len = max_gen_ptrs;
073862ba5   Eric Dumazet   netns: fix net_al...
88
89
90
  
  	return ng;
  }
c7d03a00b   Alexey Dobriyan   netns: make struc...
91
  static int net_assign_generic(struct net *net, unsigned int id, void *data)
05fceb4ad   Jiri Pirko   net: disallow to ...
92
93
  {
  	struct net_generic *ng, *old_ng;
6af2d5fff   Alexey Dobriyan   netns: fix net_ge...
94
  	BUG_ON(id < MIN_PERNET_OPS_ID);
05fceb4ad   Jiri Pirko   net: disallow to ...
95

1c87733d0   Eric Dumazet   net_ns: add __rcu...
96
  	old_ng = rcu_dereference_protected(net->gen,
4420bf21f   Kirill Tkhai   net: Rename net_s...
97
  					   lockdep_is_held(&pernet_ops_rwsem));
6af2d5fff   Alexey Dobriyan   netns: fix net_ge...
98
99
  	if (old_ng->s.len > id) {
  		old_ng->ptr[id] = data;
1a9a05920   Alexey Dobriyan   netns: publish ne...
100
101
  		return 0;
  	}
05fceb4ad   Jiri Pirko   net: disallow to ...
102

073862ba5   Eric Dumazet   netns: fix net_al...
103
  	ng = net_alloc_generic();
05fceb4ad   Jiri Pirko   net: disallow to ...
104
105
106
107
108
109
110
111
112
113
114
115
116
  	if (ng == NULL)
  		return -ENOMEM;
  
  	/*
  	 * Some synchronisation notes:
  	 *
  	 * The net_generic explores the net->gen array inside rcu
  	 * read section. Besides once set the net->gen->ptr[x]
  	 * pointer never changes (see rules in netns/generic.h).
  	 *
  	 * That said, we simply duplicate this array and schedule
  	 * the old copy for kfree after a grace period.
  	 */
6af2d5fff   Alexey Dobriyan   netns: fix net_ge...
117
118
119
  	memcpy(&ng->ptr[MIN_PERNET_OPS_ID], &old_ng->ptr[MIN_PERNET_OPS_ID],
  	       (old_ng->s.len - MIN_PERNET_OPS_ID) * sizeof(void *));
  	ng->ptr[id] = data;
05fceb4ad   Jiri Pirko   net: disallow to ...
120
121
  
  	rcu_assign_pointer(net->gen, ng);
9bfc7b996   Alexey Dobriyan   netns: add dummy ...
122
  	kfree_rcu(old_ng, s.rcu);
05fceb4ad   Jiri Pirko   net: disallow to ...
123
124
  	return 0;
  }
f875bae06   Eric W. Biederman   net: Automaticall...
125
126
  static int ops_init(const struct pernet_operations *ops, struct net *net)
  {
b922934d0   Julian Anastasov   netns: do not lea...
127
128
  	int err = -ENOMEM;
  	void *data = NULL;
f875bae06   Eric W. Biederman   net: Automaticall...
129
  	if (ops->id && ops->size) {
b922934d0   Julian Anastasov   netns: do not lea...
130
  		data = kzalloc(ops->size, GFP_KERNEL);
f875bae06   Eric W. Biederman   net: Automaticall...
131
  		if (!data)
b922934d0   Julian Anastasov   netns: do not lea...
132
  			goto out;
f875bae06   Eric W. Biederman   net: Automaticall...
133
134
  
  		err = net_assign_generic(net, *ops->id, data);
b922934d0   Julian Anastasov   netns: do not lea...
135
136
  		if (err)
  			goto cleanup;
f875bae06   Eric W. Biederman   net: Automaticall...
137
  	}
b922934d0   Julian Anastasov   netns: do not lea...
138
  	err = 0;
f875bae06   Eric W. Biederman   net: Automaticall...
139
  	if (ops->init)
b922934d0   Julian Anastasov   netns: do not lea...
140
141
142
143
144
145
146
147
148
  		err = ops->init(net);
  	if (!err)
  		return 0;
  
  cleanup:
  	kfree(data);
  
  out:
  	return err;
f875bae06   Eric W. Biederman   net: Automaticall...
149
150
151
152
153
  }
  
  static void ops_free(const struct pernet_operations *ops, struct net *net)
  {
  	if (ops->id && ops->size) {
c7d03a00b   Alexey Dobriyan   netns: make struc...
154
  		kfree(net_generic(net, *ops->id));
f875bae06   Eric W. Biederman   net: Automaticall...
155
156
  	}
  }
d7d99872c   Eric Dumazet   netns: add pre_ex...
157
158
159
160
161
162
163
164
165
166
  static void ops_pre_exit_list(const struct pernet_operations *ops,
  			      struct list_head *net_exit_list)
  {
  	struct net *net;
  
  	if (ops->pre_exit) {
  		list_for_each_entry(net, net_exit_list, exit_list)
  			ops->pre_exit(net);
  	}
  }
72ad937ab   Eric W. Biederman   net: Add support ...
167
168
169
170
171
172
173
174
  static void ops_exit_list(const struct pernet_operations *ops,
  			  struct list_head *net_exit_list)
  {
  	struct net *net;
  	if (ops->exit) {
  		list_for_each_entry(net, net_exit_list, exit_list)
  			ops->exit(net);
  	}
72ad937ab   Eric W. Biederman   net: Add support ...
175
176
177
178
179
180
181
182
183
184
185
186
187
  	if (ops->exit_batch)
  		ops->exit_batch(net_exit_list);
  }
  
  static void ops_free_list(const struct pernet_operations *ops,
  			  struct list_head *net_exit_list)
  {
  	struct net *net;
  	if (ops->size && ops->id) {
  		list_for_each_entry(net, net_exit_list, exit_list)
  			ops_free(ops, net);
  	}
  }
95f38411d   Nicolas Dichtel   netns: use a spin...
188
  /* should be called with nsid_lock held */
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
189
190
  static int alloc_netid(struct net *net, struct net *peer, int reqid)
  {
3138dbf88   Nicolas Dichtel   netns: notify new...
191
  	int min = 0, max = 0;
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
192

0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
193
194
195
196
  	if (reqid >= 0) {
  		min = reqid;
  		max = reqid + 1;
  	}
95f38411d   Nicolas Dichtel   netns: use a spin...
197
  	return idr_alloc(&net->netns_ids, peer, min, max, GFP_ATOMIC);
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
198
199
200
201
202
203
204
205
206
207
208
209
210
211
  }
  
  /* This function is used by idr_for_each(). If net is equal to peer, the
   * function returns the id so that idr_for_each() stops. Because we cannot
   * returns the id 0 (idr_for_each() will not stop), we return the magic value
   * NET_ID_ZERO (-1) for it.
   */
  #define NET_ID_ZERO -1
  static int net_eq_idr(int id, void *net, void *peer)
  {
  	if (net_eq(net, peer))
  		return id ? : NET_ID_ZERO;
  	return 0;
  }
2dce224f4   Guillaume Nault   netns: protect ne...
212
  /* Must be called from RCU-critical section or with nsid_lock held */
490529416   Guillaume Nault   netns: Remove __p...
213
  static int __peernet2id(const struct net *net, struct net *peer)
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
214
215
  {
  	int id = idr_for_each(&net->netns_ids, net_eq_idr, peer);
3138dbf88   Nicolas Dichtel   netns: notify new...
216

0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
217
218
219
220
221
  	/* Magic value for id 0. */
  	if (id == NET_ID_ZERO)
  		return 0;
  	if (id > 0)
  		return id;
109582af1   Nicolas Dichtel   netns: returns al...
222
  	return NETNSA_NSID_NOT_ASSIGNED;
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
223
  }
993e4c929   Nicolas Dichtel   netns: fix NLM_F_...
224
  static void rtnl_net_notifyid(struct net *net, int cmd, int id, u32 portid,
d4e4fdf9e   Guillaume Nault   netns: fix GFP fl...
225
  			      struct nlmsghdr *nlh, gfp_t gfp);
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
226
227
228
  /* This function returns the id of a peer netns. If no id is assigned, one will
   * be allocated and returned.
   */
d4e4fdf9e   Guillaume Nault   netns: fix GFP fl...
229
  int peernet2id_alloc(struct net *net, struct net *peer, gfp_t gfp)
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
230
  {
3138dbf88   Nicolas Dichtel   netns: notify new...
231
  	int id;
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
232

273c28bc5   Kirill Tkhai   net: Convert atom...
233
  	if (refcount_read(&net->count) == 0)
cfc44a4d1   WANG Cong   net: check dead n...
234
  		return NETNSA_NSID_NOT_ASSIGNED;
490529416   Guillaume Nault   netns: Remove __p...
235

e1f469cd5   Taehee Yoo   Revert "netns: do...
236
  	spin_lock_bh(&net->nsid_lock);
490529416   Guillaume Nault   netns: Remove __p...
237
238
  	id = __peernet2id(net, peer);
  	if (id >= 0) {
e1f469cd5   Taehee Yoo   Revert "netns: do...
239
  		spin_unlock_bh(&net->nsid_lock);
490529416   Guillaume Nault   netns: Remove __p...
240
241
242
243
  		return id;
  	}
  
  	/* When peer is obtained from RCU lists, we may race with
0c06bea91   Kirill Tkhai   net: Fix possible...
244
245
246
247
  	 * its cleanup. Check whether it's alive, and this guarantees
  	 * we never hash a peer back to net->netns_ids, after it has
  	 * just been idr_remove()'d from there in cleanup_net().
  	 */
490529416   Guillaume Nault   netns: Remove __p...
248
  	if (!maybe_get_net(peer)) {
e1f469cd5   Taehee Yoo   Revert "netns: do...
249
  		spin_unlock_bh(&net->nsid_lock);
490529416   Guillaume Nault   netns: Remove __p...
250
251
252
253
  		return NETNSA_NSID_NOT_ASSIGNED;
  	}
  
  	id = alloc_netid(net, peer, -1);
e1f469cd5   Taehee Yoo   Revert "netns: do...
254
  	spin_unlock_bh(&net->nsid_lock);
490529416   Guillaume Nault   netns: Remove __p...
255
256
257
258
259
260
  
  	put_net(peer);
  	if (id < 0)
  		return NETNSA_NSID_NOT_ASSIGNED;
  
  	rtnl_net_notifyid(net, RTM_NEWNSID, id, 0, NULL, gfp);
3138dbf88   Nicolas Dichtel   netns: notify new...
261
  	return id;
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
262
  }
7cbebc8a1   Jiri Benc   net: export peern...
263
  EXPORT_SYMBOL_GPL(peernet2id_alloc);
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
264

95f38411d   Nicolas Dichtel   netns: use a spin...
265
  /* This function returns, if assigned, the id of a peer netns. */
56f200c78   Guillaume Nault   netns: Constify e...
266
  int peernet2id(const struct net *net, struct net *peer)
95f38411d   Nicolas Dichtel   netns: use a spin...
267
  {
95f38411d   Nicolas Dichtel   netns: use a spin...
268
  	int id;
2dce224f4   Guillaume Nault   netns: protect ne...
269
  	rcu_read_lock();
95f38411d   Nicolas Dichtel   netns: use a spin...
270
  	id = __peernet2id(net, peer);
2dce224f4   Guillaume Nault   netns: protect ne...
271
  	rcu_read_unlock();
95f38411d   Nicolas Dichtel   netns: use a spin...
272
273
  	return id;
  }
38f507f1b   WANG Cong   vxlan: call peern...
274
  EXPORT_SYMBOL(peernet2id);
95f38411d   Nicolas Dichtel   netns: use a spin...
275

59324cf35   Nicolas Dichtel   netlink: allow to...
276
277
278
  /* This function returns true is the peer netns has an id assigned into the
   * current netns.
   */
56f200c78   Guillaume Nault   netns: Constify e...
279
  bool peernet_has_id(const struct net *net, struct net *peer)
59324cf35   Nicolas Dichtel   netlink: allow to...
280
281
282
  {
  	return peernet2id(net, peer) >= 0;
  }
56f200c78   Guillaume Nault   netns: Constify e...
283
  struct net *get_net_ns_by_id(const struct net *net, int id)
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
284
285
286
287
288
289
290
291
292
  {
  	struct net *peer;
  
  	if (id < 0)
  		return NULL;
  
  	rcu_read_lock();
  	peer = idr_find(&net->netns_ids, id);
  	if (peer)
21b594435   Eric W. Biederman   net: Fix double f...
293
  		peer = maybe_get_net(peer);
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
294
295
296
297
  	rcu_read_unlock();
  
  	return peer;
  }
5f256becd   Eric W. Biederman   [NET]: Basic netw...
298
299
300
  /*
   * setup_net runs the initializers for the network namespace object.
   */
038e7332b   Eric W. Biederman   userns: make each...
301
  static __net_init int setup_net(struct net *net, struct user_namespace *user_ns)
5f256becd   Eric W. Biederman   [NET]: Basic netw...
302
  {
4420bf21f   Kirill Tkhai   net: Rename net_s...
303
  	/* Must be called with pernet_ops_rwsem held */
f875bae06   Eric W. Biederman   net: Automaticall...
304
  	const struct pernet_operations *ops, *saved_ops;
486a87f1e   Daniel Lezcano   netns: fix double...
305
  	int error = 0;
72ad937ab   Eric W. Biederman   net: Add support ...
306
  	LIST_HEAD(net_exit_list);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
307

273c28bc5   Kirill Tkhai   net: Convert atom...
308
  	refcount_set(&net->count, 1);
c122e14df   Reshetova, Elena   net: convert net....
309
  	refcount_set(&net->passive, 1);
355b98553   Eric Dumazet   netns: provide pu...
310
  	get_random_bytes(&net->hash_mix, sizeof(u32));
4e985adaa   Thomas Graf   rtnl: provide lin...
311
  	net->dev_base_seq = 1;
038e7332b   Eric W. Biederman   userns: make each...
312
  	net->user_ns = user_ns;
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
313
  	idr_init(&net->netns_ids);
de133464c   WANG Cong   netns: make nsid_...
314
  	spin_lock_init(&net->nsid_lock);
d9ff30497   Kirill Tkhai   net: Replace ip_r...
315
  	mutex_init(&net->ipv4.ra_mutex);
486a87f1e   Daniel Lezcano   netns: fix double...
316

768f3591e   Pavel Emelyanov   [NETNS]: Cleanup ...
317
  	list_for_each_entry(ops, &pernet_list, list) {
f875bae06   Eric W. Biederman   net: Automaticall...
318
319
320
  		error = ops_init(ops, net);
  		if (error < 0)
  			goto out_undo;
5f256becd   Eric W. Biederman   [NET]: Basic netw...
321
  	}
f0b07bb15   Kirill Tkhai   net: Introduce ne...
322
  	down_write(&net_rwsem);
98f6c533a   Kirill Tkhai   net: Assign net t...
323
  	list_add_tail_rcu(&net->list, &net_namespace_list);
f0b07bb15   Kirill Tkhai   net: Introduce ne...
324
  	up_write(&net_rwsem);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
325
326
  out:
  	return error;
768f3591e   Pavel Emelyanov   [NETNS]: Cleanup ...
327

5f256becd   Eric W. Biederman   [NET]: Basic netw...
328
329
330
331
  out_undo:
  	/* Walk through the list backwards calling the exit functions
  	 * for the pernet modules whose init functions did not fail.
  	 */
72ad937ab   Eric W. Biederman   net: Add support ...
332
  	list_add(&net->exit_list, &net_exit_list);
f875bae06   Eric W. Biederman   net: Automaticall...
333
  	saved_ops = ops;
72ad937ab   Eric W. Biederman   net: Add support ...
334
  	list_for_each_entry_continue_reverse(ops, &pernet_list, list)
d7d99872c   Eric Dumazet   netns: add pre_ex...
335
336
337
  		ops_pre_exit_list(ops, &net_exit_list);
  
  	synchronize_rcu();
b272a0ad7   Li RongQing   netns: restore op...
338
  	ops = saved_ops;
d7d99872c   Eric Dumazet   netns: add pre_ex...
339
  	list_for_each_entry_continue_reverse(ops, &pernet_list, list)
72ad937ab   Eric W. Biederman   net: Add support ...
340
  		ops_exit_list(ops, &net_exit_list);
f875bae06   Eric W. Biederman   net: Automaticall...
341
342
  	ops = saved_ops;
  	list_for_each_entry_continue_reverse(ops, &pernet_list, list)
72ad937ab   Eric W. Biederman   net: Add support ...
343
  		ops_free_list(ops, &net_exit_list);
310928d96   Daniel Lezcano   [NETNS]: fix net ...
344
345
  
  	rcu_barrier();
5f256becd   Eric W. Biederman   [NET]: Basic netw...
346
347
  	goto out;
  }
7c3f1875c   Roman Kapl   net: move somaxco...
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
  static int __net_init net_defaults_init_net(struct net *net)
  {
  	net->core.sysctl_somaxconn = SOMAXCONN;
  	return 0;
  }
  
  static struct pernet_operations net_defaults_ops = {
  	.init = net_defaults_init_net,
  };
  
  static __init int net_defaults_init(void)
  {
  	if (register_pernet_subsys(&net_defaults_ops))
  		panic("Cannot initialize net default settings");
  
  	return 0;
  }
  
  core_initcall(net_defaults_init);
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
367

ebe47d47b   Clemens Noss   netns: build fix ...
368
  #ifdef CONFIG_NET_NS
2ed6afdee   Arnd Bergmann   netns: move {inc,...
369
370
371
372
373
374
375
376
377
  static struct ucounts *inc_net_namespaces(struct user_namespace *ns)
  {
  	return inc_ucount(ns, current_euid(), UCOUNT_NET_NAMESPACES);
  }
  
  static void dec_net_namespaces(struct ucounts *ucounts)
  {
  	dec_ucount(ucounts, UCOUNT_NET_NAMESPACES);
  }
08009a760   Alexey Dobriyan   net: make kmem ca...
378
  static struct kmem_cache *net_cachep __ro_after_init;
ebe47d47b   Clemens Noss   netns: build fix ...
379
  static struct workqueue_struct *netns_wq;
486a87f1e   Daniel Lezcano   netns: fix double...
380
  static struct net *net_alloc(void)
45a19b0a7   Johann Felix Soden   [NETNS]: Fix comp...
381
  {
486a87f1e   Daniel Lezcano   netns: fix double...
382
383
384
385
386
387
388
389
  	struct net *net = NULL;
  	struct net_generic *ng;
  
  	ng = net_alloc_generic();
  	if (!ng)
  		goto out;
  
  	net = kmem_cache_zalloc(net_cachep, GFP_KERNEL);
45a19b0a7   Johann Felix Soden   [NETNS]: Fix comp...
390
  	if (!net)
486a87f1e   Daniel Lezcano   netns: fix double...
391
  		goto out_free;
45a19b0a7   Johann Felix Soden   [NETNS]: Fix comp...
392

9b2426105   David Howells   keys: Network nam...
393
394
395
396
397
398
  #ifdef CONFIG_KEYS
  	net->key_domain = kzalloc(sizeof(struct key_tag), GFP_KERNEL);
  	if (!net->key_domain)
  		goto out_free_2;
  	refcount_set(&net->key_domain->usage, 1);
  #endif
486a87f1e   Daniel Lezcano   netns: fix double...
399
400
401
  	rcu_assign_pointer(net->gen, ng);
  out:
  	return net;
9b2426105   David Howells   keys: Network nam...
402
403
404
405
406
  #ifdef CONFIG_KEYS
  out_free_2:
  	kmem_cache_free(net_cachep, net);
  	net = NULL;
  #endif
486a87f1e   Daniel Lezcano   netns: fix double...
407
408
409
410
411
412
413
  out_free:
  	kfree(ng);
  	goto out;
  }
  
  static void net_free(struct net *net)
  {
416c51e17   Eric Dumazet   netns: remove one...
414
  	kfree(rcu_access_pointer(net->gen));
45a19b0a7   Johann Felix Soden   [NETNS]: Fix comp...
415
416
  	kmem_cache_free(net_cachep, net);
  }
a685e0898   Al Viro   Delay struct net ...
417
418
419
  void net_drop_ns(void *p)
  {
  	struct net *ns = p;
c122e14df   Reshetova, Elena   net: convert net....
420
  	if (ns && refcount_dec_and_test(&ns->passive))
a685e0898   Al Viro   Delay struct net ...
421
422
  		net_free(ns);
  }
038e7332b   Eric W. Biederman   userns: make each...
423
424
  struct net *copy_net_ns(unsigned long flags,
  			struct user_namespace *user_ns, struct net *old_net)
9dd776b6d   Eric W. Biederman   [NET]: Add networ...
425
  {
703286608   Eric W. Biederman   netns: Add a limi...
426
  	struct ucounts *ucounts;
088eb2d90   Alexey Dobriyan   netns 2/2: extrac...
427
428
  	struct net *net;
  	int rv;
9dd776b6d   Eric W. Biederman   [NET]: Add networ...
429

911cb193f   Rob Landley   net: minor cleanu...
430
431
  	if (!(flags & CLONE_NEWNET))
  		return get_net(old_net);
703286608   Eric W. Biederman   netns: Add a limi...
432
433
  	ucounts = inc_net_namespaces(user_ns);
  	if (!ucounts)
df75e7748   Eric W. Biederman   userns: When the ...
434
  		return ERR_PTR(-ENOSPC);
703286608   Eric W. Biederman   netns: Add a limi...
435

088eb2d90   Alexey Dobriyan   netns 2/2: extrac...
436
  	net = net_alloc();
703286608   Eric W. Biederman   netns: Add a limi...
437
  	if (!net) {
5ba049a5c   Kirill Tkhai   net: Cleanup in c...
438
439
  		rv = -ENOMEM;
  		goto dec_ucounts;
703286608   Eric W. Biederman   netns: Add a limi...
440
  	}
5ba049a5c   Kirill Tkhai   net: Cleanup in c...
441
442
  	refcount_set(&net->passive, 1);
  	net->ucounts = ucounts;
038e7332b   Eric W. Biederman   userns: make each...
443
  	get_user_ns(user_ns);
094374e5e   Kirill Tkhai   net: Reflect all ...
444

4420bf21f   Kirill Tkhai   net: Rename net_s...
445
  	rv = down_read_killable(&pernet_ops_rwsem);
5ba049a5c   Kirill Tkhai   net: Cleanup in c...
446
447
  	if (rv < 0)
  		goto put_userns;
19efbd93e   Kirill Tkhai   net: Kill net_mutex
448

038e7332b   Eric W. Biederman   userns: make each...
449
  	rv = setup_net(net, user_ns);
19efbd93e   Kirill Tkhai   net: Kill net_mutex
450

4420bf21f   Kirill Tkhai   net: Rename net_s...
451
  	up_read(&pernet_ops_rwsem);
19efbd93e   Kirill Tkhai   net: Kill net_mutex
452

088eb2d90   Alexey Dobriyan   netns 2/2: extrac...
453
  	if (rv < 0) {
5ba049a5c   Kirill Tkhai   net: Cleanup in c...
454
  put_userns:
82ecff655   Takeshi Misawa   keys: Fix memory ...
455
  		key_remove_domain(net->key_domain);
038e7332b   Eric W. Biederman   userns: make each...
456
  		put_user_ns(user_ns);
a685e0898   Al Viro   Delay struct net ...
457
  		net_drop_ns(net);
5ba049a5c   Kirill Tkhai   net: Cleanup in c...
458
459
  dec_ucounts:
  		dec_net_namespaces(ucounts);
088eb2d90   Alexey Dobriyan   netns 2/2: extrac...
460
461
462
463
  		return ERR_PTR(rv);
  	}
  	return net;
  }
486a87f1e   Daniel Lezcano   netns: fix double...
464

fbdeaed40   Tyler Hicks   net: create reusa...
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
  /**
   * net_ns_get_ownership - get sysfs ownership data for @net
   * @net: network namespace in question (can be NULL)
   * @uid: kernel user ID for sysfs objects
   * @gid: kernel group ID for sysfs objects
   *
   * Returns the uid/gid pair of root in the user namespace associated with the
   * given network namespace.
   */
  void net_ns_get_ownership(const struct net *net, kuid_t *uid, kgid_t *gid)
  {
  	if (net) {
  		kuid_t ns_root_uid = make_kuid(net->user_ns, 0);
  		kgid_t ns_root_gid = make_kgid(net->user_ns, 0);
  
  		if (uid_valid(ns_root_uid))
  			*uid = ns_root_uid;
  
  		if (gid_valid(ns_root_gid))
  			*gid = ns_root_gid;
  	} else {
  		*uid = GLOBAL_ROOT_UID;
  		*gid = GLOBAL_ROOT_GID;
  	}
  }
  EXPORT_SYMBOL_GPL(net_ns_get_ownership);
fb07a820f   Kirill Tkhai   net: Move net:net...
491
492
493
494
495
496
497
  static void unhash_nsid(struct net *net, struct net *last)
  {
  	struct net *tmp;
  	/* This function is only called from cleanup_net() work,
  	 * and this work is the only process, that may delete
  	 * a net from net_namespace_list. So, when the below
  	 * is executing, the list may only grow. Thus, we do not
f0b07bb15   Kirill Tkhai   net: Introduce ne...
498
  	 * use for_each_net_rcu() or net_rwsem.
fb07a820f   Kirill Tkhai   net: Move net:net...
499
500
501
  	 */
  	for_each_net(tmp) {
  		int id;
e1f469cd5   Taehee Yoo   Revert "netns: do...
502
  		spin_lock_bh(&tmp->nsid_lock);
fb07a820f   Kirill Tkhai   net: Move net:net...
503
504
505
  		id = __peernet2id(tmp, net);
  		if (id >= 0)
  			idr_remove(&tmp->netns_ids, id);
e1f469cd5   Taehee Yoo   Revert "netns: do...
506
  		spin_unlock_bh(&tmp->nsid_lock);
fb07a820f   Kirill Tkhai   net: Move net:net...
507
  		if (id >= 0)
d4e4fdf9e   Guillaume Nault   netns: fix GFP fl...
508
509
  			rtnl_net_notifyid(tmp, RTM_DELNSID, id, 0, NULL,
  					  GFP_KERNEL);
fb07a820f   Kirill Tkhai   net: Move net:net...
510
511
512
  		if (tmp == last)
  			break;
  	}
e1f469cd5   Taehee Yoo   Revert "netns: do...
513
  	spin_lock_bh(&net->nsid_lock);
fb07a820f   Kirill Tkhai   net: Move net:net...
514
  	idr_destroy(&net->netns_ids);
e1f469cd5   Taehee Yoo   Revert "netns: do...
515
  	spin_unlock_bh(&net->nsid_lock);
fb07a820f   Kirill Tkhai   net: Move net:net...
516
  }
65b7b5b90   Kirill Tkhai   net: Make cleanup...
517
  static LLIST_HEAD(cleanup_list);
2b035b399   Eric W. Biederman   net: Batch networ...
518

6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
519
520
  static void cleanup_net(struct work_struct *work)
  {
f875bae06   Eric W. Biederman   net: Automaticall...
521
  	const struct pernet_operations *ops;
fb07a820f   Kirill Tkhai   net: Move net:net...
522
  	struct net *net, *tmp, *last;
65b7b5b90   Kirill Tkhai   net: Make cleanup...
523
  	struct llist_node *net_kill_list;
72ad937ab   Eric W. Biederman   net: Add support ...
524
  	LIST_HEAD(net_exit_list);
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
525

2b035b399   Eric W. Biederman   net: Batch networ...
526
  	/* Atomically snapshot the list of namespaces to cleanup */
65b7b5b90   Kirill Tkhai   net: Make cleanup...
527
  	net_kill_list = llist_del_all(&cleanup_list);
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
528

4420bf21f   Kirill Tkhai   net: Rename net_s...
529
  	down_read(&pernet_ops_rwsem);
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
530
531
  
  	/* Don't let anyone else find us. */
f0b07bb15   Kirill Tkhai   net: Introduce ne...
532
  	down_write(&net_rwsem);
65b7b5b90   Kirill Tkhai   net: Make cleanup...
533
  	llist_for_each_entry(net, net_kill_list, cleanup_list)
2b035b399   Eric W. Biederman   net: Batch networ...
534
  		list_del_rcu(&net->list);
fb07a820f   Kirill Tkhai   net: Move net:net...
535
536
537
538
539
540
541
542
543
544
545
  	/* Cache last net. After we unlock rtnl, no one new net
  	 * added to net_namespace_list can assign nsid pointer
  	 * to a net from net_kill_list (see peernet2id_alloc()).
  	 * So, we skip them in unhash_nsid().
  	 *
  	 * Note, that unhash_nsid() does not delete nsid links
  	 * between net_kill_list's nets, as they've already
  	 * deleted from net_namespace_list. But, this would be
  	 * useless anyway, as netns_ids are destroyed there.
  	 */
  	last = list_last_entry(&net_namespace_list, struct net, list);
f0b07bb15   Kirill Tkhai   net: Introduce ne...
546
  	up_write(&net_rwsem);
6d458f5b4   Nicolas Dichtel   Revert "netns: do...
547

65b7b5b90   Kirill Tkhai   net: Make cleanup...
548
  	llist_for_each_entry(net, net_kill_list, cleanup_list) {
fb07a820f   Kirill Tkhai   net: Move net:net...
549
550
  		unhash_nsid(net, last);
  		list_add_tail(&net->exit_list, &net_exit_list);
72ad937ab   Eric W. Biederman   net: Add support ...
551
  	}
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
552

d7d99872c   Eric Dumazet   netns: add pre_ex...
553
554
555
  	/* Run all of the network namespace pre_exit methods */
  	list_for_each_entry_reverse(ops, &pernet_list, list)
  		ops_pre_exit_list(ops, &net_exit_list);
11a28d373   Johannes Berg   net: make namespa...
556
557
558
559
  	/*
  	 * Another CPU might be rcu-iterating the list, wait for it.
  	 * This needs to be before calling the exit() notifiers, so
  	 * the rcu_barrier() below isn't sufficient alone.
d7d99872c   Eric Dumazet   netns: add pre_ex...
560
  	 * Also the pre_exit() and exit() methods need this barrier.
11a28d373   Johannes Berg   net: make namespa...
561
562
  	 */
  	synchronize_rcu();
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
563
  	/* Run all of the network namespace exit methods */
72ad937ab   Eric W. Biederman   net: Add support ...
564
565
  	list_for_each_entry_reverse(ops, &pernet_list, list)
  		ops_exit_list(ops, &net_exit_list);
f875bae06   Eric W. Biederman   net: Automaticall...
566
  	/* Free the net generic variables */
72ad937ab   Eric W. Biederman   net: Add support ...
567
568
  	list_for_each_entry_reverse(ops, &pernet_list, list)
  		ops_free_list(ops, &net_exit_list);
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
569

4420bf21f   Kirill Tkhai   net: Rename net_s...
570
  	up_read(&pernet_ops_rwsem);
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
571
572
573
574
575
576
577
  
  	/* Ensure there are no outstanding rcu callbacks using this
  	 * network namespace.
  	 */
  	rcu_barrier();
  
  	/* Finally it is safe to free my network namespace structure */
72ad937ab   Eric W. Biederman   net: Add support ...
578
579
  	list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) {
  		list_del_init(&net->exit_list);
703286608   Eric W. Biederman   netns: Add a limi...
580
  		dec_net_namespaces(net->ucounts);
9b2426105   David Howells   keys: Network nam...
581
  		key_remove_domain(net->key_domain);
038e7332b   Eric W. Biederman   userns: make each...
582
  		put_user_ns(net->user_ns);
a685e0898   Al Viro   Delay struct net ...
583
  		net_drop_ns(net);
2b035b399   Eric W. Biederman   net: Batch networ...
584
  	}
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
585
  }
7866cc57b   Florian Westphal   netns: add and us...
586
587
588
589
590
591
592
593
594
595
596
597
  
  /**
   * net_ns_barrier - wait until concurrent net_cleanup_work is done
   *
   * cleanup_net runs from work queue and will first remove namespaces
   * from the global list, then run net exit functions.
   *
   * Call this in module exit path to make sure that all netns
   * ->exit ops have been invoked before the function is removed.
   */
  void net_ns_barrier(void)
  {
4420bf21f   Kirill Tkhai   net: Rename net_s...
598
599
  	down_write(&pernet_ops_rwsem);
  	up_write(&pernet_ops_rwsem);
7866cc57b   Florian Westphal   netns: add and us...
600
601
  }
  EXPORT_SYMBOL(net_ns_barrier);
2b035b399   Eric W. Biederman   net: Batch networ...
602
  static DECLARE_WORK(net_cleanup_work, cleanup_net);
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
603
604
605
606
  
  void __put_net(struct net *net)
  {
  	/* Cleanup the network namespace in process context */
8349efd90   Kirill Tkhai   net: Queue net_cl...
607
608
  	if (llist_add(&net->cleanup_list, &cleanup_list))
  		queue_work(netns_wq, &net_cleanup_work);
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
609
610
  }
  EXPORT_SYMBOL_GPL(__put_net);
956c92078   Stephen Rothwell   net: fix get_net_...
611
612
  struct net *get_net_ns_by_fd(int fd)
  {
956c92078   Stephen Rothwell   net: fix get_net_...
613
  	struct file *file;
33c429405   Al Viro   copy address of p...
614
  	struct ns_common *ns;
956c92078   Stephen Rothwell   net: fix get_net_...
615
  	struct net *net;
956c92078   Stephen Rothwell   net: fix get_net_...
616
  	file = proc_ns_fget(fd);
c316e6a30   Al Viro   get_net_ns_by_fd(...
617
618
  	if (IS_ERR(file))
  		return ERR_CAST(file);
956c92078   Stephen Rothwell   net: fix get_net_...
619

f77c80142   Al Viro   bury struct proc_...
620
  	ns = get_proc_ns(file_inode(file));
33c429405   Al Viro   copy address of p...
621
622
  	if (ns->ops == &netns_operations)
  		net = get_net(container_of(ns, struct net, ns));
c316e6a30   Al Viro   get_net_ns_by_fd(...
623
624
  	else
  		net = ERR_PTR(-EINVAL);
956c92078   Stephen Rothwell   net: fix get_net_...
625

c316e6a30   Al Viro   get_net_ns_by_fd(...
626
  	fput(file);
956c92078   Stephen Rothwell   net: fix get_net_...
627
628
  	return net;
  }
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
629
  #else
956c92078   Stephen Rothwell   net: fix get_net_...
630
631
632
633
  struct net *get_net_ns_by_fd(int fd)
  {
  	return ERR_PTR(-EINVAL);
  }
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
634
  #endif
4b681c82d   Vadim Kochan   nl80211: Allow se...
635
  EXPORT_SYMBOL_GPL(get_net_ns_by_fd);
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
636

30ffee848   Johannes Berg   net: move and exp...
637
638
639
640
641
642
643
644
645
646
647
  struct net *get_net_ns_by_pid(pid_t pid)
  {
  	struct task_struct *tsk;
  	struct net *net;
  
  	/* Lookup the network namespace */
  	net = ERR_PTR(-ESRCH);
  	rcu_read_lock();
  	tsk = find_task_by_vpid(pid);
  	if (tsk) {
  		struct nsproxy *nsproxy;
728dba3a3   Eric W. Biederman   namespaces: Use t...
648
649
  		task_lock(tsk);
  		nsproxy = tsk->nsproxy;
30ffee848   Johannes Berg   net: move and exp...
650
651
  		if (nsproxy)
  			net = get_net(nsproxy->net_ns);
728dba3a3   Eric W. Biederman   namespaces: Use t...
652
  		task_unlock(tsk);
30ffee848   Johannes Berg   net: move and exp...
653
654
655
656
657
  	}
  	rcu_read_unlock();
  	return net;
  }
  EXPORT_SYMBOL_GPL(get_net_ns_by_pid);
98f842e67   Eric W. Biederman   proc: Usable inod...
658
659
  static __net_init int net_ns_net_init(struct net *net)
  {
33c429405   Al Viro   copy address of p...
660
661
662
  #ifdef CONFIG_NET_NS
  	net->ns.ops = &netns_operations;
  #endif
6344c433a   Al Viro   new helpers: ns_a...
663
  	return ns_alloc_inum(&net->ns);
98f842e67   Eric W. Biederman   proc: Usable inod...
664
665
666
667
  }
  
  static __net_exit void net_ns_net_exit(struct net *net)
  {
6344c433a   Al Viro   new helpers: ns_a...
668
  	ns_free_inum(&net->ns);
98f842e67   Eric W. Biederman   proc: Usable inod...
669
670
671
672
673
674
  }
  
  static struct pernet_operations __net_initdata net_ns_ops = {
  	.init = net_ns_net_init,
  	.exit = net_ns_net_exit,
  };
3ee5256da   stephen hemminger   netns: make nla_p...
675
  static const struct nla_policy rtnl_net_policy[NETNSA_MAX + 1] = {
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
676
677
678
679
  	[NETNSA_NONE]		= { .type = NLA_UNSPEC },
  	[NETNSA_NSID]		= { .type = NLA_S32 },
  	[NETNSA_PID]		= { .type = NLA_U32 },
  	[NETNSA_FD]		= { .type = NLA_U32 },
cff478b9d   Nicolas Dichtel   netns: add suppor...
680
  	[NETNSA_TARGET_NSID]	= { .type = NLA_S32 },
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
681
  };
c21ef3e34   David Ahern   net: rtnetlink: p...
682
683
  static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh,
  			  struct netlink_ext_ack *extack)
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
684
685
686
  {
  	struct net *net = sock_net(skb->sk);
  	struct nlattr *tb[NETNSA_MAX + 1];
4a7f7bc60   Nicolas Dichtel   netns: define ext...
687
  	struct nlattr *nla;
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
688
689
  	struct net *peer;
  	int nsid, err;
8cb081746   Johannes Berg   netlink: make val...
690
691
  	err = nlmsg_parse_deprecated(nlh, sizeof(struct rtgenmsg), tb,
  				     NETNSA_MAX, rtnl_net_policy, extack);
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
692
693
  	if (err < 0)
  		return err;
4a7f7bc60   Nicolas Dichtel   netns: define ext...
694
695
  	if (!tb[NETNSA_NSID]) {
  		NL_SET_ERR_MSG(extack, "nsid is missing");
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
696
  		return -EINVAL;
4a7f7bc60   Nicolas Dichtel   netns: define ext...
697
  	}
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
698
  	nsid = nla_get_s32(tb[NETNSA_NSID]);
4a7f7bc60   Nicolas Dichtel   netns: define ext...
699
  	if (tb[NETNSA_PID]) {
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
700
  		peer = get_net_ns_by_pid(nla_get_u32(tb[NETNSA_PID]));
4a7f7bc60   Nicolas Dichtel   netns: define ext...
701
702
  		nla = tb[NETNSA_PID];
  	} else if (tb[NETNSA_FD]) {
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
703
  		peer = get_net_ns_by_fd(nla_get_u32(tb[NETNSA_FD]));
4a7f7bc60   Nicolas Dichtel   netns: define ext...
704
705
706
  		nla = tb[NETNSA_FD];
  	} else {
  		NL_SET_ERR_MSG(extack, "Peer netns reference is missing");
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
707
  		return -EINVAL;
4a7f7bc60   Nicolas Dichtel   netns: define ext...
708
709
710
711
  	}
  	if (IS_ERR(peer)) {
  		NL_SET_BAD_ATTR(extack, nla);
  		NL_SET_ERR_MSG(extack, "Peer netns reference is invalid");
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
712
  		return PTR_ERR(peer);
4a7f7bc60   Nicolas Dichtel   netns: define ext...
713
  	}
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
714

e1f469cd5   Taehee Yoo   Revert "netns: do...
715
  	spin_lock_bh(&net->nsid_lock);
3138dbf88   Nicolas Dichtel   netns: notify new...
716
  	if (__peernet2id(net, peer) >= 0) {
e1f469cd5   Taehee Yoo   Revert "netns: do...
717
  		spin_unlock_bh(&net->nsid_lock);
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
718
  		err = -EEXIST;
4a7f7bc60   Nicolas Dichtel   netns: define ext...
719
720
721
  		NL_SET_BAD_ATTR(extack, nla);
  		NL_SET_ERR_MSG(extack,
  			       "Peer netns already has a nsid assigned");
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
722
723
724
725
  		goto out;
  	}
  
  	err = alloc_netid(net, peer, nsid);
e1f469cd5   Taehee Yoo   Revert "netns: do...
726
  	spin_unlock_bh(&net->nsid_lock);
3138dbf88   Nicolas Dichtel   netns: notify new...
727
  	if (err >= 0) {
993e4c929   Nicolas Dichtel   netns: fix NLM_F_...
728
  		rtnl_net_notifyid(net, RTM_NEWNSID, err, NETLINK_CB(skb).portid,
d4e4fdf9e   Guillaume Nault   netns: fix GFP fl...
729
  				  nlh, GFP_KERNEL);
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
730
  		err = 0;
4a7f7bc60   Nicolas Dichtel   netns: define ext...
731
  	} else if (err == -ENOSPC && nsid >= 0) {
10d486a30   Nicolas Dichtel   netns: fix error ...
732
  		err = -EEXIST;
4a7f7bc60   Nicolas Dichtel   netns: define ext...
733
734
  		NL_SET_BAD_ATTR(extack, tb[NETNSA_NSID]);
  		NL_SET_ERR_MSG(extack, "The specified nsid is already used");
3138dbf88   Nicolas Dichtel   netns: notify new...
735
  	}
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
736
737
738
739
740
741
742
743
744
  out:
  	put_net(peer);
  	return err;
  }
  
  static int rtnl_net_get_size(void)
  {
  	return NLMSG_ALIGN(sizeof(struct rtgenmsg))
  	       + nla_total_size(sizeof(s32)) /* NETNSA_NSID */
288f06a00   Nicolas Dichtel   netns: enable to ...
745
  	       + nla_total_size(sizeof(s32)) /* NETNSA_CURRENT_NSID */
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
746
747
  	       ;
  }
a0732ad14   Nicolas Dichtel   netns: introduce ...
748
749
750
751
752
753
  struct net_fill_args {
  	u32 portid;
  	u32 seq;
  	int flags;
  	int cmd;
  	int nsid;
288f06a00   Nicolas Dichtel   netns: enable to ...
754
755
  	bool add_ref;
  	int ref_nsid;
a0732ad14   Nicolas Dichtel   netns: introduce ...
756
757
758
  };
  
  static int rtnl_net_fill(struct sk_buff *skb, struct net_fill_args *args)
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
759
760
761
  {
  	struct nlmsghdr *nlh;
  	struct rtgenmsg *rth;
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
762

a0732ad14   Nicolas Dichtel   netns: introduce ...
763
764
  	nlh = nlmsg_put(skb, args->portid, args->seq, args->cmd, sizeof(*rth),
  			args->flags);
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
765
766
767
768
769
  	if (!nlh)
  		return -EMSGSIZE;
  
  	rth = nlmsg_data(nlh);
  	rth->rtgen_family = AF_UNSPEC;
a0732ad14   Nicolas Dichtel   netns: introduce ...
770
  	if (nla_put_s32(skb, NETNSA_NSID, args->nsid))
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
771
  		goto nla_put_failure;
288f06a00   Nicolas Dichtel   netns: enable to ...
772
773
774
  	if (args->add_ref &&
  	    nla_put_s32(skb, NETNSA_CURRENT_NSID, args->ref_nsid))
  		goto nla_put_failure;
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
775
776
777
778
779
780
781
  	nlmsg_end(skb, nlh);
  	return 0;
  
  nla_put_failure:
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
  }
4d165f614   Jakub Kicinski   net: namespace: p...
782
783
784
785
786
787
788
789
  static int rtnl_net_valid_getid_req(struct sk_buff *skb,
  				    const struct nlmsghdr *nlh,
  				    struct nlattr **tb,
  				    struct netlink_ext_ack *extack)
  {
  	int i, err;
  
  	if (!netlink_strict_get_check(skb))
8cb081746   Johannes Berg   netlink: make val...
790
791
792
  		return nlmsg_parse_deprecated(nlh, sizeof(struct rtgenmsg),
  					      tb, NETNSA_MAX, rtnl_net_policy,
  					      extack);
4d165f614   Jakub Kicinski   net: namespace: p...
793

8cb081746   Johannes Berg   netlink: make val...
794
795
796
  	err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct rtgenmsg), tb,
  					    NETNSA_MAX, rtnl_net_policy,
  					    extack);
4d165f614   Jakub Kicinski   net: namespace: p...
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
  	if (err)
  		return err;
  
  	for (i = 0; i <= NETNSA_MAX; i++) {
  		if (!tb[i])
  			continue;
  
  		switch (i) {
  		case NETNSA_PID:
  		case NETNSA_FD:
  		case NETNSA_NSID:
  		case NETNSA_TARGET_NSID:
  			break;
  		default:
  			NL_SET_ERR_MSG(extack, "Unsupported attribute in peer netns getid request");
  			return -EINVAL;
  		}
  	}
  
  	return 0;
  }
c21ef3e34   David Ahern   net: rtnetlink: p...
818
819
  static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
  			  struct netlink_ext_ack *extack)
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
820
821
822
  {
  	struct net *net = sock_net(skb->sk);
  	struct nlattr *tb[NETNSA_MAX + 1];
a0732ad14   Nicolas Dichtel   netns: introduce ...
823
824
825
826
827
  	struct net_fill_args fillargs = {
  		.portid = NETLINK_CB(skb).portid,
  		.seq = nlh->nlmsg_seq,
  		.cmd = RTM_NEWNSID,
  	};
cff478b9d   Nicolas Dichtel   netns: add suppor...
828
  	struct net *peer, *target = net;
4a7f7bc60   Nicolas Dichtel   netns: define ext...
829
  	struct nlattr *nla;
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
830
  	struct sk_buff *msg;
a0732ad14   Nicolas Dichtel   netns: introduce ...
831
  	int err;
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
832

4d165f614   Jakub Kicinski   net: namespace: p...
833
  	err = rtnl_net_valid_getid_req(skb, nlh, tb, extack);
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
834
835
  	if (err < 0)
  		return err;
4a7f7bc60   Nicolas Dichtel   netns: define ext...
836
  	if (tb[NETNSA_PID]) {
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
837
  		peer = get_net_ns_by_pid(nla_get_u32(tb[NETNSA_PID]));
4a7f7bc60   Nicolas Dichtel   netns: define ext...
838
839
  		nla = tb[NETNSA_PID];
  	} else if (tb[NETNSA_FD]) {
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
840
  		peer = get_net_ns_by_fd(nla_get_u32(tb[NETNSA_FD]));
4a7f7bc60   Nicolas Dichtel   netns: define ext...
841
  		nla = tb[NETNSA_FD];
3a4f68bf6   Nicolas Dichtel   netns: enable to ...
842
  	} else if (tb[NETNSA_NSID]) {
ecce39ec1   Guillaume Nault   netns: read NETNS...
843
  		peer = get_net_ns_by_id(net, nla_get_s32(tb[NETNSA_NSID]));
3a4f68bf6   Nicolas Dichtel   netns: enable to ...
844
845
846
  		if (!peer)
  			peer = ERR_PTR(-ENOENT);
  		nla = tb[NETNSA_NSID];
4a7f7bc60   Nicolas Dichtel   netns: define ext...
847
848
  	} else {
  		NL_SET_ERR_MSG(extack, "Peer netns reference is missing");
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
849
  		return -EINVAL;
4a7f7bc60   Nicolas Dichtel   netns: define ext...
850
  	}
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
851

4a7f7bc60   Nicolas Dichtel   netns: define ext...
852
853
854
  	if (IS_ERR(peer)) {
  		NL_SET_BAD_ATTR(extack, nla);
  		NL_SET_ERR_MSG(extack, "Peer netns reference is invalid");
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
855
  		return PTR_ERR(peer);
4a7f7bc60   Nicolas Dichtel   netns: define ext...
856
  	}
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
857

cff478b9d   Nicolas Dichtel   netns: add suppor...
858
859
860
861
862
863
864
865
866
867
868
  	if (tb[NETNSA_TARGET_NSID]) {
  		int id = nla_get_s32(tb[NETNSA_TARGET_NSID]);
  
  		target = rtnl_get_net_ns_capable(NETLINK_CB(skb).sk, id);
  		if (IS_ERR(target)) {
  			NL_SET_BAD_ATTR(extack, tb[NETNSA_TARGET_NSID]);
  			NL_SET_ERR_MSG(extack,
  				       "Target netns reference is invalid");
  			err = PTR_ERR(target);
  			goto out;
  		}
288f06a00   Nicolas Dichtel   netns: enable to ...
869
870
  		fillargs.add_ref = true;
  		fillargs.ref_nsid = peernet2id(net, peer);
cff478b9d   Nicolas Dichtel   netns: add suppor...
871
  	}
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
872
873
874
875
876
  	msg = nlmsg_new(rtnl_net_get_size(), GFP_KERNEL);
  	if (!msg) {
  		err = -ENOMEM;
  		goto out;
  	}
cff478b9d   Nicolas Dichtel   netns: add suppor...
877
  	fillargs.nsid = peernet2id(target, peer);
a0732ad14   Nicolas Dichtel   netns: introduce ...
878
  	err = rtnl_net_fill(msg, &fillargs);
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
879
880
881
882
883
884
885
886
887
  	if (err < 0)
  		goto err_out;
  
  	err = rtnl_unicast(msg, net, NETLINK_CB(skb).portid);
  	goto out;
  
  err_out:
  	nlmsg_free(msg);
  out:
288f06a00   Nicolas Dichtel   netns: enable to ...
888
  	if (fillargs.add_ref)
cff478b9d   Nicolas Dichtel   netns: add suppor...
889
  		put_net(target);
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
890
891
892
  	put_net(peer);
  	return err;
  }
a143c40c3   Nicolas Dichtel   netns: allow to d...
893
  struct rtnl_net_dump_cb {
cff478b9d   Nicolas Dichtel   netns: add suppor...
894
  	struct net *tgt_net;
288f06a00   Nicolas Dichtel   netns: enable to ...
895
  	struct net *ref_net;
a143c40c3   Nicolas Dichtel   netns: allow to d...
896
  	struct sk_buff *skb;
a0732ad14   Nicolas Dichtel   netns: introduce ...
897
  	struct net_fill_args fillargs;
a143c40c3   Nicolas Dichtel   netns: allow to d...
898
899
900
  	int idx;
  	int s_idx;
  };
2dce224f4   Guillaume Nault   netns: protect ne...
901
  /* Runs in RCU-critical section. */
a143c40c3   Nicolas Dichtel   netns: allow to d...
902
903
904
905
906
907
908
  static int rtnl_net_dumpid_one(int id, void *peer, void *data)
  {
  	struct rtnl_net_dump_cb *net_cb = (struct rtnl_net_dump_cb *)data;
  	int ret;
  
  	if (net_cb->idx < net_cb->s_idx)
  		goto cont;
a0732ad14   Nicolas Dichtel   netns: introduce ...
909
  	net_cb->fillargs.nsid = id;
288f06a00   Nicolas Dichtel   netns: enable to ...
910
911
  	if (net_cb->fillargs.add_ref)
  		net_cb->fillargs.ref_nsid = __peernet2id(net_cb->ref_net, peer);
a0732ad14   Nicolas Dichtel   netns: introduce ...
912
  	ret = rtnl_net_fill(net_cb->skb, &net_cb->fillargs);
a143c40c3   Nicolas Dichtel   netns: allow to d...
913
914
915
916
917
918
919
  	if (ret < 0)
  		return ret;
  
  cont:
  	net_cb->idx++;
  	return 0;
  }
cff478b9d   Nicolas Dichtel   netns: add suppor...
920
921
922
923
924
925
926
  static int rtnl_valid_dump_net_req(const struct nlmsghdr *nlh, struct sock *sk,
  				   struct rtnl_net_dump_cb *net_cb,
  				   struct netlink_callback *cb)
  {
  	struct netlink_ext_ack *extack = cb->extack;
  	struct nlattr *tb[NETNSA_MAX + 1];
  	int err, i;
8cb081746   Johannes Berg   netlink: make val...
927
928
929
  	err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct rtgenmsg), tb,
  					    NETNSA_MAX, rtnl_net_policy,
  					    extack);
cff478b9d   Nicolas Dichtel   netns: add suppor...
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
  	if (err < 0)
  		return err;
  
  	for (i = 0; i <= NETNSA_MAX; i++) {
  		if (!tb[i])
  			continue;
  
  		if (i == NETNSA_TARGET_NSID) {
  			struct net *net;
  
  			net = rtnl_get_net_ns_capable(sk, nla_get_s32(tb[i]));
  			if (IS_ERR(net)) {
  				NL_SET_BAD_ATTR(extack, tb[i]);
  				NL_SET_ERR_MSG(extack,
  					       "Invalid target network namespace id");
  				return PTR_ERR(net);
  			}
288f06a00   Nicolas Dichtel   netns: enable to ...
947
948
  			net_cb->fillargs.add_ref = true;
  			net_cb->ref_net = net_cb->tgt_net;
cff478b9d   Nicolas Dichtel   netns: add suppor...
949
  			net_cb->tgt_net = net;
cff478b9d   Nicolas Dichtel   netns: add suppor...
950
951
952
953
954
955
956
957
958
959
  		} else {
  			NL_SET_BAD_ATTR(extack, tb[i]);
  			NL_SET_ERR_MSG(extack,
  				       "Unsupported attribute in dump request");
  			return -EINVAL;
  		}
  	}
  
  	return 0;
  }
a143c40c3   Nicolas Dichtel   netns: allow to d...
960
961
  static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
  {
a143c40c3   Nicolas Dichtel   netns: allow to d...
962
  	struct rtnl_net_dump_cb net_cb = {
cff478b9d   Nicolas Dichtel   netns: add suppor...
963
  		.tgt_net = sock_net(skb->sk),
a143c40c3   Nicolas Dichtel   netns: allow to d...
964
  		.skb = skb,
a0732ad14   Nicolas Dichtel   netns: introduce ...
965
966
967
968
969
970
  		.fillargs = {
  			.portid = NETLINK_CB(cb->skb).portid,
  			.seq = cb->nlh->nlmsg_seq,
  			.flags = NLM_F_MULTI,
  			.cmd = RTM_NEWNSID,
  		},
a143c40c3   Nicolas Dichtel   netns: allow to d...
971
972
973
  		.idx = 0,
  		.s_idx = cb->args[0],
  	};
cff478b9d   Nicolas Dichtel   netns: add suppor...
974
  	int err = 0;
a143c40c3   Nicolas Dichtel   netns: allow to d...
975

cff478b9d   Nicolas Dichtel   netns: add suppor...
976
977
978
979
  	if (cb->strict_check) {
  		err = rtnl_valid_dump_net_req(cb->nlh, skb->sk, &net_cb, cb);
  		if (err < 0)
  			goto end;
f80f14c36   David Ahern   net/namespace: Up...
980
  	}
2dce224f4   Guillaume Nault   netns: protect ne...
981
  	rcu_read_lock();
cff478b9d   Nicolas Dichtel   netns: add suppor...
982
  	idr_for_each(&net_cb.tgt_net->netns_ids, rtnl_net_dumpid_one, &net_cb);
2dce224f4   Guillaume Nault   netns: protect ne...
983
  	rcu_read_unlock();
a143c40c3   Nicolas Dichtel   netns: allow to d...
984
985
  
  	cb->args[0] = net_cb.idx;
cff478b9d   Nicolas Dichtel   netns: add suppor...
986
  end:
288f06a00   Nicolas Dichtel   netns: enable to ...
987
  	if (net_cb.fillargs.add_ref)
cff478b9d   Nicolas Dichtel   netns: add suppor...
988
989
  		put_net(net_cb.tgt_net);
  	return err < 0 ? err : skb->len;
a143c40c3   Nicolas Dichtel   netns: allow to d...
990
  }
993e4c929   Nicolas Dichtel   netns: fix NLM_F_...
991
  static void rtnl_net_notifyid(struct net *net, int cmd, int id, u32 portid,
d4e4fdf9e   Guillaume Nault   netns: fix GFP fl...
992
  			      struct nlmsghdr *nlh, gfp_t gfp)
9a9634545   Nicolas Dichtel   netns: notify net...
993
  {
a0732ad14   Nicolas Dichtel   netns: introduce ...
994
  	struct net_fill_args fillargs = {
993e4c929   Nicolas Dichtel   netns: fix NLM_F_...
995
996
  		.portid = portid,
  		.seq = nlh ? nlh->nlmsg_seq : 0,
a0732ad14   Nicolas Dichtel   netns: introduce ...
997
998
999
  		.cmd = cmd,
  		.nsid = id,
  	};
9a9634545   Nicolas Dichtel   netns: notify net...
1000
1001
  	struct sk_buff *msg;
  	int err = -ENOMEM;
d4e4fdf9e   Guillaume Nault   netns: fix GFP fl...
1002
  	msg = nlmsg_new(rtnl_net_get_size(), gfp);
9a9634545   Nicolas Dichtel   netns: notify net...
1003
1004
  	if (!msg)
  		goto out;
a0732ad14   Nicolas Dichtel   netns: introduce ...
1005
  	err = rtnl_net_fill(msg, &fillargs);
9a9634545   Nicolas Dichtel   netns: notify net...
1006
1007
  	if (err < 0)
  		goto err_out;
d4e4fdf9e   Guillaume Nault   netns: fix GFP fl...
1008
  	rtnl_notify(msg, net, portid, RTNLGRP_NSID, nlh, gfp);
9a9634545   Nicolas Dichtel   netns: notify net...
1009
1010
1011
1012
1013
1014
1015
  	return;
  
  err_out:
  	nlmsg_free(msg);
  out:
  	rtnl_set_sk_err(net, RTNLGRP_NSID, err);
  }
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1016
1017
  static int __init net_ns_init(void)
  {
486a87f1e   Daniel Lezcano   netns: fix double...
1018
  	struct net_generic *ng;
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1019

d57a9212e   Pavel Emelyanov   [NET]: Hide the n...
1020
  #ifdef CONFIG_NET_NS
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1021
1022
  	net_cachep = kmem_cache_create("net_namespace", sizeof(struct net),
  					SMP_CACHE_BYTES,
30855ffc2   Kirill Tkhai   net: Make account...
1023
  					SLAB_PANIC|SLAB_ACCOUNT, NULL);
3ef1355dc   Benjamin Thery   [NET]: Make netns...
1024
1025
1026
1027
1028
  
  	/* Create workqueue for cleanup */
  	netns_wq = create_singlethread_workqueue("netns");
  	if (!netns_wq)
  		panic("Could not create netns workq");
d57a9212e   Pavel Emelyanov   [NET]: Hide the n...
1029
  #endif
3ef1355dc   Benjamin Thery   [NET]: Make netns...
1030

486a87f1e   Daniel Lezcano   netns: fix double...
1031
1032
1033
1034
1035
  	ng = net_alloc_generic();
  	if (!ng)
  		panic("Could not allocate generic netns");
  
  	rcu_assign_pointer(init_net.gen, ng);
92acdc58a   Daniel Borkmann   bpf, net: Rework ...
1036
1037
1038
1039
  
  	preempt_disable();
  	__net_gen_cookie(&init_net);
  	preempt_enable();
486a87f1e   Daniel Lezcano   netns: fix double...
1040

4420bf21f   Kirill Tkhai   net: Rename net_s...
1041
  	down_write(&pernet_ops_rwsem);
038e7332b   Eric W. Biederman   userns: make each...
1042
  	if (setup_net(&init_net, &init_user_ns))
ca0f31125   Stephen Hemminger   netns: simplify n...
1043
  		panic("Could not setup the initial network namespace");
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1044

f8c46cb39   Dmitry Torokhov   netns: do not cal...
1045
  	init_net_initialized = true;
4420bf21f   Kirill Tkhai   net: Rename net_s...
1046
  	up_write(&pernet_ops_rwsem);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1047

0eb987c87   Aditya Pakki   net/net_namespace...
1048
1049
  	if (register_pernet_subsys(&net_ns_ops))
  		panic("Could not register network namespace subsystems");
98f842e67   Eric W. Biederman   proc: Usable inod...
1050

165b91172   Florian Westphal   net: call newid/g...
1051
1052
  	rtnl_register(PF_UNSPEC, RTM_NEWNSID, rtnl_net_newid, NULL,
  		      RTNL_FLAG_DOIT_UNLOCKED);
a143c40c3   Nicolas Dichtel   netns: allow to d...
1053
  	rtnl_register(PF_UNSPEC, RTM_GETNSID, rtnl_net_getid, rtnl_net_dumpid,
165b91172   Florian Westphal   net: call newid/g...
1054
  		      RTNL_FLAG_DOIT_UNLOCKED);
0c7aecd4b   Nicolas Dichtel   netns: add rtnl c...
1055

5f256becd   Eric W. Biederman   [NET]: Basic netw...
1056
1057
1058
1059
  	return 0;
  }
  
  pure_initcall(net_ns_init);
ed160e839   Denis V. Lunev   [NET]: Cleanup pe...
1060
  #ifdef CONFIG_NET_NS
f875bae06   Eric W. Biederman   net: Automaticall...
1061
1062
  static int __register_pernet_operations(struct list_head *list,
  					struct pernet_operations *ops)
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1063
  {
72ad937ab   Eric W. Biederman   net: Add support ...
1064
  	struct net *net;
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1065
  	int error;
72ad937ab   Eric W. Biederman   net: Add support ...
1066
  	LIST_HEAD(net_exit_list);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1067

5f256becd   Eric W. Biederman   [NET]: Basic netw...
1068
  	list_add_tail(&ops->list, list);
f875bae06   Eric W. Biederman   net: Automaticall...
1069
  	if (ops->init || (ops->id && ops->size)) {
f0b07bb15   Kirill Tkhai   net: Introduce ne...
1070
1071
1072
  		/* We held write locked pernet_ops_rwsem, and parallel
  		 * setup_net() and cleanup_net() are not possible.
  		 */
1dba323b3   Pavel Emelyanov   [NETNS]: Make the...
1073
  		for_each_net(net) {
f875bae06   Eric W. Biederman   net: Automaticall...
1074
  			error = ops_init(ops, net);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1075
1076
  			if (error)
  				goto out_undo;
72ad937ab   Eric W. Biederman   net: Add support ...
1077
  			list_add_tail(&net->exit_list, &net_exit_list);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1078
1079
  		}
  	}
1dba323b3   Pavel Emelyanov   [NETNS]: Make the...
1080
  	return 0;
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1081
1082
1083
1084
  
  out_undo:
  	/* If I have an error cleanup all namespaces I initialized */
  	list_del(&ops->list);
d7d99872c   Eric Dumazet   netns: add pre_ex...
1085
1086
  	ops_pre_exit_list(ops, &net_exit_list);
  	synchronize_rcu();
72ad937ab   Eric W. Biederman   net: Add support ...
1087
1088
  	ops_exit_list(ops, &net_exit_list);
  	ops_free_list(ops, &net_exit_list);
1dba323b3   Pavel Emelyanov   [NETNS]: Make the...
1089
  	return error;
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1090
  }
f875bae06   Eric W. Biederman   net: Automaticall...
1091
  static void __unregister_pernet_operations(struct pernet_operations *ops)
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1092
1093
  {
  	struct net *net;
72ad937ab   Eric W. Biederman   net: Add support ...
1094
  	LIST_HEAD(net_exit_list);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1095
1096
  
  	list_del(&ops->list);
f0b07bb15   Kirill Tkhai   net: Introduce ne...
1097
  	/* See comment in __register_pernet_operations() */
72ad937ab   Eric W. Biederman   net: Add support ...
1098
1099
  	for_each_net(net)
  		list_add_tail(&net->exit_list, &net_exit_list);
d7d99872c   Eric Dumazet   netns: add pre_ex...
1100
1101
  	ops_pre_exit_list(ops, &net_exit_list);
  	synchronize_rcu();
72ad937ab   Eric W. Biederman   net: Add support ...
1102
1103
  	ops_exit_list(ops, &net_exit_list);
  	ops_free_list(ops, &net_exit_list);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1104
  }
ed160e839   Denis V. Lunev   [NET]: Cleanup pe...
1105
  #else
f875bae06   Eric W. Biederman   net: Automaticall...
1106
1107
  static int __register_pernet_operations(struct list_head *list,
  					struct pernet_operations *ops)
ed160e839   Denis V. Lunev   [NET]: Cleanup pe...
1108
  {
f8c46cb39   Dmitry Torokhov   netns: do not cal...
1109
1110
1111
1112
  	if (!init_net_initialized) {
  		list_add_tail(&ops->list, list);
  		return 0;
  	}
b922934d0   Julian Anastasov   netns: do not lea...
1113
  	return ops_init(ops, &init_net);
ed160e839   Denis V. Lunev   [NET]: Cleanup pe...
1114
  }
f875bae06   Eric W. Biederman   net: Automaticall...
1115
  static void __unregister_pernet_operations(struct pernet_operations *ops)
ed160e839   Denis V. Lunev   [NET]: Cleanup pe...
1116
  {
f8c46cb39   Dmitry Torokhov   netns: do not cal...
1117
1118
1119
1120
1121
  	if (!init_net_initialized) {
  		list_del(&ops->list);
  	} else {
  		LIST_HEAD(net_exit_list);
  		list_add(&init_net.exit_list, &net_exit_list);
d7d99872c   Eric Dumazet   netns: add pre_ex...
1122
1123
  		ops_pre_exit_list(ops, &net_exit_list);
  		synchronize_rcu();
f8c46cb39   Dmitry Torokhov   netns: do not cal...
1124
1125
1126
  		ops_exit_list(ops, &net_exit_list);
  		ops_free_list(ops, &net_exit_list);
  	}
ed160e839   Denis V. Lunev   [NET]: Cleanup pe...
1127
  }
f875bae06   Eric W. Biederman   net: Automaticall...
1128
1129
  
  #endif /* CONFIG_NET_NS */
ed160e839   Denis V. Lunev   [NET]: Cleanup pe...
1130

c93cf61fd   Pavel Emelyanov   [NETNS]: The net-...
1131
  static DEFINE_IDA(net_generic_ids);
f875bae06   Eric W. Biederman   net: Automaticall...
1132
1133
1134
1135
1136
1137
  static int register_pernet_operations(struct list_head *list,
  				      struct pernet_operations *ops)
  {
  	int error;
  
  	if (ops->id) {
6e77cc471   Matthew Wilcox   Convert net_names...
1138
1139
1140
  		error = ida_alloc_min(&net_generic_ids, MIN_PERNET_OPS_ID,
  				GFP_KERNEL);
  		if (error < 0)
f875bae06   Eric W. Biederman   net: Automaticall...
1141
  			return error;
6e77cc471   Matthew Wilcox   Convert net_names...
1142
  		*ops->id = error;
6af2d5fff   Alexey Dobriyan   netns: fix net_ge...
1143
  		max_gen_ptrs = max(max_gen_ptrs, *ops->id + 1);
f875bae06   Eric W. Biederman   net: Automaticall...
1144
1145
  	}
  	error = __register_pernet_operations(list, ops);
3a765edad   Eric W. Biederman   netns: Add an exp...
1146
1147
1148
  	if (error) {
  		rcu_barrier();
  		if (ops->id)
6e77cc471   Matthew Wilcox   Convert net_names...
1149
  			ida_free(&net_generic_ids, *ops->id);
3a765edad   Eric W. Biederman   netns: Add an exp...
1150
  	}
f875bae06   Eric W. Biederman   net: Automaticall...
1151
1152
1153
1154
1155
1156
  
  	return error;
  }
  
  static void unregister_pernet_operations(struct pernet_operations *ops)
  {
f875bae06   Eric W. Biederman   net: Automaticall...
1157
  	__unregister_pernet_operations(ops);
3a765edad   Eric W. Biederman   netns: Add an exp...
1158
  	rcu_barrier();
f875bae06   Eric W. Biederman   net: Automaticall...
1159
  	if (ops->id)
6e77cc471   Matthew Wilcox   Convert net_names...
1160
  		ida_free(&net_generic_ids, *ops->id);
f875bae06   Eric W. Biederman   net: Automaticall...
1161
  }
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
  /**
   *      register_pernet_subsys - register a network namespace subsystem
   *	@ops:  pernet operations structure for the subsystem
   *
   *	Register a subsystem which has init and exit functions
   *	that are called when network namespaces are created and
   *	destroyed respectively.
   *
   *	When registered all network namespace init functions are
   *	called for every existing network namespace.  Allowing kernel
   *	modules to have a race free view of the set of network namespaces.
   *
   *	When a new network namespace is created all of the init
   *	methods are called in the order in which they were registered.
   *
   *	When a network namespace is destroyed all of the exit methods
   *	are called in the reverse of the order with which they were
   *	registered.
   */
  int register_pernet_subsys(struct pernet_operations *ops)
  {
  	int error;
4420bf21f   Kirill Tkhai   net: Rename net_s...
1184
  	down_write(&pernet_ops_rwsem);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1185
  	error =  register_pernet_operations(first_device, ops);
4420bf21f   Kirill Tkhai   net: Rename net_s...
1186
  	up_write(&pernet_ops_rwsem);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1187
1188
1189
1190
1191
1192
1193
1194
1195
  	return error;
  }
  EXPORT_SYMBOL_GPL(register_pernet_subsys);
  
  /**
   *      unregister_pernet_subsys - unregister a network namespace subsystem
   *	@ops: pernet operations structure to manipulate
   *
   *	Remove the pernet operations structure from the list to be
53379e57a   Oliver Pinter   typo fixes in net...
1196
   *	used when network namespaces are created or destroyed.  In
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1197
1198
1199
   *	addition run the exit method for all existing network
   *	namespaces.
   */
b3c981d2b   Jiri Pirko   netns: rename unr...
1200
  void unregister_pernet_subsys(struct pernet_operations *ops)
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1201
  {
4420bf21f   Kirill Tkhai   net: Rename net_s...
1202
  	down_write(&pernet_ops_rwsem);
b3c981d2b   Jiri Pirko   netns: rename unr...
1203
  	unregister_pernet_operations(ops);
4420bf21f   Kirill Tkhai   net: Rename net_s...
1204
  	up_write(&pernet_ops_rwsem);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
  }
  EXPORT_SYMBOL_GPL(unregister_pernet_subsys);
  
  /**
   *      register_pernet_device - register a network namespace device
   *	@ops:  pernet operations structure for the subsystem
   *
   *	Register a device which has init and exit functions
   *	that are called when network namespaces are created and
   *	destroyed respectively.
   *
   *	When registered all network namespace init functions are
   *	called for every existing network namespace.  Allowing kernel
   *	modules to have a race free view of the set of network namespaces.
   *
   *	When a new network namespace is created all of the init
   *	methods are called in the order in which they were registered.
   *
   *	When a network namespace is destroyed all of the exit methods
   *	are called in the reverse of the order with which they were
   *	registered.
   */
  int register_pernet_device(struct pernet_operations *ops)
  {
  	int error;
4420bf21f   Kirill Tkhai   net: Rename net_s...
1230
  	down_write(&pernet_ops_rwsem);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1231
1232
1233
  	error = register_pernet_operations(&pernet_list, ops);
  	if (!error && (first_device == &pernet_list))
  		first_device = &ops->list;
4420bf21f   Kirill Tkhai   net: Rename net_s...
1234
  	up_write(&pernet_ops_rwsem);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1235
1236
1237
1238
1239
1240
1241
1242
1243
  	return error;
  }
  EXPORT_SYMBOL_GPL(register_pernet_device);
  
  /**
   *      unregister_pernet_device - unregister a network namespace netdevice
   *	@ops: pernet operations structure to manipulate
   *
   *	Remove the pernet operations structure from the list to be
53379e57a   Oliver Pinter   typo fixes in net...
1244
   *	used when network namespaces are created or destroyed.  In
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1245
1246
1247
1248
1249
   *	addition run the exit method for all existing network
   *	namespaces.
   */
  void unregister_pernet_device(struct pernet_operations *ops)
  {
4420bf21f   Kirill Tkhai   net: Rename net_s...
1250
  	down_write(&pernet_ops_rwsem);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1251
1252
1253
  	if (&ops->list == first_device)
  		first_device = first_device->next;
  	unregister_pernet_operations(ops);
4420bf21f   Kirill Tkhai   net: Rename net_s...
1254
  	up_write(&pernet_ops_rwsem);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1255
1256
  }
  EXPORT_SYMBOL_GPL(unregister_pernet_device);
13b6f5762   Eric W. Biederman   ns proc: Add supp...
1257
1258
  
  #ifdef CONFIG_NET_NS
64964528b   Al Viro   make proc_ns_oper...
1259
  static struct ns_common *netns_get(struct task_struct *task)
13b6f5762   Eric W. Biederman   ns proc: Add supp...
1260
  {
f06305294   Eric W. Biederman   net: Allow settin...
1261
1262
  	struct net *net = NULL;
  	struct nsproxy *nsproxy;
728dba3a3   Eric W. Biederman   namespaces: Use t...
1263
1264
  	task_lock(task);
  	nsproxy = task->nsproxy;
f06305294   Eric W. Biederman   net: Allow settin...
1265
1266
  	if (nsproxy)
  		net = get_net(nsproxy->net_ns);
728dba3a3   Eric W. Biederman   namespaces: Use t...
1267
  	task_unlock(task);
f06305294   Eric W. Biederman   net: Allow settin...
1268

ff24870f4   Al Viro   netns: switch ->g...
1269
1270
1271
1272
1273
1274
  	return net ? &net->ns : NULL;
  }
  
  static inline struct net *to_net_ns(struct ns_common *ns)
  {
  	return container_of(ns, struct net, ns);
13b6f5762   Eric W. Biederman   ns proc: Add supp...
1275
  }
64964528b   Al Viro   make proc_ns_oper...
1276
  static void netns_put(struct ns_common *ns)
13b6f5762   Eric W. Biederman   ns proc: Add supp...
1277
  {
ff24870f4   Al Viro   netns: switch ->g...
1278
  	put_net(to_net_ns(ns));
13b6f5762   Eric W. Biederman   ns proc: Add supp...
1279
  }
f2a8d52e0   Christian Brauner   nsproxy: add stru...
1280
  static int netns_install(struct nsset *nsset, struct ns_common *ns)
13b6f5762   Eric W. Biederman   ns proc: Add supp...
1281
  {
f2a8d52e0   Christian Brauner   nsproxy: add stru...
1282
  	struct nsproxy *nsproxy = nsset->nsproxy;
ff24870f4   Al Viro   netns: switch ->g...
1283
  	struct net *net = to_net_ns(ns);
142e1d1d5   Eric W. Biederman   userns: Allow unp...
1284

5e4a08476   Eric W. Biederman   userns: Require C...
1285
  	if (!ns_capable(net->user_ns, CAP_SYS_ADMIN) ||
f2a8d52e0   Christian Brauner   nsproxy: add stru...
1286
  	    !ns_capable(nsset->cred->user_ns, CAP_SYS_ADMIN))
142e1d1d5   Eric W. Biederman   userns: Allow unp...
1287
  		return -EPERM;
13b6f5762   Eric W. Biederman   ns proc: Add supp...
1288
  	put_net(nsproxy->net_ns);
142e1d1d5   Eric W. Biederman   userns: Allow unp...
1289
  	nsproxy->net_ns = get_net(net);
13b6f5762   Eric W. Biederman   ns proc: Add supp...
1290
1291
  	return 0;
  }
bcac25a58   Andrey Vagin   kernel: add a hel...
1292
1293
1294
1295
  static struct user_namespace *netns_owner(struct ns_common *ns)
  {
  	return to_net_ns(ns)->user_ns;
  }
13b6f5762   Eric W. Biederman   ns proc: Add supp...
1296
1297
1298
1299
1300
1301
  const struct proc_ns_operations netns_operations = {
  	.name		= "net",
  	.type		= CLONE_NEWNET,
  	.get		= netns_get,
  	.put		= netns_put,
  	.install	= netns_install,
bcac25a58   Andrey Vagin   kernel: add a hel...
1302
  	.owner		= netns_owner,
13b6f5762   Eric W. Biederman   ns proc: Add supp...
1303
1304
  };
  #endif