Blame view
net/core/net_namespace.c
32.4 KB
457c89965 treewide: Add SPD... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
e005d193d net: core: Use pr... |
2 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
5f256becd [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 [NET]: Add networ... |
9 |
#include <linux/sched.h> |
c93cf61fd [NETNS]: The net-... |
10 |
#include <linux/idr.h> |
11a28d373 net: make namespa... |
11 |
#include <linux/rculist.h> |
30ffee848 net: move and exp... |
12 |
#include <linux/nsproxy.h> |
0bb80f240 proc: Split the n... |
13 14 |
#include <linux/fs.h> #include <linux/proc_ns.h> |
f06305294 net: Allow settin... |
15 |
#include <linux/file.h> |
bc3b2d7fb net: Add export.h... |
16 |
#include <linux/export.h> |
038e7332b userns: make each... |
17 |
#include <linux/user_namespace.h> |
0c7aecd4b netns: add rtnl c... |
18 |
#include <linux/net_namespace.h> |
f719ff9bc sched/headers: Pr... |
19 |
#include <linux/sched/task.h> |
fbdeaed40 net: create reusa... |
20 |
#include <linux/uidgid.h> |
92acdc58a bpf, net: Rework ... |
21 |
#include <linux/cookie.h> |
f719ff9bc sched/headers: Pr... |
22 |
|
0c7aecd4b netns: add rtnl c... |
23 24 |
#include <net/sock.h> #include <net/netlink.h> |
5f256becd [NET]: Basic netw... |
25 |
#include <net/net_namespace.h> |
dec827d17 [NETNS]: The gene... |
26 |
#include <net/netns/generic.h> |
5f256becd [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 [NET]: Basic netw... |
34 |
|
5f256becd [NET]: Basic netw... |
35 |
LIST_HEAD(net_namespace_list); |
b76a461f1 netns: export net... |
36 |
EXPORT_SYMBOL_GPL(net_namespace_list); |
5f256becd [NET]: Basic netw... |
37 |
|
f0b07bb15 net: Introduce ne... |
38 39 40 |
/* Protects net_namespace_list. Nests iside rtnl_lock() */ DECLARE_RWSEM(net_rwsem); EXPORT_SYMBOL_GPL(net_rwsem); |
9b2426105 keys: Network nam... |
41 42 43 |
#ifdef CONFIG_KEYS static struct key_tag init_net_key_domain = { .usage = REFCOUNT_INIT(1) }; #endif |
734b65417 net: Statically i... |
44 |
struct net init_net = { |
273c28bc5 net: Convert atom... |
45 |
.count = REFCOUNT_INIT(1), |
b5082df80 net: Initialise i... |
46 |
.dev_base_head = LIST_HEAD_INIT(init_net.dev_base_head), |
9b2426105 keys: Network nam... |
47 48 49 |
#ifdef CONFIG_KEYS .key_domain = &init_net_key_domain, #endif |
734b65417 net: Statically i... |
50 |
}; |
ff4b95027 [NETNS]: Re-expor... |
51 |
EXPORT_SYMBOL(init_net); |
5f256becd [NET]: Basic netw... |
52 |
|
f8c46cb39 netns: do not cal... |
53 |
static bool init_net_initialized; |
1a57feb84 net: Introduce ne... |
54 |
/* |
4420bf21f net: Rename net_s... |
55 |
* pernet_ops_rwsem: protects: pernet_list, net_generic_ids, |
1a57feb84 net: Introduce ne... |
56 |
* init_net_initialized and first_device pointer. |
8518e9bb9 net: Add more com... |
57 58 |
* This is internal net namespace object. Please, don't use it * outside. |
1a57feb84 net: Introduce ne... |
59 |
*/ |
4420bf21f net: Rename net_s... |
60 |
DECLARE_RWSEM(pernet_ops_rwsem); |
554873e51 net: Do not take ... |
61 |
EXPORT_SYMBOL_GPL(pernet_ops_rwsem); |
f8c46cb39 netns: do not cal... |
62 |
|
6af2d5fff netns: fix net_ge... |
63 64 |
#define MIN_PERNET_OPS_ID \ ((sizeof(struct net_generic) + sizeof(void *) - 1) / sizeof(void *)) |
dec827d17 [NETNS]: The gene... |
65 |
#define INITIAL_NET_GEN_PTRS 13 /* +1 for len +2 for rcu_head */ |
073862ba5 netns: fix net_al... |
66 |
static unsigned int max_gen_ptrs = INITIAL_NET_GEN_PTRS; |
92acdc58a bpf, net: Rework ... |
67 |
DEFINE_COOKIE(net_cookie); |
f318903c0 bpf: Add netns co... |
68 |
|
92acdc58a bpf, net: Rework ... |
69 |
u64 __net_gen_cookie(struct net *net) |
f318903c0 bpf: Add netns co... |
70 71 72 73 74 75 |
{ while (1) { u64 res = atomic64_read(&net->net_cookie); if (res) return res; |
92acdc58a bpf, net: Rework ... |
76 |
res = gen_cookie_next(&net_cookie); |
f318903c0 bpf: Add netns co... |
77 78 79 |
atomic64_cmpxchg(&net->net_cookie, 0, res); } } |
073862ba5 netns: fix net_al... |
80 81 82 |
static struct net_generic *net_alloc_generic(void) { struct net_generic *ng; |
6af2d5fff netns: fix net_ge... |
83 |
unsigned int generic_size = offsetof(struct net_generic, ptr[max_gen_ptrs]); |
073862ba5 netns: fix net_al... |
84 85 86 |
ng = kzalloc(generic_size, GFP_KERNEL); if (ng) |
9bfc7b996 netns: add dummy ... |
87 |
ng->s.len = max_gen_ptrs; |
073862ba5 netns: fix net_al... |
88 89 90 |
return ng; } |
c7d03a00b netns: make struc... |
91 |
static int net_assign_generic(struct net *net, unsigned int id, void *data) |
05fceb4ad net: disallow to ... |
92 93 |
{ struct net_generic *ng, *old_ng; |
6af2d5fff netns: fix net_ge... |
94 |
BUG_ON(id < MIN_PERNET_OPS_ID); |
05fceb4ad net: disallow to ... |
95 |
|
1c87733d0 net_ns: add __rcu... |
96 |
old_ng = rcu_dereference_protected(net->gen, |
4420bf21f net: Rename net_s... |
97 |
lockdep_is_held(&pernet_ops_rwsem)); |
6af2d5fff netns: fix net_ge... |
98 99 |
if (old_ng->s.len > id) { old_ng->ptr[id] = data; |
1a9a05920 netns: publish ne... |
100 101 |
return 0; } |
05fceb4ad net: disallow to ... |
102 |
|
073862ba5 netns: fix net_al... |
103 |
ng = net_alloc_generic(); |
05fceb4ad 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 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 net: disallow to ... |
120 121 |
rcu_assign_pointer(net->gen, ng); |
9bfc7b996 netns: add dummy ... |
122 |
kfree_rcu(old_ng, s.rcu); |
05fceb4ad net: disallow to ... |
123 124 |
return 0; } |
f875bae06 net: Automaticall... |
125 126 |
static int ops_init(const struct pernet_operations *ops, struct net *net) { |
b922934d0 netns: do not lea... |
127 128 |
int err = -ENOMEM; void *data = NULL; |
f875bae06 net: Automaticall... |
129 |
if (ops->id && ops->size) { |
b922934d0 netns: do not lea... |
130 |
data = kzalloc(ops->size, GFP_KERNEL); |
f875bae06 net: Automaticall... |
131 |
if (!data) |
b922934d0 netns: do not lea... |
132 |
goto out; |
f875bae06 net: Automaticall... |
133 134 |
err = net_assign_generic(net, *ops->id, data); |
b922934d0 netns: do not lea... |
135 136 |
if (err) goto cleanup; |
f875bae06 net: Automaticall... |
137 |
} |
b922934d0 netns: do not lea... |
138 |
err = 0; |
f875bae06 net: Automaticall... |
139 |
if (ops->init) |
b922934d0 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 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 netns: make struc... |
154 |
kfree(net_generic(net, *ops->id)); |
f875bae06 net: Automaticall... |
155 156 |
} } |
d7d99872c 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 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 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 netns: use a spin... |
188 |
/* should be called with nsid_lock held */ |
0c7aecd4b netns: add rtnl c... |
189 190 |
static int alloc_netid(struct net *net, struct net *peer, int reqid) { |
3138dbf88 netns: notify new... |
191 |
int min = 0, max = 0; |
0c7aecd4b netns: add rtnl c... |
192 |
|
0c7aecd4b netns: add rtnl c... |
193 194 195 196 |
if (reqid >= 0) { min = reqid; max = reqid + 1; } |
95f38411d netns: use a spin... |
197 |
return idr_alloc(&net->netns_ids, peer, min, max, GFP_ATOMIC); |
0c7aecd4b 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 netns: protect ne... |
212 |
/* Must be called from RCU-critical section or with nsid_lock held */ |
490529416 netns: Remove __p... |
213 |
static int __peernet2id(const struct net *net, struct net *peer) |
0c7aecd4b netns: add rtnl c... |
214 215 |
{ int id = idr_for_each(&net->netns_ids, net_eq_idr, peer); |
3138dbf88 netns: notify new... |
216 |
|
0c7aecd4b 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 netns: returns al... |
222 |
return NETNSA_NSID_NOT_ASSIGNED; |
0c7aecd4b netns: add rtnl c... |
223 |
} |
993e4c929 netns: fix NLM_F_... |
224 |
static void rtnl_net_notifyid(struct net *net, int cmd, int id, u32 portid, |
d4e4fdf9e netns: fix GFP fl... |
225 |
struct nlmsghdr *nlh, gfp_t gfp); |
0c7aecd4b 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 netns: fix GFP fl... |
229 |
int peernet2id_alloc(struct net *net, struct net *peer, gfp_t gfp) |
0c7aecd4b netns: add rtnl c... |
230 |
{ |
3138dbf88 netns: notify new... |
231 |
int id; |
0c7aecd4b netns: add rtnl c... |
232 |
|
273c28bc5 net: Convert atom... |
233 |
if (refcount_read(&net->count) == 0) |
cfc44a4d1 net: check dead n... |
234 |
return NETNSA_NSID_NOT_ASSIGNED; |
490529416 netns: Remove __p... |
235 |
|
e1f469cd5 Revert "netns: do... |
236 |
spin_lock_bh(&net->nsid_lock); |
490529416 netns: Remove __p... |
237 238 |
id = __peernet2id(net, peer); if (id >= 0) { |
e1f469cd5 Revert "netns: do... |
239 |
spin_unlock_bh(&net->nsid_lock); |
490529416 netns: Remove __p... |
240 241 242 243 |
return id; } /* When peer is obtained from RCU lists, we may race with |
0c06bea91 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 netns: Remove __p... |
248 |
if (!maybe_get_net(peer)) { |
e1f469cd5 Revert "netns: do... |
249 |
spin_unlock_bh(&net->nsid_lock); |
490529416 netns: Remove __p... |
250 251 252 253 |
return NETNSA_NSID_NOT_ASSIGNED; } id = alloc_netid(net, peer, -1); |
e1f469cd5 Revert "netns: do... |
254 |
spin_unlock_bh(&net->nsid_lock); |
490529416 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 netns: notify new... |
261 |
return id; |
0c7aecd4b netns: add rtnl c... |
262 |
} |
7cbebc8a1 net: export peern... |
263 |
EXPORT_SYMBOL_GPL(peernet2id_alloc); |
0c7aecd4b netns: add rtnl c... |
264 |
|
95f38411d netns: use a spin... |
265 |
/* This function returns, if assigned, the id of a peer netns. */ |
56f200c78 netns: Constify e... |
266 |
int peernet2id(const struct net *net, struct net *peer) |
95f38411d netns: use a spin... |
267 |
{ |
95f38411d netns: use a spin... |
268 |
int id; |
2dce224f4 netns: protect ne... |
269 |
rcu_read_lock(); |
95f38411d netns: use a spin... |
270 |
id = __peernet2id(net, peer); |
2dce224f4 netns: protect ne... |
271 |
rcu_read_unlock(); |
95f38411d netns: use a spin... |
272 273 |
return id; } |
38f507f1b vxlan: call peern... |
274 |
EXPORT_SYMBOL(peernet2id); |
95f38411d netns: use a spin... |
275 |
|
59324cf35 netlink: allow to... |
276 277 278 |
/* This function returns true is the peer netns has an id assigned into the * current netns. */ |
56f200c78 netns: Constify e... |
279 |
bool peernet_has_id(const struct net *net, struct net *peer) |
59324cf35 netlink: allow to... |
280 281 282 |
{ return peernet2id(net, peer) >= 0; } |
56f200c78 netns: Constify e... |
283 |
struct net *get_net_ns_by_id(const struct net *net, int id) |
0c7aecd4b 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 net: Fix double f... |
293 |
peer = maybe_get_net(peer); |
0c7aecd4b netns: add rtnl c... |
294 295 296 297 |
rcu_read_unlock(); return peer; } |
5f256becd [NET]: Basic netw... |
298 299 300 |
/* * setup_net runs the initializers for the network namespace object. */ |
038e7332b userns: make each... |
301 |
static __net_init int setup_net(struct net *net, struct user_namespace *user_ns) |
5f256becd [NET]: Basic netw... |
302 |
{ |
4420bf21f net: Rename net_s... |
303 |
/* Must be called with pernet_ops_rwsem held */ |
f875bae06 net: Automaticall... |
304 |
const struct pernet_operations *ops, *saved_ops; |
486a87f1e netns: fix double... |
305 |
int error = 0; |
72ad937ab net: Add support ... |
306 |
LIST_HEAD(net_exit_list); |
5f256becd [NET]: Basic netw... |
307 |
|
273c28bc5 net: Convert atom... |
308 |
refcount_set(&net->count, 1); |
c122e14df net: convert net.... |
309 |
refcount_set(&net->passive, 1); |
355b98553 netns: provide pu... |
310 |
get_random_bytes(&net->hash_mix, sizeof(u32)); |
4e985adaa rtnl: provide lin... |
311 |
net->dev_base_seq = 1; |
038e7332b userns: make each... |
312 |
net->user_ns = user_ns; |
0c7aecd4b netns: add rtnl c... |
313 |
idr_init(&net->netns_ids); |
de133464c netns: make nsid_... |
314 |
spin_lock_init(&net->nsid_lock); |
d9ff30497 net: Replace ip_r... |
315 |
mutex_init(&net->ipv4.ra_mutex); |
486a87f1e netns: fix double... |
316 |
|
768f3591e [NETNS]: Cleanup ... |
317 |
list_for_each_entry(ops, &pernet_list, list) { |
f875bae06 net: Automaticall... |
318 319 320 |
error = ops_init(ops, net); if (error < 0) goto out_undo; |
5f256becd [NET]: Basic netw... |
321 |
} |
f0b07bb15 net: Introduce ne... |
322 |
down_write(&net_rwsem); |
98f6c533a net: Assign net t... |
323 |
list_add_tail_rcu(&net->list, &net_namespace_list); |
f0b07bb15 net: Introduce ne... |
324 |
up_write(&net_rwsem); |
5f256becd [NET]: Basic netw... |
325 326 |
out: return error; |
768f3591e [NETNS]: Cleanup ... |
327 |
|
5f256becd [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 net: Add support ... |
332 |
list_add(&net->exit_list, &net_exit_list); |
f875bae06 net: Automaticall... |
333 |
saved_ops = ops; |
72ad937ab net: Add support ... |
334 |
list_for_each_entry_continue_reverse(ops, &pernet_list, list) |
d7d99872c netns: add pre_ex... |
335 336 337 |
ops_pre_exit_list(ops, &net_exit_list); synchronize_rcu(); |
b272a0ad7 netns: restore op... |
338 |
ops = saved_ops; |
d7d99872c netns: add pre_ex... |
339 |
list_for_each_entry_continue_reverse(ops, &pernet_list, list) |
72ad937ab net: Add support ... |
340 |
ops_exit_list(ops, &net_exit_list); |
f875bae06 net: Automaticall... |
341 342 |
ops = saved_ops; list_for_each_entry_continue_reverse(ops, &pernet_list, list) |
72ad937ab net: Add support ... |
343 |
ops_free_list(ops, &net_exit_list); |
310928d96 [NETNS]: fix net ... |
344 345 |
rcu_barrier(); |
5f256becd [NET]: Basic netw... |
346 347 |
goto out; } |
7c3f1875c 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 [NET]: Hide the d... |
367 |
|
ebe47d47b netns: build fix ... |
368 |
#ifdef CONFIG_NET_NS |
2ed6afdee 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 net: make kmem ca... |
378 |
static struct kmem_cache *net_cachep __ro_after_init; |
ebe47d47b netns: build fix ... |
379 |
static struct workqueue_struct *netns_wq; |
486a87f1e netns: fix double... |
380 |
static struct net *net_alloc(void) |
45a19b0a7 [NETNS]: Fix comp... |
381 |
{ |
486a87f1e 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 [NETNS]: Fix comp... |
390 |
if (!net) |
486a87f1e netns: fix double... |
391 |
goto out_free; |
45a19b0a7 [NETNS]: Fix comp... |
392 |
|
9b2426105 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 netns: fix double... |
399 400 401 |
rcu_assign_pointer(net->gen, ng); out: return net; |
9b2426105 keys: Network nam... |
402 403 404 405 406 |
#ifdef CONFIG_KEYS out_free_2: kmem_cache_free(net_cachep, net); net = NULL; #endif |
486a87f1e netns: fix double... |
407 408 409 410 411 412 413 |
out_free: kfree(ng); goto out; } static void net_free(struct net *net) { |
416c51e17 netns: remove one... |
414 |
kfree(rcu_access_pointer(net->gen)); |
45a19b0a7 [NETNS]: Fix comp... |
415 416 |
kmem_cache_free(net_cachep, net); } |
a685e0898 Delay struct net ... |
417 418 419 |
void net_drop_ns(void *p) { struct net *ns = p; |
c122e14df net: convert net.... |
420 |
if (ns && refcount_dec_and_test(&ns->passive)) |
a685e0898 Delay struct net ... |
421 422 |
net_free(ns); } |
038e7332b userns: make each... |
423 424 |
struct net *copy_net_ns(unsigned long flags, struct user_namespace *user_ns, struct net *old_net) |
9dd776b6d [NET]: Add networ... |
425 |
{ |
703286608 netns: Add a limi... |
426 |
struct ucounts *ucounts; |
088eb2d90 netns 2/2: extrac... |
427 428 |
struct net *net; int rv; |
9dd776b6d [NET]: Add networ... |
429 |
|
911cb193f net: minor cleanu... |
430 431 |
if (!(flags & CLONE_NEWNET)) return get_net(old_net); |
703286608 netns: Add a limi... |
432 433 |
ucounts = inc_net_namespaces(user_ns); if (!ucounts) |
df75e7748 userns: When the ... |
434 |
return ERR_PTR(-ENOSPC); |
703286608 netns: Add a limi... |
435 |
|
088eb2d90 netns 2/2: extrac... |
436 |
net = net_alloc(); |
703286608 netns: Add a limi... |
437 |
if (!net) { |
5ba049a5c net: Cleanup in c... |
438 439 |
rv = -ENOMEM; goto dec_ucounts; |
703286608 netns: Add a limi... |
440 |
} |
5ba049a5c net: Cleanup in c... |
441 442 |
refcount_set(&net->passive, 1); net->ucounts = ucounts; |
038e7332b userns: make each... |
443 |
get_user_ns(user_ns); |
094374e5e net: Reflect all ... |
444 |
|
4420bf21f net: Rename net_s... |
445 |
rv = down_read_killable(&pernet_ops_rwsem); |
5ba049a5c net: Cleanup in c... |
446 447 |
if (rv < 0) goto put_userns; |
19efbd93e net: Kill net_mutex |
448 |
|
038e7332b userns: make each... |
449 |
rv = setup_net(net, user_ns); |
19efbd93e net: Kill net_mutex |
450 |
|
4420bf21f net: Rename net_s... |
451 |
up_read(&pernet_ops_rwsem); |
19efbd93e net: Kill net_mutex |
452 |
|
088eb2d90 netns 2/2: extrac... |
453 |
if (rv < 0) { |
5ba049a5c net: Cleanup in c... |
454 |
put_userns: |
82ecff655 keys: Fix memory ... |
455 |
key_remove_domain(net->key_domain); |
038e7332b userns: make each... |
456 |
put_user_ns(user_ns); |
a685e0898 Delay struct net ... |
457 |
net_drop_ns(net); |
5ba049a5c net: Cleanup in c... |
458 459 |
dec_ucounts: dec_net_namespaces(ucounts); |
088eb2d90 netns 2/2: extrac... |
460 461 462 463 |
return ERR_PTR(rv); } return net; } |
486a87f1e netns: fix double... |
464 |
|
fbdeaed40 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 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 net: Introduce ne... |
498 |
* use for_each_net_rcu() or net_rwsem. |
fb07a820f net: Move net:net... |
499 500 501 |
*/ for_each_net(tmp) { int id; |
e1f469cd5 Revert "netns: do... |
502 |
spin_lock_bh(&tmp->nsid_lock); |
fb07a820f net: Move net:net... |
503 504 505 |
id = __peernet2id(tmp, net); if (id >= 0) idr_remove(&tmp->netns_ids, id); |
e1f469cd5 Revert "netns: do... |
506 |
spin_unlock_bh(&tmp->nsid_lock); |
fb07a820f net: Move net:net... |
507 |
if (id >= 0) |
d4e4fdf9e netns: fix GFP fl... |
508 509 |
rtnl_net_notifyid(tmp, RTM_DELNSID, id, 0, NULL, GFP_KERNEL); |
fb07a820f net: Move net:net... |
510 511 512 |
if (tmp == last) break; } |
e1f469cd5 Revert "netns: do... |
513 |
spin_lock_bh(&net->nsid_lock); |
fb07a820f net: Move net:net... |
514 |
idr_destroy(&net->netns_ids); |
e1f469cd5 Revert "netns: do... |
515 |
spin_unlock_bh(&net->nsid_lock); |
fb07a820f net: Move net:net... |
516 |
} |
65b7b5b90 net: Make cleanup... |
517 |
static LLIST_HEAD(cleanup_list); |
2b035b399 net: Batch networ... |
518 |
|
6a1a3b9f6 [NET]: Hide the d... |
519 520 |
static void cleanup_net(struct work_struct *work) { |
f875bae06 net: Automaticall... |
521 |
const struct pernet_operations *ops; |
fb07a820f net: Move net:net... |
522 |
struct net *net, *tmp, *last; |
65b7b5b90 net: Make cleanup... |
523 |
struct llist_node *net_kill_list; |
72ad937ab net: Add support ... |
524 |
LIST_HEAD(net_exit_list); |
6a1a3b9f6 [NET]: Hide the d... |
525 |
|
2b035b399 net: Batch networ... |
526 |
/* Atomically snapshot the list of namespaces to cleanup */ |
65b7b5b90 net: Make cleanup... |
527 |
net_kill_list = llist_del_all(&cleanup_list); |
6a1a3b9f6 [NET]: Hide the d... |
528 |
|
4420bf21f net: Rename net_s... |
529 |
down_read(&pernet_ops_rwsem); |
6a1a3b9f6 [NET]: Hide the d... |
530 531 |
/* Don't let anyone else find us. */ |
f0b07bb15 net: Introduce ne... |
532 |
down_write(&net_rwsem); |
65b7b5b90 net: Make cleanup... |
533 |
llist_for_each_entry(net, net_kill_list, cleanup_list) |
2b035b399 net: Batch networ... |
534 |
list_del_rcu(&net->list); |
fb07a820f 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 net: Introduce ne... |
546 |
up_write(&net_rwsem); |
6d458f5b4 Revert "netns: do... |
547 |
|
65b7b5b90 net: Make cleanup... |
548 |
llist_for_each_entry(net, net_kill_list, cleanup_list) { |
fb07a820f net: Move net:net... |
549 550 |
unhash_nsid(net, last); list_add_tail(&net->exit_list, &net_exit_list); |
72ad937ab net: Add support ... |
551 |
} |
6a1a3b9f6 [NET]: Hide the d... |
552 |
|
d7d99872c 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 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 netns: add pre_ex... |
560 |
* Also the pre_exit() and exit() methods need this barrier. |
11a28d373 net: make namespa... |
561 562 |
*/ synchronize_rcu(); |
6a1a3b9f6 [NET]: Hide the d... |
563 |
/* Run all of the network namespace exit methods */ |
72ad937ab net: Add support ... |
564 565 |
list_for_each_entry_reverse(ops, &pernet_list, list) ops_exit_list(ops, &net_exit_list); |
f875bae06 net: Automaticall... |
566 |
/* Free the net generic variables */ |
72ad937ab net: Add support ... |
567 568 |
list_for_each_entry_reverse(ops, &pernet_list, list) ops_free_list(ops, &net_exit_list); |
6a1a3b9f6 [NET]: Hide the d... |
569 |
|
4420bf21f net: Rename net_s... |
570 |
up_read(&pernet_ops_rwsem); |
6a1a3b9f6 [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 net: Add support ... |
578 579 |
list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) { list_del_init(&net->exit_list); |
703286608 netns: Add a limi... |
580 |
dec_net_namespaces(net->ucounts); |
9b2426105 keys: Network nam... |
581 |
key_remove_domain(net->key_domain); |
038e7332b userns: make each... |
582 |
put_user_ns(net->user_ns); |
a685e0898 Delay struct net ... |
583 |
net_drop_ns(net); |
2b035b399 net: Batch networ... |
584 |
} |
6a1a3b9f6 [NET]: Hide the d... |
585 |
} |
7866cc57b 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 net: Rename net_s... |
598 599 |
down_write(&pernet_ops_rwsem); up_write(&pernet_ops_rwsem); |
7866cc57b netns: add and us... |
600 601 |
} EXPORT_SYMBOL(net_ns_barrier); |
2b035b399 net: Batch networ... |
602 |
static DECLARE_WORK(net_cleanup_work, cleanup_net); |
6a1a3b9f6 [NET]: Hide the d... |
603 604 605 606 |
void __put_net(struct net *net) { /* Cleanup the network namespace in process context */ |
8349efd90 net: Queue net_cl... |
607 608 |
if (llist_add(&net->cleanup_list, &cleanup_list)) queue_work(netns_wq, &net_cleanup_work); |
6a1a3b9f6 [NET]: Hide the d... |
609 610 |
} EXPORT_SYMBOL_GPL(__put_net); |
956c92078 net: fix get_net_... |
611 612 |
struct net *get_net_ns_by_fd(int fd) { |
956c92078 net: fix get_net_... |
613 |
struct file *file; |
33c429405 copy address of p... |
614 |
struct ns_common *ns; |
956c92078 net: fix get_net_... |
615 |
struct net *net; |
956c92078 net: fix get_net_... |
616 |
file = proc_ns_fget(fd); |
c316e6a30 get_net_ns_by_fd(... |
617 618 |
if (IS_ERR(file)) return ERR_CAST(file); |
956c92078 net: fix get_net_... |
619 |
|
f77c80142 bury struct proc_... |
620 |
ns = get_proc_ns(file_inode(file)); |
33c429405 copy address of p... |
621 622 |
if (ns->ops == &netns_operations) net = get_net(container_of(ns, struct net, ns)); |
c316e6a30 get_net_ns_by_fd(... |
623 624 |
else net = ERR_PTR(-EINVAL); |
956c92078 net: fix get_net_... |
625 |
|
c316e6a30 get_net_ns_by_fd(... |
626 |
fput(file); |
956c92078 net: fix get_net_... |
627 628 |
return net; } |
6a1a3b9f6 [NET]: Hide the d... |
629 |
#else |
956c92078 net: fix get_net_... |
630 631 632 633 |
struct net *get_net_ns_by_fd(int fd) { return ERR_PTR(-EINVAL); } |
6a1a3b9f6 [NET]: Hide the d... |
634 |
#endif |
4b681c82d nl80211: Allow se... |
635 |
EXPORT_SYMBOL_GPL(get_net_ns_by_fd); |
6a1a3b9f6 [NET]: Hide the d... |
636 |
|
30ffee848 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 namespaces: Use t... |
648 649 |
task_lock(tsk); nsproxy = tsk->nsproxy; |
30ffee848 net: move and exp... |
650 651 |
if (nsproxy) net = get_net(nsproxy->net_ns); |
728dba3a3 namespaces: Use t... |
652 |
task_unlock(tsk); |
30ffee848 net: move and exp... |
653 654 655 656 657 |
} rcu_read_unlock(); return net; } EXPORT_SYMBOL_GPL(get_net_ns_by_pid); |
98f842e67 proc: Usable inod... |
658 659 |
static __net_init int net_ns_net_init(struct net *net) { |
33c429405 copy address of p... |
660 661 662 |
#ifdef CONFIG_NET_NS net->ns.ops = &netns_operations; #endif |
6344c433a new helpers: ns_a... |
663 |
return ns_alloc_inum(&net->ns); |
98f842e67 proc: Usable inod... |
664 665 666 667 |
} static __net_exit void net_ns_net_exit(struct net *net) { |
6344c433a new helpers: ns_a... |
668 |
ns_free_inum(&net->ns); |
98f842e67 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 netns: make nla_p... |
675 |
static const struct nla_policy rtnl_net_policy[NETNSA_MAX + 1] = { |
0c7aecd4b 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 netns: add suppor... |
680 |
[NETNSA_TARGET_NSID] = { .type = NLA_S32 }, |
0c7aecd4b netns: add rtnl c... |
681 |
}; |
c21ef3e34 net: rtnetlink: p... |
682 683 |
static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) |
0c7aecd4b netns: add rtnl c... |
684 685 686 |
{ struct net *net = sock_net(skb->sk); struct nlattr *tb[NETNSA_MAX + 1]; |
4a7f7bc60 netns: define ext... |
687 |
struct nlattr *nla; |
0c7aecd4b netns: add rtnl c... |
688 689 |
struct net *peer; int nsid, err; |
8cb081746 netlink: make val... |
690 691 |
err = nlmsg_parse_deprecated(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX, rtnl_net_policy, extack); |
0c7aecd4b netns: add rtnl c... |
692 693 |
if (err < 0) return err; |
4a7f7bc60 netns: define ext... |
694 695 |
if (!tb[NETNSA_NSID]) { NL_SET_ERR_MSG(extack, "nsid is missing"); |
0c7aecd4b netns: add rtnl c... |
696 |
return -EINVAL; |
4a7f7bc60 netns: define ext... |
697 |
} |
0c7aecd4b netns: add rtnl c... |
698 |
nsid = nla_get_s32(tb[NETNSA_NSID]); |
4a7f7bc60 netns: define ext... |
699 |
if (tb[NETNSA_PID]) { |
0c7aecd4b netns: add rtnl c... |
700 |
peer = get_net_ns_by_pid(nla_get_u32(tb[NETNSA_PID])); |
4a7f7bc60 netns: define ext... |
701 702 |
nla = tb[NETNSA_PID]; } else if (tb[NETNSA_FD]) { |
0c7aecd4b netns: add rtnl c... |
703 |
peer = get_net_ns_by_fd(nla_get_u32(tb[NETNSA_FD])); |
4a7f7bc60 netns: define ext... |
704 705 706 |
nla = tb[NETNSA_FD]; } else { NL_SET_ERR_MSG(extack, "Peer netns reference is missing"); |
0c7aecd4b netns: add rtnl c... |
707 |
return -EINVAL; |
4a7f7bc60 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 netns: add rtnl c... |
712 |
return PTR_ERR(peer); |
4a7f7bc60 netns: define ext... |
713 |
} |
0c7aecd4b netns: add rtnl c... |
714 |
|
e1f469cd5 Revert "netns: do... |
715 |
spin_lock_bh(&net->nsid_lock); |
3138dbf88 netns: notify new... |
716 |
if (__peernet2id(net, peer) >= 0) { |
e1f469cd5 Revert "netns: do... |
717 |
spin_unlock_bh(&net->nsid_lock); |
0c7aecd4b netns: add rtnl c... |
718 |
err = -EEXIST; |
4a7f7bc60 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 netns: add rtnl c... |
722 723 724 725 |
goto out; } err = alloc_netid(net, peer, nsid); |
e1f469cd5 Revert "netns: do... |
726 |
spin_unlock_bh(&net->nsid_lock); |
3138dbf88 netns: notify new... |
727 |
if (err >= 0) { |
993e4c929 netns: fix NLM_F_... |
728 |
rtnl_net_notifyid(net, RTM_NEWNSID, err, NETLINK_CB(skb).portid, |
d4e4fdf9e netns: fix GFP fl... |
729 |
nlh, GFP_KERNEL); |
0c7aecd4b netns: add rtnl c... |
730 |
err = 0; |
4a7f7bc60 netns: define ext... |
731 |
} else if (err == -ENOSPC && nsid >= 0) { |
10d486a30 netns: fix error ... |
732 |
err = -EEXIST; |
4a7f7bc60 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 netns: notify new... |
735 |
} |
0c7aecd4b 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 netns: enable to ... |
745 |
+ nla_total_size(sizeof(s32)) /* NETNSA_CURRENT_NSID */ |
0c7aecd4b netns: add rtnl c... |
746 747 |
; } |
a0732ad14 netns: introduce ... |
748 749 750 751 752 753 |
struct net_fill_args { u32 portid; u32 seq; int flags; int cmd; int nsid; |
288f06a00 netns: enable to ... |
754 755 |
bool add_ref; int ref_nsid; |
a0732ad14 netns: introduce ... |
756 757 758 |
}; static int rtnl_net_fill(struct sk_buff *skb, struct net_fill_args *args) |
0c7aecd4b netns: add rtnl c... |
759 760 761 |
{ struct nlmsghdr *nlh; struct rtgenmsg *rth; |
0c7aecd4b netns: add rtnl c... |
762 |
|
a0732ad14 netns: introduce ... |
763 764 |
nlh = nlmsg_put(skb, args->portid, args->seq, args->cmd, sizeof(*rth), args->flags); |
0c7aecd4b netns: add rtnl c... |
765 766 767 768 769 |
if (!nlh) return -EMSGSIZE; rth = nlmsg_data(nlh); rth->rtgen_family = AF_UNSPEC; |
a0732ad14 netns: introduce ... |
770 |
if (nla_put_s32(skb, NETNSA_NSID, args->nsid)) |
0c7aecd4b netns: add rtnl c... |
771 |
goto nla_put_failure; |
288f06a00 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 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 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 netlink: make val... |
790 791 792 |
return nlmsg_parse_deprecated(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX, rtnl_net_policy, extack); |
4d165f614 net: namespace: p... |
793 |
|
8cb081746 netlink: make val... |
794 795 796 |
err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX, rtnl_net_policy, extack); |
4d165f614 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 net: rtnetlink: p... |
818 819 |
static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) |
0c7aecd4b netns: add rtnl c... |
820 821 822 |
{ struct net *net = sock_net(skb->sk); struct nlattr *tb[NETNSA_MAX + 1]; |
a0732ad14 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 netns: add suppor... |
828 |
struct net *peer, *target = net; |
4a7f7bc60 netns: define ext... |
829 |
struct nlattr *nla; |
0c7aecd4b netns: add rtnl c... |
830 |
struct sk_buff *msg; |
a0732ad14 netns: introduce ... |
831 |
int err; |
0c7aecd4b netns: add rtnl c... |
832 |
|
4d165f614 net: namespace: p... |
833 |
err = rtnl_net_valid_getid_req(skb, nlh, tb, extack); |
0c7aecd4b netns: add rtnl c... |
834 835 |
if (err < 0) return err; |
4a7f7bc60 netns: define ext... |
836 |
if (tb[NETNSA_PID]) { |
0c7aecd4b netns: add rtnl c... |
837 |
peer = get_net_ns_by_pid(nla_get_u32(tb[NETNSA_PID])); |
4a7f7bc60 netns: define ext... |
838 839 |
nla = tb[NETNSA_PID]; } else if (tb[NETNSA_FD]) { |
0c7aecd4b netns: add rtnl c... |
840 |
peer = get_net_ns_by_fd(nla_get_u32(tb[NETNSA_FD])); |
4a7f7bc60 netns: define ext... |
841 |
nla = tb[NETNSA_FD]; |
3a4f68bf6 netns: enable to ... |
842 |
} else if (tb[NETNSA_NSID]) { |
ecce39ec1 netns: read NETNS... |
843 |
peer = get_net_ns_by_id(net, nla_get_s32(tb[NETNSA_NSID])); |
3a4f68bf6 netns: enable to ... |
844 845 846 |
if (!peer) peer = ERR_PTR(-ENOENT); nla = tb[NETNSA_NSID]; |
4a7f7bc60 netns: define ext... |
847 848 |
} else { NL_SET_ERR_MSG(extack, "Peer netns reference is missing"); |
0c7aecd4b netns: add rtnl c... |
849 |
return -EINVAL; |
4a7f7bc60 netns: define ext... |
850 |
} |
0c7aecd4b netns: add rtnl c... |
851 |
|
4a7f7bc60 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 netns: add rtnl c... |
855 |
return PTR_ERR(peer); |
4a7f7bc60 netns: define ext... |
856 |
} |
0c7aecd4b netns: add rtnl c... |
857 |
|
cff478b9d 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 netns: enable to ... |
869 870 |
fillargs.add_ref = true; fillargs.ref_nsid = peernet2id(net, peer); |
cff478b9d netns: add suppor... |
871 |
} |
0c7aecd4b 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 netns: add suppor... |
877 |
fillargs.nsid = peernet2id(target, peer); |
a0732ad14 netns: introduce ... |
878 |
err = rtnl_net_fill(msg, &fillargs); |
0c7aecd4b 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 netns: enable to ... |
888 |
if (fillargs.add_ref) |
cff478b9d netns: add suppor... |
889 |
put_net(target); |
0c7aecd4b netns: add rtnl c... |
890 891 892 |
put_net(peer); return err; } |
a143c40c3 netns: allow to d... |
893 |
struct rtnl_net_dump_cb { |
cff478b9d netns: add suppor... |
894 |
struct net *tgt_net; |
288f06a00 netns: enable to ... |
895 |
struct net *ref_net; |
a143c40c3 netns: allow to d... |
896 |
struct sk_buff *skb; |
a0732ad14 netns: introduce ... |
897 |
struct net_fill_args fillargs; |
a143c40c3 netns: allow to d... |
898 899 900 |
int idx; int s_idx; }; |
2dce224f4 netns: protect ne... |
901 |
/* Runs in RCU-critical section. */ |
a143c40c3 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 netns: introduce ... |
909 |
net_cb->fillargs.nsid = id; |
288f06a00 netns: enable to ... |
910 911 |
if (net_cb->fillargs.add_ref) net_cb->fillargs.ref_nsid = __peernet2id(net_cb->ref_net, peer); |
a0732ad14 netns: introduce ... |
912 |
ret = rtnl_net_fill(net_cb->skb, &net_cb->fillargs); |
a143c40c3 netns: allow to d... |
913 914 915 916 917 918 919 |
if (ret < 0) return ret; cont: net_cb->idx++; return 0; } |
cff478b9d 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 netlink: make val... |
927 928 929 |
err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX, rtnl_net_policy, extack); |
cff478b9d 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 netns: enable to ... |
947 948 |
net_cb->fillargs.add_ref = true; net_cb->ref_net = net_cb->tgt_net; |
cff478b9d netns: add suppor... |
949 |
net_cb->tgt_net = net; |
cff478b9d 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 netns: allow to d... |
960 961 |
static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb) { |
a143c40c3 netns: allow to d... |
962 |
struct rtnl_net_dump_cb net_cb = { |
cff478b9d netns: add suppor... |
963 |
.tgt_net = sock_net(skb->sk), |
a143c40c3 netns: allow to d... |
964 |
.skb = skb, |
a0732ad14 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 netns: allow to d... |
971 972 973 |
.idx = 0, .s_idx = cb->args[0], }; |
cff478b9d netns: add suppor... |
974 |
int err = 0; |
a143c40c3 netns: allow to d... |
975 |
|
cff478b9d 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 net/namespace: Up... |
980 |
} |
2dce224f4 netns: protect ne... |
981 |
rcu_read_lock(); |
cff478b9d netns: add suppor... |
982 |
idr_for_each(&net_cb.tgt_net->netns_ids, rtnl_net_dumpid_one, &net_cb); |
2dce224f4 netns: protect ne... |
983 |
rcu_read_unlock(); |
a143c40c3 netns: allow to d... |
984 985 |
cb->args[0] = net_cb.idx; |
cff478b9d netns: add suppor... |
986 |
end: |
288f06a00 netns: enable to ... |
987 |
if (net_cb.fillargs.add_ref) |
cff478b9d netns: add suppor... |
988 989 |
put_net(net_cb.tgt_net); return err < 0 ? err : skb->len; |
a143c40c3 netns: allow to d... |
990 |
} |
993e4c929 netns: fix NLM_F_... |
991 |
static void rtnl_net_notifyid(struct net *net, int cmd, int id, u32 portid, |
d4e4fdf9e netns: fix GFP fl... |
992 |
struct nlmsghdr *nlh, gfp_t gfp) |
9a9634545 netns: notify net... |
993 |
{ |
a0732ad14 netns: introduce ... |
994 |
struct net_fill_args fillargs = { |
993e4c929 netns: fix NLM_F_... |
995 996 |
.portid = portid, .seq = nlh ? nlh->nlmsg_seq : 0, |
a0732ad14 netns: introduce ... |
997 998 999 |
.cmd = cmd, .nsid = id, }; |
9a9634545 netns: notify net... |
1000 1001 |
struct sk_buff *msg; int err = -ENOMEM; |
d4e4fdf9e netns: fix GFP fl... |
1002 |
msg = nlmsg_new(rtnl_net_get_size(), gfp); |
9a9634545 netns: notify net... |
1003 1004 |
if (!msg) goto out; |
a0732ad14 netns: introduce ... |
1005 |
err = rtnl_net_fill(msg, &fillargs); |
9a9634545 netns: notify net... |
1006 1007 |
if (err < 0) goto err_out; |
d4e4fdf9e netns: fix GFP fl... |
1008 |
rtnl_notify(msg, net, portid, RTNLGRP_NSID, nlh, gfp); |
9a9634545 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 [NET]: Basic netw... |
1016 1017 |
static int __init net_ns_init(void) { |
486a87f1e netns: fix double... |
1018 |
struct net_generic *ng; |
5f256becd [NET]: Basic netw... |
1019 |
|
d57a9212e [NET]: Hide the n... |
1020 |
#ifdef CONFIG_NET_NS |
5f256becd [NET]: Basic netw... |
1021 1022 |
net_cachep = kmem_cache_create("net_namespace", sizeof(struct net), SMP_CACHE_BYTES, |
30855ffc2 net: Make account... |
1023 |
SLAB_PANIC|SLAB_ACCOUNT, NULL); |
3ef1355dc [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 [NET]: Hide the n... |
1029 |
#endif |
3ef1355dc [NET]: Make netns... |
1030 |
|
486a87f1e 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 bpf, net: Rework ... |
1036 1037 1038 1039 |
preempt_disable(); __net_gen_cookie(&init_net); preempt_enable(); |
486a87f1e netns: fix double... |
1040 |
|
4420bf21f net: Rename net_s... |
1041 |
down_write(&pernet_ops_rwsem); |
038e7332b userns: make each... |
1042 |
if (setup_net(&init_net, &init_user_ns)) |
ca0f31125 netns: simplify n... |
1043 |
panic("Could not setup the initial network namespace"); |
5f256becd [NET]: Basic netw... |
1044 |
|
f8c46cb39 netns: do not cal... |
1045 |
init_net_initialized = true; |
4420bf21f net: Rename net_s... |
1046 |
up_write(&pernet_ops_rwsem); |
5f256becd [NET]: Basic netw... |
1047 |
|
0eb987c87 net/net_namespace... |
1048 1049 |
if (register_pernet_subsys(&net_ns_ops)) panic("Could not register network namespace subsystems"); |
98f842e67 proc: Usable inod... |
1050 |
|
165b91172 net: call newid/g... |
1051 1052 |
rtnl_register(PF_UNSPEC, RTM_NEWNSID, rtnl_net_newid, NULL, RTNL_FLAG_DOIT_UNLOCKED); |
a143c40c3 netns: allow to d... |
1053 |
rtnl_register(PF_UNSPEC, RTM_GETNSID, rtnl_net_getid, rtnl_net_dumpid, |
165b91172 net: call newid/g... |
1054 |
RTNL_FLAG_DOIT_UNLOCKED); |
0c7aecd4b netns: add rtnl c... |
1055 |
|
5f256becd [NET]: Basic netw... |
1056 1057 1058 1059 |
return 0; } pure_initcall(net_ns_init); |
ed160e839 [NET]: Cleanup pe... |
1060 |
#ifdef CONFIG_NET_NS |
f875bae06 net: Automaticall... |
1061 1062 |
static int __register_pernet_operations(struct list_head *list, struct pernet_operations *ops) |
5f256becd [NET]: Basic netw... |
1063 |
{ |
72ad937ab net: Add support ... |
1064 |
struct net *net; |
5f256becd [NET]: Basic netw... |
1065 |
int error; |
72ad937ab net: Add support ... |
1066 |
LIST_HEAD(net_exit_list); |
5f256becd [NET]: Basic netw... |
1067 |
|
5f256becd [NET]: Basic netw... |
1068 |
list_add_tail(&ops->list, list); |
f875bae06 net: Automaticall... |
1069 |
if (ops->init || (ops->id && ops->size)) { |
f0b07bb15 net: Introduce ne... |
1070 1071 1072 |
/* We held write locked pernet_ops_rwsem, and parallel * setup_net() and cleanup_net() are not possible. */ |
1dba323b3 [NETNS]: Make the... |
1073 |
for_each_net(net) { |
f875bae06 net: Automaticall... |
1074 |
error = ops_init(ops, net); |
5f256becd [NET]: Basic netw... |
1075 1076 |
if (error) goto out_undo; |
72ad937ab net: Add support ... |
1077 |
list_add_tail(&net->exit_list, &net_exit_list); |
5f256becd [NET]: Basic netw... |
1078 1079 |
} } |
1dba323b3 [NETNS]: Make the... |
1080 |
return 0; |
5f256becd [NET]: Basic netw... |
1081 1082 1083 1084 |
out_undo: /* If I have an error cleanup all namespaces I initialized */ list_del(&ops->list); |
d7d99872c netns: add pre_ex... |
1085 1086 |
ops_pre_exit_list(ops, &net_exit_list); synchronize_rcu(); |
72ad937ab net: Add support ... |
1087 1088 |
ops_exit_list(ops, &net_exit_list); ops_free_list(ops, &net_exit_list); |
1dba323b3 [NETNS]: Make the... |
1089 |
return error; |
5f256becd [NET]: Basic netw... |
1090 |
} |
f875bae06 net: Automaticall... |
1091 |
static void __unregister_pernet_operations(struct pernet_operations *ops) |
5f256becd [NET]: Basic netw... |
1092 1093 |
{ struct net *net; |
72ad937ab net: Add support ... |
1094 |
LIST_HEAD(net_exit_list); |
5f256becd [NET]: Basic netw... |
1095 1096 |
list_del(&ops->list); |
f0b07bb15 net: Introduce ne... |
1097 |
/* See comment in __register_pernet_operations() */ |
72ad937ab net: Add support ... |
1098 1099 |
for_each_net(net) list_add_tail(&net->exit_list, &net_exit_list); |
d7d99872c netns: add pre_ex... |
1100 1101 |
ops_pre_exit_list(ops, &net_exit_list); synchronize_rcu(); |
72ad937ab net: Add support ... |
1102 1103 |
ops_exit_list(ops, &net_exit_list); ops_free_list(ops, &net_exit_list); |
5f256becd [NET]: Basic netw... |
1104 |
} |
ed160e839 [NET]: Cleanup pe... |
1105 |
#else |
f875bae06 net: Automaticall... |
1106 1107 |
static int __register_pernet_operations(struct list_head *list, struct pernet_operations *ops) |
ed160e839 [NET]: Cleanup pe... |
1108 |
{ |
f8c46cb39 netns: do not cal... |
1109 1110 1111 1112 |
if (!init_net_initialized) { list_add_tail(&ops->list, list); return 0; } |
b922934d0 netns: do not lea... |
1113 |
return ops_init(ops, &init_net); |
ed160e839 [NET]: Cleanup pe... |
1114 |
} |
f875bae06 net: Automaticall... |
1115 |
static void __unregister_pernet_operations(struct pernet_operations *ops) |
ed160e839 [NET]: Cleanup pe... |
1116 |
{ |
f8c46cb39 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 netns: add pre_ex... |
1122 1123 |
ops_pre_exit_list(ops, &net_exit_list); synchronize_rcu(); |
f8c46cb39 netns: do not cal... |
1124 1125 1126 |
ops_exit_list(ops, &net_exit_list); ops_free_list(ops, &net_exit_list); } |
ed160e839 [NET]: Cleanup pe... |
1127 |
} |
f875bae06 net: Automaticall... |
1128 1129 |
#endif /* CONFIG_NET_NS */ |
ed160e839 [NET]: Cleanup pe... |
1130 |
|
c93cf61fd [NETNS]: The net-... |
1131 |
static DEFINE_IDA(net_generic_ids); |
f875bae06 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 Convert net_names... |
1138 1139 1140 |
error = ida_alloc_min(&net_generic_ids, MIN_PERNET_OPS_ID, GFP_KERNEL); if (error < 0) |
f875bae06 net: Automaticall... |
1141 |
return error; |
6e77cc471 Convert net_names... |
1142 |
*ops->id = error; |
6af2d5fff netns: fix net_ge... |
1143 |
max_gen_ptrs = max(max_gen_ptrs, *ops->id + 1); |
f875bae06 net: Automaticall... |
1144 1145 |
} error = __register_pernet_operations(list, ops); |
3a765edad netns: Add an exp... |
1146 1147 1148 |
if (error) { rcu_barrier(); if (ops->id) |
6e77cc471 Convert net_names... |
1149 |
ida_free(&net_generic_ids, *ops->id); |
3a765edad netns: Add an exp... |
1150 |
} |
f875bae06 net: Automaticall... |
1151 1152 1153 1154 1155 1156 |
return error; } static void unregister_pernet_operations(struct pernet_operations *ops) { |
f875bae06 net: Automaticall... |
1157 |
__unregister_pernet_operations(ops); |
3a765edad netns: Add an exp... |
1158 |
rcu_barrier(); |
f875bae06 net: Automaticall... |
1159 |
if (ops->id) |
6e77cc471 Convert net_names... |
1160 |
ida_free(&net_generic_ids, *ops->id); |
f875bae06 net: Automaticall... |
1161 |
} |
5f256becd [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 net: Rename net_s... |
1184 |
down_write(&pernet_ops_rwsem); |
5f256becd [NET]: Basic netw... |
1185 |
error = register_pernet_operations(first_device, ops); |
4420bf21f net: Rename net_s... |
1186 |
up_write(&pernet_ops_rwsem); |
5f256becd [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 typo fixes in net... |
1196 |
* used when network namespaces are created or destroyed. In |
5f256becd [NET]: Basic netw... |
1197 1198 1199 |
* addition run the exit method for all existing network * namespaces. */ |
b3c981d2b netns: rename unr... |
1200 |
void unregister_pernet_subsys(struct pernet_operations *ops) |
5f256becd [NET]: Basic netw... |
1201 |
{ |
4420bf21f net: Rename net_s... |
1202 |
down_write(&pernet_ops_rwsem); |
b3c981d2b netns: rename unr... |
1203 |
unregister_pernet_operations(ops); |
4420bf21f net: Rename net_s... |
1204 |
up_write(&pernet_ops_rwsem); |
5f256becd [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 net: Rename net_s... |
1230 |
down_write(&pernet_ops_rwsem); |
5f256becd [NET]: Basic netw... |
1231 1232 1233 |
error = register_pernet_operations(&pernet_list, ops); if (!error && (first_device == &pernet_list)) first_device = &ops->list; |
4420bf21f net: Rename net_s... |
1234 |
up_write(&pernet_ops_rwsem); |
5f256becd [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 typo fixes in net... |
1244 |
* used when network namespaces are created or destroyed. In |
5f256becd [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 net: Rename net_s... |
1250 |
down_write(&pernet_ops_rwsem); |
5f256becd [NET]: Basic netw... |
1251 1252 1253 |
if (&ops->list == first_device) first_device = first_device->next; unregister_pernet_operations(ops); |
4420bf21f net: Rename net_s... |
1254 |
up_write(&pernet_ops_rwsem); |
5f256becd [NET]: Basic netw... |
1255 1256 |
} EXPORT_SYMBOL_GPL(unregister_pernet_device); |
13b6f5762 ns proc: Add supp... |
1257 1258 |
#ifdef CONFIG_NET_NS |
64964528b make proc_ns_oper... |
1259 |
static struct ns_common *netns_get(struct task_struct *task) |
13b6f5762 ns proc: Add supp... |
1260 |
{ |
f06305294 net: Allow settin... |
1261 1262 |
struct net *net = NULL; struct nsproxy *nsproxy; |
728dba3a3 namespaces: Use t... |
1263 1264 |
task_lock(task); nsproxy = task->nsproxy; |
f06305294 net: Allow settin... |
1265 1266 |
if (nsproxy) net = get_net(nsproxy->net_ns); |
728dba3a3 namespaces: Use t... |
1267 |
task_unlock(task); |
f06305294 net: Allow settin... |
1268 |
|
ff24870f4 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 ns proc: Add supp... |
1275 |
} |
64964528b make proc_ns_oper... |
1276 |
static void netns_put(struct ns_common *ns) |
13b6f5762 ns proc: Add supp... |
1277 |
{ |
ff24870f4 netns: switch ->g... |
1278 |
put_net(to_net_ns(ns)); |
13b6f5762 ns proc: Add supp... |
1279 |
} |
f2a8d52e0 nsproxy: add stru... |
1280 |
static int netns_install(struct nsset *nsset, struct ns_common *ns) |
13b6f5762 ns proc: Add supp... |
1281 |
{ |
f2a8d52e0 nsproxy: add stru... |
1282 |
struct nsproxy *nsproxy = nsset->nsproxy; |
ff24870f4 netns: switch ->g... |
1283 |
struct net *net = to_net_ns(ns); |
142e1d1d5 userns: Allow unp... |
1284 |
|
5e4a08476 userns: Require C... |
1285 |
if (!ns_capable(net->user_ns, CAP_SYS_ADMIN) || |
f2a8d52e0 nsproxy: add stru... |
1286 |
!ns_capable(nsset->cred->user_ns, CAP_SYS_ADMIN)) |
142e1d1d5 userns: Allow unp... |
1287 |
return -EPERM; |
13b6f5762 ns proc: Add supp... |
1288 |
put_net(nsproxy->net_ns); |
142e1d1d5 userns: Allow unp... |
1289 |
nsproxy->net_ns = get_net(net); |
13b6f5762 ns proc: Add supp... |
1290 1291 |
return 0; } |
bcac25a58 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 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 kernel: add a hel... |
1302 |
.owner = netns_owner, |
13b6f5762 ns proc: Add supp... |
1303 1304 |
}; #endif |