18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 58c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 68c2ecf20Sopenharmony_ci#include <linux/cache.h> 78c2ecf20Sopenharmony_ci#include <linux/slab.h> 88c2ecf20Sopenharmony_ci#include <linux/list.h> 98c2ecf20Sopenharmony_ci#include <linux/delay.h> 108c2ecf20Sopenharmony_ci#include <linux/sched.h> 118c2ecf20Sopenharmony_ci#include <linux/idr.h> 128c2ecf20Sopenharmony_ci#include <linux/rculist.h> 138c2ecf20Sopenharmony_ci#include <linux/nsproxy.h> 148c2ecf20Sopenharmony_ci#include <linux/fs.h> 158c2ecf20Sopenharmony_ci#include <linux/proc_ns.h> 168c2ecf20Sopenharmony_ci#include <linux/file.h> 178c2ecf20Sopenharmony_ci#include <linux/export.h> 188c2ecf20Sopenharmony_ci#include <linux/user_namespace.h> 198c2ecf20Sopenharmony_ci#include <linux/net_namespace.h> 208c2ecf20Sopenharmony_ci#include <linux/sched/task.h> 218c2ecf20Sopenharmony_ci#include <linux/uidgid.h> 228c2ecf20Sopenharmony_ci#include <linux/cookie.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <net/sock.h> 258c2ecf20Sopenharmony_ci#include <net/netlink.h> 268c2ecf20Sopenharmony_ci#include <net/net_namespace.h> 278c2ecf20Sopenharmony_ci#include <net/netns/generic.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* 308c2ecf20Sopenharmony_ci * Our network namespace constructor/destructor lists 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic LIST_HEAD(pernet_list); 348c2ecf20Sopenharmony_cistatic struct list_head *first_device = &pernet_list; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ciLIST_HEAD(net_namespace_list); 378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(net_namespace_list); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* Protects net_namespace_list. Nests iside rtnl_lock() */ 408c2ecf20Sopenharmony_ciDECLARE_RWSEM(net_rwsem); 418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(net_rwsem); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#ifdef CONFIG_KEYS 448c2ecf20Sopenharmony_cistatic struct key_tag init_net_key_domain = { .usage = REFCOUNT_INIT(1) }; 458c2ecf20Sopenharmony_ci#endif 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistruct net init_net = { 488c2ecf20Sopenharmony_ci .count = REFCOUNT_INIT(1), 498c2ecf20Sopenharmony_ci .dev_base_head = LIST_HEAD_INIT(init_net.dev_base_head), 508c2ecf20Sopenharmony_ci#ifdef CONFIG_KEYS 518c2ecf20Sopenharmony_ci .key_domain = &init_net_key_domain, 528c2ecf20Sopenharmony_ci#endif 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ciEXPORT_SYMBOL(init_net); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic bool init_net_initialized; 578c2ecf20Sopenharmony_ci/* 588c2ecf20Sopenharmony_ci * pernet_ops_rwsem: protects: pernet_list, net_generic_ids, 598c2ecf20Sopenharmony_ci * init_net_initialized and first_device pointer. 608c2ecf20Sopenharmony_ci * This is internal net namespace object. Please, don't use it 618c2ecf20Sopenharmony_ci * outside. 628c2ecf20Sopenharmony_ci */ 638c2ecf20Sopenharmony_ciDECLARE_RWSEM(pernet_ops_rwsem); 648c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pernet_ops_rwsem); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#define MIN_PERNET_OPS_ID \ 678c2ecf20Sopenharmony_ci ((sizeof(struct net_generic) + sizeof(void *) - 1) / sizeof(void *)) 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#define INITIAL_NET_GEN_PTRS 13 /* +1 for len +2 for rcu_head */ 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic unsigned int max_gen_ptrs = INITIAL_NET_GEN_PTRS; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ciDEFINE_COOKIE(net_cookie); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ciu64 __net_gen_cookie(struct net *net) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci while (1) { 788c2ecf20Sopenharmony_ci u64 res = atomic64_read(&net->net_cookie); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (res) 818c2ecf20Sopenharmony_ci return res; 828c2ecf20Sopenharmony_ci res = gen_cookie_next(&net_cookie); 838c2ecf20Sopenharmony_ci atomic64_cmpxchg(&net->net_cookie, 0, res); 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic struct net_generic *net_alloc_generic(void) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci unsigned int gen_ptrs = READ_ONCE(max_gen_ptrs); 908c2ecf20Sopenharmony_ci unsigned int generic_size; 918c2ecf20Sopenharmony_ci struct net_generic *ng; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci generic_size = offsetof(struct net_generic, ptr[gen_ptrs]); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci ng = kzalloc(generic_size, GFP_KERNEL); 968c2ecf20Sopenharmony_ci if (ng) 978c2ecf20Sopenharmony_ci ng->s.len = gen_ptrs; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci return ng; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic int net_assign_generic(struct net *net, unsigned int id, void *data) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci struct net_generic *ng, *old_ng; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci BUG_ON(id < MIN_PERNET_OPS_ID); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci old_ng = rcu_dereference_protected(net->gen, 1098c2ecf20Sopenharmony_ci lockdep_is_held(&pernet_ops_rwsem)); 1108c2ecf20Sopenharmony_ci if (old_ng->s.len > id) { 1118c2ecf20Sopenharmony_ci old_ng->ptr[id] = data; 1128c2ecf20Sopenharmony_ci return 0; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci ng = net_alloc_generic(); 1168c2ecf20Sopenharmony_ci if (ng == NULL) 1178c2ecf20Sopenharmony_ci return -ENOMEM; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci /* 1208c2ecf20Sopenharmony_ci * Some synchronisation notes: 1218c2ecf20Sopenharmony_ci * 1228c2ecf20Sopenharmony_ci * The net_generic explores the net->gen array inside rcu 1238c2ecf20Sopenharmony_ci * read section. Besides once set the net->gen->ptr[x] 1248c2ecf20Sopenharmony_ci * pointer never changes (see rules in netns/generic.h). 1258c2ecf20Sopenharmony_ci * 1268c2ecf20Sopenharmony_ci * That said, we simply duplicate this array and schedule 1278c2ecf20Sopenharmony_ci * the old copy for kfree after a grace period. 1288c2ecf20Sopenharmony_ci */ 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci memcpy(&ng->ptr[MIN_PERNET_OPS_ID], &old_ng->ptr[MIN_PERNET_OPS_ID], 1318c2ecf20Sopenharmony_ci (old_ng->s.len - MIN_PERNET_OPS_ID) * sizeof(void *)); 1328c2ecf20Sopenharmony_ci ng->ptr[id] = data; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci rcu_assign_pointer(net->gen, ng); 1358c2ecf20Sopenharmony_ci kfree_rcu(old_ng, s.rcu); 1368c2ecf20Sopenharmony_ci return 0; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic int ops_init(const struct pernet_operations *ops, struct net *net) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci struct net_generic *ng; 1428c2ecf20Sopenharmony_ci int err = -ENOMEM; 1438c2ecf20Sopenharmony_ci void *data = NULL; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (ops->id && ops->size) { 1468c2ecf20Sopenharmony_ci data = kzalloc(ops->size, GFP_KERNEL); 1478c2ecf20Sopenharmony_ci if (!data) 1488c2ecf20Sopenharmony_ci goto out; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci err = net_assign_generic(net, *ops->id, data); 1518c2ecf20Sopenharmony_ci if (err) 1528c2ecf20Sopenharmony_ci goto cleanup; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci err = 0; 1558c2ecf20Sopenharmony_ci if (ops->init) 1568c2ecf20Sopenharmony_ci err = ops->init(net); 1578c2ecf20Sopenharmony_ci if (!err) 1588c2ecf20Sopenharmony_ci return 0; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (ops->id && ops->size) { 1618c2ecf20Sopenharmony_ci ng = rcu_dereference_protected(net->gen, 1628c2ecf20Sopenharmony_ci lockdep_is_held(&pernet_ops_rwsem)); 1638c2ecf20Sopenharmony_ci ng->ptr[*ops->id] = NULL; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cicleanup: 1678c2ecf20Sopenharmony_ci kfree(data); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ciout: 1708c2ecf20Sopenharmony_ci return err; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic void ops_free(const struct pernet_operations *ops, struct net *net) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci if (ops->id && ops->size) { 1768c2ecf20Sopenharmony_ci kfree(net_generic(net, *ops->id)); 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic void ops_pre_exit_list(const struct pernet_operations *ops, 1818c2ecf20Sopenharmony_ci struct list_head *net_exit_list) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct net *net; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (ops->pre_exit) { 1868c2ecf20Sopenharmony_ci list_for_each_entry(net, net_exit_list, exit_list) 1878c2ecf20Sopenharmony_ci ops->pre_exit(net); 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic void ops_exit_list(const struct pernet_operations *ops, 1928c2ecf20Sopenharmony_ci struct list_head *net_exit_list) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci struct net *net; 1958c2ecf20Sopenharmony_ci if (ops->exit) { 1968c2ecf20Sopenharmony_ci list_for_each_entry(net, net_exit_list, exit_list) { 1978c2ecf20Sopenharmony_ci ops->exit(net); 1988c2ecf20Sopenharmony_ci cond_resched(); 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci if (ops->exit_batch) 2028c2ecf20Sopenharmony_ci ops->exit_batch(net_exit_list); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic void ops_free_list(const struct pernet_operations *ops, 2068c2ecf20Sopenharmony_ci struct list_head *net_exit_list) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct net *net; 2098c2ecf20Sopenharmony_ci if (ops->size && ops->id) { 2108c2ecf20Sopenharmony_ci list_for_each_entry(net, net_exit_list, exit_list) 2118c2ecf20Sopenharmony_ci ops_free(ops, net); 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci/* should be called with nsid_lock held */ 2168c2ecf20Sopenharmony_cistatic int alloc_netid(struct net *net, struct net *peer, int reqid) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci int min = 0, max = 0; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (reqid >= 0) { 2218c2ecf20Sopenharmony_ci min = reqid; 2228c2ecf20Sopenharmony_ci max = reqid + 1; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci return idr_alloc(&net->netns_ids, peer, min, max, GFP_ATOMIC); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci/* This function is used by idr_for_each(). If net is equal to peer, the 2298c2ecf20Sopenharmony_ci * function returns the id so that idr_for_each() stops. Because we cannot 2308c2ecf20Sopenharmony_ci * returns the id 0 (idr_for_each() will not stop), we return the magic value 2318c2ecf20Sopenharmony_ci * NET_ID_ZERO (-1) for it. 2328c2ecf20Sopenharmony_ci */ 2338c2ecf20Sopenharmony_ci#define NET_ID_ZERO -1 2348c2ecf20Sopenharmony_cistatic int net_eq_idr(int id, void *net, void *peer) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci if (net_eq(net, peer)) 2378c2ecf20Sopenharmony_ci return id ? : NET_ID_ZERO; 2388c2ecf20Sopenharmony_ci return 0; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci/* Must be called from RCU-critical section or with nsid_lock held */ 2428c2ecf20Sopenharmony_cistatic int __peernet2id(const struct net *net, struct net *peer) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci int id = idr_for_each(&net->netns_ids, net_eq_idr, peer); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* Magic value for id 0. */ 2478c2ecf20Sopenharmony_ci if (id == NET_ID_ZERO) 2488c2ecf20Sopenharmony_ci return 0; 2498c2ecf20Sopenharmony_ci if (id > 0) 2508c2ecf20Sopenharmony_ci return id; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci return NETNSA_NSID_NOT_ASSIGNED; 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic void rtnl_net_notifyid(struct net *net, int cmd, int id, u32 portid, 2568c2ecf20Sopenharmony_ci struct nlmsghdr *nlh, gfp_t gfp); 2578c2ecf20Sopenharmony_ci/* This function returns the id of a peer netns. If no id is assigned, one will 2588c2ecf20Sopenharmony_ci * be allocated and returned. 2598c2ecf20Sopenharmony_ci */ 2608c2ecf20Sopenharmony_ciint peernet2id_alloc(struct net *net, struct net *peer, gfp_t gfp) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci int id; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (refcount_read(&net->count) == 0) 2658c2ecf20Sopenharmony_ci return NETNSA_NSID_NOT_ASSIGNED; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci spin_lock_bh(&net->nsid_lock); 2688c2ecf20Sopenharmony_ci id = __peernet2id(net, peer); 2698c2ecf20Sopenharmony_ci if (id >= 0) { 2708c2ecf20Sopenharmony_ci spin_unlock_bh(&net->nsid_lock); 2718c2ecf20Sopenharmony_ci return id; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* When peer is obtained from RCU lists, we may race with 2758c2ecf20Sopenharmony_ci * its cleanup. Check whether it's alive, and this guarantees 2768c2ecf20Sopenharmony_ci * we never hash a peer back to net->netns_ids, after it has 2778c2ecf20Sopenharmony_ci * just been idr_remove()'d from there in cleanup_net(). 2788c2ecf20Sopenharmony_ci */ 2798c2ecf20Sopenharmony_ci if (!maybe_get_net(peer)) { 2808c2ecf20Sopenharmony_ci spin_unlock_bh(&net->nsid_lock); 2818c2ecf20Sopenharmony_ci return NETNSA_NSID_NOT_ASSIGNED; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci id = alloc_netid(net, peer, -1); 2858c2ecf20Sopenharmony_ci spin_unlock_bh(&net->nsid_lock); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci put_net(peer); 2888c2ecf20Sopenharmony_ci if (id < 0) 2898c2ecf20Sopenharmony_ci return NETNSA_NSID_NOT_ASSIGNED; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci rtnl_net_notifyid(net, RTM_NEWNSID, id, 0, NULL, gfp); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci return id; 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(peernet2id_alloc); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci/* This function returns, if assigned, the id of a peer netns. */ 2988c2ecf20Sopenharmony_ciint peernet2id(const struct net *net, struct net *peer) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci int id; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci rcu_read_lock(); 3038c2ecf20Sopenharmony_ci id = __peernet2id(net, peer); 3048c2ecf20Sopenharmony_ci rcu_read_unlock(); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci return id; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ciEXPORT_SYMBOL(peernet2id); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci/* This function returns true is the peer netns has an id assigned into the 3118c2ecf20Sopenharmony_ci * current netns. 3128c2ecf20Sopenharmony_ci */ 3138c2ecf20Sopenharmony_cibool peernet_has_id(const struct net *net, struct net *peer) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci return peernet2id(net, peer) >= 0; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistruct net *get_net_ns_by_id(const struct net *net, int id) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct net *peer; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (id < 0) 3238c2ecf20Sopenharmony_ci return NULL; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci rcu_read_lock(); 3268c2ecf20Sopenharmony_ci peer = idr_find(&net->netns_ids, id); 3278c2ecf20Sopenharmony_ci if (peer) 3288c2ecf20Sopenharmony_ci peer = maybe_get_net(peer); 3298c2ecf20Sopenharmony_ci rcu_read_unlock(); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci return peer; 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci/* 3358c2ecf20Sopenharmony_ci * setup_net runs the initializers for the network namespace object. 3368c2ecf20Sopenharmony_ci */ 3378c2ecf20Sopenharmony_cistatic __net_init int setup_net(struct net *net, struct user_namespace *user_ns) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci /* Must be called with pernet_ops_rwsem held */ 3408c2ecf20Sopenharmony_ci const struct pernet_operations *ops, *saved_ops; 3418c2ecf20Sopenharmony_ci int error = 0; 3428c2ecf20Sopenharmony_ci LIST_HEAD(net_exit_list); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci refcount_set(&net->count, 1); 3458c2ecf20Sopenharmony_ci refcount_set(&net->passive, 1); 3468c2ecf20Sopenharmony_ci get_random_bytes(&net->hash_mix, sizeof(u32)); 3478c2ecf20Sopenharmony_ci net->dev_base_seq = 1; 3488c2ecf20Sopenharmony_ci net->user_ns = user_ns; 3498c2ecf20Sopenharmony_ci idr_init(&net->netns_ids); 3508c2ecf20Sopenharmony_ci spin_lock_init(&net->nsid_lock); 3518c2ecf20Sopenharmony_ci mutex_init(&net->ipv4.ra_mutex); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci list_for_each_entry(ops, &pernet_list, list) { 3548c2ecf20Sopenharmony_ci error = ops_init(ops, net); 3558c2ecf20Sopenharmony_ci if (error < 0) 3568c2ecf20Sopenharmony_ci goto out_undo; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci down_write(&net_rwsem); 3598c2ecf20Sopenharmony_ci list_add_tail_rcu(&net->list, &net_namespace_list); 3608c2ecf20Sopenharmony_ci up_write(&net_rwsem); 3618c2ecf20Sopenharmony_ciout: 3628c2ecf20Sopenharmony_ci return error; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ciout_undo: 3658c2ecf20Sopenharmony_ci /* Walk through the list backwards calling the exit functions 3668c2ecf20Sopenharmony_ci * for the pernet modules whose init functions did not fail. 3678c2ecf20Sopenharmony_ci */ 3688c2ecf20Sopenharmony_ci list_add(&net->exit_list, &net_exit_list); 3698c2ecf20Sopenharmony_ci saved_ops = ops; 3708c2ecf20Sopenharmony_ci list_for_each_entry_continue_reverse(ops, &pernet_list, list) 3718c2ecf20Sopenharmony_ci ops_pre_exit_list(ops, &net_exit_list); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci synchronize_rcu(); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci ops = saved_ops; 3768c2ecf20Sopenharmony_ci list_for_each_entry_continue_reverse(ops, &pernet_list, list) 3778c2ecf20Sopenharmony_ci ops_exit_list(ops, &net_exit_list); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci ops = saved_ops; 3808c2ecf20Sopenharmony_ci list_for_each_entry_continue_reverse(ops, &pernet_list, list) 3818c2ecf20Sopenharmony_ci ops_free_list(ops, &net_exit_list); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci rcu_barrier(); 3848c2ecf20Sopenharmony_ci goto out; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic int __net_init net_defaults_init_net(struct net *net) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci net->core.sysctl_somaxconn = SOMAXCONN; 3908c2ecf20Sopenharmony_ci return 0; 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cistatic struct pernet_operations net_defaults_ops = { 3948c2ecf20Sopenharmony_ci .init = net_defaults_init_net, 3958c2ecf20Sopenharmony_ci}; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic __init int net_defaults_init(void) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci if (register_pernet_subsys(&net_defaults_ops)) 4008c2ecf20Sopenharmony_ci panic("Cannot initialize net default settings"); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci return 0; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cicore_initcall(net_defaults_init); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_NS 4088c2ecf20Sopenharmony_cistatic struct ucounts *inc_net_namespaces(struct user_namespace *ns) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci return inc_ucount(ns, current_euid(), UCOUNT_NET_NAMESPACES); 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic void dec_net_namespaces(struct ucounts *ucounts) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci dec_ucount(ucounts, UCOUNT_NET_NAMESPACES); 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic struct kmem_cache *net_cachep __ro_after_init; 4198c2ecf20Sopenharmony_cistatic struct workqueue_struct *netns_wq; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic struct net *net_alloc(void) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci struct net *net = NULL; 4248c2ecf20Sopenharmony_ci struct net_generic *ng; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci ng = net_alloc_generic(); 4278c2ecf20Sopenharmony_ci if (!ng) 4288c2ecf20Sopenharmony_ci goto out; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci net = kmem_cache_zalloc(net_cachep, GFP_KERNEL); 4318c2ecf20Sopenharmony_ci if (!net) 4328c2ecf20Sopenharmony_ci goto out_free; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci#ifdef CONFIG_KEYS 4358c2ecf20Sopenharmony_ci net->key_domain = kzalloc(sizeof(struct key_tag), GFP_KERNEL); 4368c2ecf20Sopenharmony_ci if (!net->key_domain) 4378c2ecf20Sopenharmony_ci goto out_free_2; 4388c2ecf20Sopenharmony_ci refcount_set(&net->key_domain->usage, 1); 4398c2ecf20Sopenharmony_ci#endif 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci rcu_assign_pointer(net->gen, ng); 4428c2ecf20Sopenharmony_ciout: 4438c2ecf20Sopenharmony_ci return net; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci#ifdef CONFIG_KEYS 4468c2ecf20Sopenharmony_ciout_free_2: 4478c2ecf20Sopenharmony_ci kmem_cache_free(net_cachep, net); 4488c2ecf20Sopenharmony_ci net = NULL; 4498c2ecf20Sopenharmony_ci#endif 4508c2ecf20Sopenharmony_ciout_free: 4518c2ecf20Sopenharmony_ci kfree(ng); 4528c2ecf20Sopenharmony_ci goto out; 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_cistatic void net_free(struct net *net) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci kfree(rcu_access_pointer(net->gen)); 4588c2ecf20Sopenharmony_ci kmem_cache_free(net_cachep, net); 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_civoid net_drop_ns(void *p) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci struct net *ns = p; 4648c2ecf20Sopenharmony_ci if (ns && refcount_dec_and_test(&ns->passive)) 4658c2ecf20Sopenharmony_ci net_free(ns); 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistruct net *copy_net_ns(unsigned long flags, 4698c2ecf20Sopenharmony_ci struct user_namespace *user_ns, struct net *old_net) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci struct ucounts *ucounts; 4728c2ecf20Sopenharmony_ci struct net *net; 4738c2ecf20Sopenharmony_ci int rv; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci if (!(flags & CLONE_NEWNET)) 4768c2ecf20Sopenharmony_ci return get_net(old_net); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci ucounts = inc_net_namespaces(user_ns); 4798c2ecf20Sopenharmony_ci if (!ucounts) 4808c2ecf20Sopenharmony_ci return ERR_PTR(-ENOSPC); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci net = net_alloc(); 4838c2ecf20Sopenharmony_ci if (!net) { 4848c2ecf20Sopenharmony_ci rv = -ENOMEM; 4858c2ecf20Sopenharmony_ci goto dec_ucounts; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci refcount_set(&net->passive, 1); 4888c2ecf20Sopenharmony_ci net->ucounts = ucounts; 4898c2ecf20Sopenharmony_ci get_user_ns(user_ns); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci rv = down_read_killable(&pernet_ops_rwsem); 4928c2ecf20Sopenharmony_ci if (rv < 0) 4938c2ecf20Sopenharmony_ci goto put_userns; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci rv = setup_net(net, user_ns); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci up_read(&pernet_ops_rwsem); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (rv < 0) { 5008c2ecf20Sopenharmony_ciput_userns: 5018c2ecf20Sopenharmony_ci#ifdef CONFIG_KEYS 5028c2ecf20Sopenharmony_ci key_remove_domain(net->key_domain); 5038c2ecf20Sopenharmony_ci#endif 5048c2ecf20Sopenharmony_ci put_user_ns(user_ns); 5058c2ecf20Sopenharmony_ci net_drop_ns(net); 5068c2ecf20Sopenharmony_cidec_ucounts: 5078c2ecf20Sopenharmony_ci dec_net_namespaces(ucounts); 5088c2ecf20Sopenharmony_ci return ERR_PTR(rv); 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci return net; 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci/** 5148c2ecf20Sopenharmony_ci * net_ns_get_ownership - get sysfs ownership data for @net 5158c2ecf20Sopenharmony_ci * @net: network namespace in question (can be NULL) 5168c2ecf20Sopenharmony_ci * @uid: kernel user ID for sysfs objects 5178c2ecf20Sopenharmony_ci * @gid: kernel group ID for sysfs objects 5188c2ecf20Sopenharmony_ci * 5198c2ecf20Sopenharmony_ci * Returns the uid/gid pair of root in the user namespace associated with the 5208c2ecf20Sopenharmony_ci * given network namespace. 5218c2ecf20Sopenharmony_ci */ 5228c2ecf20Sopenharmony_civoid net_ns_get_ownership(const struct net *net, kuid_t *uid, kgid_t *gid) 5238c2ecf20Sopenharmony_ci{ 5248c2ecf20Sopenharmony_ci if (net) { 5258c2ecf20Sopenharmony_ci kuid_t ns_root_uid = make_kuid(net->user_ns, 0); 5268c2ecf20Sopenharmony_ci kgid_t ns_root_gid = make_kgid(net->user_ns, 0); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci if (uid_valid(ns_root_uid)) 5298c2ecf20Sopenharmony_ci *uid = ns_root_uid; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci if (gid_valid(ns_root_gid)) 5328c2ecf20Sopenharmony_ci *gid = ns_root_gid; 5338c2ecf20Sopenharmony_ci } else { 5348c2ecf20Sopenharmony_ci *uid = GLOBAL_ROOT_UID; 5358c2ecf20Sopenharmony_ci *gid = GLOBAL_ROOT_GID; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(net_ns_get_ownership); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic void unhash_nsid(struct net *net, struct net *last) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci struct net *tmp; 5438c2ecf20Sopenharmony_ci /* This function is only called from cleanup_net() work, 5448c2ecf20Sopenharmony_ci * and this work is the only process, that may delete 5458c2ecf20Sopenharmony_ci * a net from net_namespace_list. So, when the below 5468c2ecf20Sopenharmony_ci * is executing, the list may only grow. Thus, we do not 5478c2ecf20Sopenharmony_ci * use for_each_net_rcu() or net_rwsem. 5488c2ecf20Sopenharmony_ci */ 5498c2ecf20Sopenharmony_ci for_each_net(tmp) { 5508c2ecf20Sopenharmony_ci int id; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci spin_lock_bh(&tmp->nsid_lock); 5538c2ecf20Sopenharmony_ci id = __peernet2id(tmp, net); 5548c2ecf20Sopenharmony_ci if (id >= 0) 5558c2ecf20Sopenharmony_ci idr_remove(&tmp->netns_ids, id); 5568c2ecf20Sopenharmony_ci spin_unlock_bh(&tmp->nsid_lock); 5578c2ecf20Sopenharmony_ci if (id >= 0) 5588c2ecf20Sopenharmony_ci rtnl_net_notifyid(tmp, RTM_DELNSID, id, 0, NULL, 5598c2ecf20Sopenharmony_ci GFP_KERNEL); 5608c2ecf20Sopenharmony_ci if (tmp == last) 5618c2ecf20Sopenharmony_ci break; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci spin_lock_bh(&net->nsid_lock); 5648c2ecf20Sopenharmony_ci idr_destroy(&net->netns_ids); 5658c2ecf20Sopenharmony_ci spin_unlock_bh(&net->nsid_lock); 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_cistatic LLIST_HEAD(cleanup_list); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cistatic void cleanup_net(struct work_struct *work) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci const struct pernet_operations *ops; 5738c2ecf20Sopenharmony_ci struct net *net, *tmp, *last; 5748c2ecf20Sopenharmony_ci struct llist_node *net_kill_list; 5758c2ecf20Sopenharmony_ci LIST_HEAD(net_exit_list); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci /* Atomically snapshot the list of namespaces to cleanup */ 5788c2ecf20Sopenharmony_ci net_kill_list = llist_del_all(&cleanup_list); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci down_read(&pernet_ops_rwsem); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci /* Don't let anyone else find us. */ 5838c2ecf20Sopenharmony_ci down_write(&net_rwsem); 5848c2ecf20Sopenharmony_ci llist_for_each_entry(net, net_kill_list, cleanup_list) 5858c2ecf20Sopenharmony_ci list_del_rcu(&net->list); 5868c2ecf20Sopenharmony_ci /* Cache last net. After we unlock rtnl, no one new net 5878c2ecf20Sopenharmony_ci * added to net_namespace_list can assign nsid pointer 5888c2ecf20Sopenharmony_ci * to a net from net_kill_list (see peernet2id_alloc()). 5898c2ecf20Sopenharmony_ci * So, we skip them in unhash_nsid(). 5908c2ecf20Sopenharmony_ci * 5918c2ecf20Sopenharmony_ci * Note, that unhash_nsid() does not delete nsid links 5928c2ecf20Sopenharmony_ci * between net_kill_list's nets, as they've already 5938c2ecf20Sopenharmony_ci * deleted from net_namespace_list. But, this would be 5948c2ecf20Sopenharmony_ci * useless anyway, as netns_ids are destroyed there. 5958c2ecf20Sopenharmony_ci */ 5968c2ecf20Sopenharmony_ci last = list_last_entry(&net_namespace_list, struct net, list); 5978c2ecf20Sopenharmony_ci up_write(&net_rwsem); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci llist_for_each_entry(net, net_kill_list, cleanup_list) { 6008c2ecf20Sopenharmony_ci unhash_nsid(net, last); 6018c2ecf20Sopenharmony_ci list_add_tail(&net->exit_list, &net_exit_list); 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci /* Run all of the network namespace pre_exit methods */ 6058c2ecf20Sopenharmony_ci list_for_each_entry_reverse(ops, &pernet_list, list) 6068c2ecf20Sopenharmony_ci ops_pre_exit_list(ops, &net_exit_list); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci /* 6098c2ecf20Sopenharmony_ci * Another CPU might be rcu-iterating the list, wait for it. 6108c2ecf20Sopenharmony_ci * This needs to be before calling the exit() notifiers, so 6118c2ecf20Sopenharmony_ci * the rcu_barrier() below isn't sufficient alone. 6128c2ecf20Sopenharmony_ci * Also the pre_exit() and exit() methods need this barrier. 6138c2ecf20Sopenharmony_ci */ 6148c2ecf20Sopenharmony_ci synchronize_rcu(); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci /* Run all of the network namespace exit methods */ 6178c2ecf20Sopenharmony_ci list_for_each_entry_reverse(ops, &pernet_list, list) 6188c2ecf20Sopenharmony_ci ops_exit_list(ops, &net_exit_list); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci /* Free the net generic variables */ 6218c2ecf20Sopenharmony_ci list_for_each_entry_reverse(ops, &pernet_list, list) 6228c2ecf20Sopenharmony_ci ops_free_list(ops, &net_exit_list); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci up_read(&pernet_ops_rwsem); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* Ensure there are no outstanding rcu callbacks using this 6278c2ecf20Sopenharmony_ci * network namespace. 6288c2ecf20Sopenharmony_ci */ 6298c2ecf20Sopenharmony_ci rcu_barrier(); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci /* Finally it is safe to free my network namespace structure */ 6328c2ecf20Sopenharmony_ci list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) { 6338c2ecf20Sopenharmony_ci list_del_init(&net->exit_list); 6348c2ecf20Sopenharmony_ci dec_net_namespaces(net->ucounts); 6358c2ecf20Sopenharmony_ci#ifdef CONFIG_KEYS 6368c2ecf20Sopenharmony_ci key_remove_domain(net->key_domain); 6378c2ecf20Sopenharmony_ci#endif 6388c2ecf20Sopenharmony_ci put_user_ns(net->user_ns); 6398c2ecf20Sopenharmony_ci net_drop_ns(net); 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci/** 6448c2ecf20Sopenharmony_ci * net_ns_barrier - wait until concurrent net_cleanup_work is done 6458c2ecf20Sopenharmony_ci * 6468c2ecf20Sopenharmony_ci * cleanup_net runs from work queue and will first remove namespaces 6478c2ecf20Sopenharmony_ci * from the global list, then run net exit functions. 6488c2ecf20Sopenharmony_ci * 6498c2ecf20Sopenharmony_ci * Call this in module exit path to make sure that all netns 6508c2ecf20Sopenharmony_ci * ->exit ops have been invoked before the function is removed. 6518c2ecf20Sopenharmony_ci */ 6528c2ecf20Sopenharmony_civoid net_ns_barrier(void) 6538c2ecf20Sopenharmony_ci{ 6548c2ecf20Sopenharmony_ci down_write(&pernet_ops_rwsem); 6558c2ecf20Sopenharmony_ci up_write(&pernet_ops_rwsem); 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ciEXPORT_SYMBOL(net_ns_barrier); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_cistatic DECLARE_WORK(net_cleanup_work, cleanup_net); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_civoid __put_net(struct net *net) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci /* Cleanup the network namespace in process context */ 6648c2ecf20Sopenharmony_ci if (llist_add(&net->cleanup_list, &cleanup_list)) 6658c2ecf20Sopenharmony_ci queue_work(netns_wq, &net_cleanup_work); 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__put_net); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci/** 6708c2ecf20Sopenharmony_ci * get_net_ns - increment the refcount of the network namespace 6718c2ecf20Sopenharmony_ci * @ns: common namespace (net) 6728c2ecf20Sopenharmony_ci * 6738c2ecf20Sopenharmony_ci * Returns the net's common namespace. 6748c2ecf20Sopenharmony_ci */ 6758c2ecf20Sopenharmony_cistruct ns_common *get_net_ns(struct ns_common *ns) 6768c2ecf20Sopenharmony_ci{ 6778c2ecf20Sopenharmony_ci return &get_net(container_of(ns, struct net, ns))->ns; 6788c2ecf20Sopenharmony_ci} 6798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(get_net_ns); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_cistruct net *get_net_ns_by_fd(int fd) 6828c2ecf20Sopenharmony_ci{ 6838c2ecf20Sopenharmony_ci struct file *file; 6848c2ecf20Sopenharmony_ci struct ns_common *ns; 6858c2ecf20Sopenharmony_ci struct net *net; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci file = proc_ns_fget(fd); 6888c2ecf20Sopenharmony_ci if (IS_ERR(file)) 6898c2ecf20Sopenharmony_ci return ERR_CAST(file); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci ns = get_proc_ns(file_inode(file)); 6928c2ecf20Sopenharmony_ci if (ns->ops == &netns_operations) 6938c2ecf20Sopenharmony_ci net = get_net(container_of(ns, struct net, ns)); 6948c2ecf20Sopenharmony_ci else 6958c2ecf20Sopenharmony_ci net = ERR_PTR(-EINVAL); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci fput(file); 6988c2ecf20Sopenharmony_ci return net; 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci#else 7028c2ecf20Sopenharmony_cistruct net *get_net_ns_by_fd(int fd) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 7058c2ecf20Sopenharmony_ci} 7068c2ecf20Sopenharmony_ci#endif 7078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(get_net_ns_by_fd); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_cistruct net *get_net_ns_by_pid(pid_t pid) 7108c2ecf20Sopenharmony_ci{ 7118c2ecf20Sopenharmony_ci struct task_struct *tsk; 7128c2ecf20Sopenharmony_ci struct net *net; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci /* Lookup the network namespace */ 7158c2ecf20Sopenharmony_ci net = ERR_PTR(-ESRCH); 7168c2ecf20Sopenharmony_ci rcu_read_lock(); 7178c2ecf20Sopenharmony_ci tsk = find_task_by_vpid(pid); 7188c2ecf20Sopenharmony_ci if (tsk) { 7198c2ecf20Sopenharmony_ci struct nsproxy *nsproxy; 7208c2ecf20Sopenharmony_ci task_lock(tsk); 7218c2ecf20Sopenharmony_ci nsproxy = tsk->nsproxy; 7228c2ecf20Sopenharmony_ci if (nsproxy) 7238c2ecf20Sopenharmony_ci net = get_net(nsproxy->net_ns); 7248c2ecf20Sopenharmony_ci task_unlock(tsk); 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci rcu_read_unlock(); 7278c2ecf20Sopenharmony_ci return net; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(get_net_ns_by_pid); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_cistatic __net_init int net_ns_net_init(struct net *net) 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_NS 7348c2ecf20Sopenharmony_ci net->ns.ops = &netns_operations; 7358c2ecf20Sopenharmony_ci#endif 7368c2ecf20Sopenharmony_ci return ns_alloc_inum(&net->ns); 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_cistatic __net_exit void net_ns_net_exit(struct net *net) 7408c2ecf20Sopenharmony_ci{ 7418c2ecf20Sopenharmony_ci ns_free_inum(&net->ns); 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistatic struct pernet_operations __net_initdata net_ns_ops = { 7458c2ecf20Sopenharmony_ci .init = net_ns_net_init, 7468c2ecf20Sopenharmony_ci .exit = net_ns_net_exit, 7478c2ecf20Sopenharmony_ci}; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_cistatic const struct nla_policy rtnl_net_policy[NETNSA_MAX + 1] = { 7508c2ecf20Sopenharmony_ci [NETNSA_NONE] = { .type = NLA_UNSPEC }, 7518c2ecf20Sopenharmony_ci [NETNSA_NSID] = { .type = NLA_S32 }, 7528c2ecf20Sopenharmony_ci [NETNSA_PID] = { .type = NLA_U32 }, 7538c2ecf20Sopenharmony_ci [NETNSA_FD] = { .type = NLA_U32 }, 7548c2ecf20Sopenharmony_ci [NETNSA_TARGET_NSID] = { .type = NLA_S32 }, 7558c2ecf20Sopenharmony_ci}; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh, 7588c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 7598c2ecf20Sopenharmony_ci{ 7608c2ecf20Sopenharmony_ci struct net *net = sock_net(skb->sk); 7618c2ecf20Sopenharmony_ci struct nlattr *tb[NETNSA_MAX + 1]; 7628c2ecf20Sopenharmony_ci struct nlattr *nla; 7638c2ecf20Sopenharmony_ci struct net *peer; 7648c2ecf20Sopenharmony_ci int nsid, err; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci err = nlmsg_parse_deprecated(nlh, sizeof(struct rtgenmsg), tb, 7678c2ecf20Sopenharmony_ci NETNSA_MAX, rtnl_net_policy, extack); 7688c2ecf20Sopenharmony_ci if (err < 0) 7698c2ecf20Sopenharmony_ci return err; 7708c2ecf20Sopenharmony_ci if (!tb[NETNSA_NSID]) { 7718c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, "nsid is missing"); 7728c2ecf20Sopenharmony_ci return -EINVAL; 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci nsid = nla_get_s32(tb[NETNSA_NSID]); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci if (tb[NETNSA_PID]) { 7778c2ecf20Sopenharmony_ci peer = get_net_ns_by_pid(nla_get_u32(tb[NETNSA_PID])); 7788c2ecf20Sopenharmony_ci nla = tb[NETNSA_PID]; 7798c2ecf20Sopenharmony_ci } else if (tb[NETNSA_FD]) { 7808c2ecf20Sopenharmony_ci peer = get_net_ns_by_fd(nla_get_u32(tb[NETNSA_FD])); 7818c2ecf20Sopenharmony_ci nla = tb[NETNSA_FD]; 7828c2ecf20Sopenharmony_ci } else { 7838c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, "Peer netns reference is missing"); 7848c2ecf20Sopenharmony_ci return -EINVAL; 7858c2ecf20Sopenharmony_ci } 7868c2ecf20Sopenharmony_ci if (IS_ERR(peer)) { 7878c2ecf20Sopenharmony_ci NL_SET_BAD_ATTR(extack, nla); 7888c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, "Peer netns reference is invalid"); 7898c2ecf20Sopenharmony_ci return PTR_ERR(peer); 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci spin_lock_bh(&net->nsid_lock); 7938c2ecf20Sopenharmony_ci if (__peernet2id(net, peer) >= 0) { 7948c2ecf20Sopenharmony_ci spin_unlock_bh(&net->nsid_lock); 7958c2ecf20Sopenharmony_ci err = -EEXIST; 7968c2ecf20Sopenharmony_ci NL_SET_BAD_ATTR(extack, nla); 7978c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, 7988c2ecf20Sopenharmony_ci "Peer netns already has a nsid assigned"); 7998c2ecf20Sopenharmony_ci goto out; 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci err = alloc_netid(net, peer, nsid); 8038c2ecf20Sopenharmony_ci spin_unlock_bh(&net->nsid_lock); 8048c2ecf20Sopenharmony_ci if (err >= 0) { 8058c2ecf20Sopenharmony_ci rtnl_net_notifyid(net, RTM_NEWNSID, err, NETLINK_CB(skb).portid, 8068c2ecf20Sopenharmony_ci nlh, GFP_KERNEL); 8078c2ecf20Sopenharmony_ci err = 0; 8088c2ecf20Sopenharmony_ci } else if (err == -ENOSPC && nsid >= 0) { 8098c2ecf20Sopenharmony_ci err = -EEXIST; 8108c2ecf20Sopenharmony_ci NL_SET_BAD_ATTR(extack, tb[NETNSA_NSID]); 8118c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, "The specified nsid is already used"); 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ciout: 8148c2ecf20Sopenharmony_ci put_net(peer); 8158c2ecf20Sopenharmony_ci return err; 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_cistatic int rtnl_net_get_size(void) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci return NLMSG_ALIGN(sizeof(struct rtgenmsg)) 8218c2ecf20Sopenharmony_ci + nla_total_size(sizeof(s32)) /* NETNSA_NSID */ 8228c2ecf20Sopenharmony_ci + nla_total_size(sizeof(s32)) /* NETNSA_CURRENT_NSID */ 8238c2ecf20Sopenharmony_ci ; 8248c2ecf20Sopenharmony_ci} 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_cistruct net_fill_args { 8278c2ecf20Sopenharmony_ci u32 portid; 8288c2ecf20Sopenharmony_ci u32 seq; 8298c2ecf20Sopenharmony_ci int flags; 8308c2ecf20Sopenharmony_ci int cmd; 8318c2ecf20Sopenharmony_ci int nsid; 8328c2ecf20Sopenharmony_ci bool add_ref; 8338c2ecf20Sopenharmony_ci int ref_nsid; 8348c2ecf20Sopenharmony_ci}; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_cistatic int rtnl_net_fill(struct sk_buff *skb, struct net_fill_args *args) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci struct nlmsghdr *nlh; 8398c2ecf20Sopenharmony_ci struct rtgenmsg *rth; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci nlh = nlmsg_put(skb, args->portid, args->seq, args->cmd, sizeof(*rth), 8428c2ecf20Sopenharmony_ci args->flags); 8438c2ecf20Sopenharmony_ci if (!nlh) 8448c2ecf20Sopenharmony_ci return -EMSGSIZE; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci rth = nlmsg_data(nlh); 8478c2ecf20Sopenharmony_ci rth->rtgen_family = AF_UNSPEC; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci if (nla_put_s32(skb, NETNSA_NSID, args->nsid)) 8508c2ecf20Sopenharmony_ci goto nla_put_failure; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci if (args->add_ref && 8538c2ecf20Sopenharmony_ci nla_put_s32(skb, NETNSA_CURRENT_NSID, args->ref_nsid)) 8548c2ecf20Sopenharmony_ci goto nla_put_failure; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci nlmsg_end(skb, nlh); 8578c2ecf20Sopenharmony_ci return 0; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_cinla_put_failure: 8608c2ecf20Sopenharmony_ci nlmsg_cancel(skb, nlh); 8618c2ecf20Sopenharmony_ci return -EMSGSIZE; 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_cistatic int rtnl_net_valid_getid_req(struct sk_buff *skb, 8658c2ecf20Sopenharmony_ci const struct nlmsghdr *nlh, 8668c2ecf20Sopenharmony_ci struct nlattr **tb, 8678c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci int i, err; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci if (!netlink_strict_get_check(skb)) 8728c2ecf20Sopenharmony_ci return nlmsg_parse_deprecated(nlh, sizeof(struct rtgenmsg), 8738c2ecf20Sopenharmony_ci tb, NETNSA_MAX, rtnl_net_policy, 8748c2ecf20Sopenharmony_ci extack); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct rtgenmsg), tb, 8778c2ecf20Sopenharmony_ci NETNSA_MAX, rtnl_net_policy, 8788c2ecf20Sopenharmony_ci extack); 8798c2ecf20Sopenharmony_ci if (err) 8808c2ecf20Sopenharmony_ci return err; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci for (i = 0; i <= NETNSA_MAX; i++) { 8838c2ecf20Sopenharmony_ci if (!tb[i]) 8848c2ecf20Sopenharmony_ci continue; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci switch (i) { 8878c2ecf20Sopenharmony_ci case NETNSA_PID: 8888c2ecf20Sopenharmony_ci case NETNSA_FD: 8898c2ecf20Sopenharmony_ci case NETNSA_NSID: 8908c2ecf20Sopenharmony_ci case NETNSA_TARGET_NSID: 8918c2ecf20Sopenharmony_ci break; 8928c2ecf20Sopenharmony_ci default: 8938c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, "Unsupported attribute in peer netns getid request"); 8948c2ecf20Sopenharmony_ci return -EINVAL; 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci return 0; 8998c2ecf20Sopenharmony_ci} 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_cistatic int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh, 9028c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 9038c2ecf20Sopenharmony_ci{ 9048c2ecf20Sopenharmony_ci struct net *net = sock_net(skb->sk); 9058c2ecf20Sopenharmony_ci struct nlattr *tb[NETNSA_MAX + 1]; 9068c2ecf20Sopenharmony_ci struct net_fill_args fillargs = { 9078c2ecf20Sopenharmony_ci .portid = NETLINK_CB(skb).portid, 9088c2ecf20Sopenharmony_ci .seq = nlh->nlmsg_seq, 9098c2ecf20Sopenharmony_ci .cmd = RTM_NEWNSID, 9108c2ecf20Sopenharmony_ci }; 9118c2ecf20Sopenharmony_ci struct net *peer, *target = net; 9128c2ecf20Sopenharmony_ci struct nlattr *nla; 9138c2ecf20Sopenharmony_ci struct sk_buff *msg; 9148c2ecf20Sopenharmony_ci int err; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci err = rtnl_net_valid_getid_req(skb, nlh, tb, extack); 9178c2ecf20Sopenharmony_ci if (err < 0) 9188c2ecf20Sopenharmony_ci return err; 9198c2ecf20Sopenharmony_ci if (tb[NETNSA_PID]) { 9208c2ecf20Sopenharmony_ci peer = get_net_ns_by_pid(nla_get_u32(tb[NETNSA_PID])); 9218c2ecf20Sopenharmony_ci nla = tb[NETNSA_PID]; 9228c2ecf20Sopenharmony_ci } else if (tb[NETNSA_FD]) { 9238c2ecf20Sopenharmony_ci peer = get_net_ns_by_fd(nla_get_u32(tb[NETNSA_FD])); 9248c2ecf20Sopenharmony_ci nla = tb[NETNSA_FD]; 9258c2ecf20Sopenharmony_ci } else if (tb[NETNSA_NSID]) { 9268c2ecf20Sopenharmony_ci peer = get_net_ns_by_id(net, nla_get_s32(tb[NETNSA_NSID])); 9278c2ecf20Sopenharmony_ci if (!peer) 9288c2ecf20Sopenharmony_ci peer = ERR_PTR(-ENOENT); 9298c2ecf20Sopenharmony_ci nla = tb[NETNSA_NSID]; 9308c2ecf20Sopenharmony_ci } else { 9318c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, "Peer netns reference is missing"); 9328c2ecf20Sopenharmony_ci return -EINVAL; 9338c2ecf20Sopenharmony_ci } 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci if (IS_ERR(peer)) { 9368c2ecf20Sopenharmony_ci NL_SET_BAD_ATTR(extack, nla); 9378c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, "Peer netns reference is invalid"); 9388c2ecf20Sopenharmony_ci return PTR_ERR(peer); 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci if (tb[NETNSA_TARGET_NSID]) { 9428c2ecf20Sopenharmony_ci int id = nla_get_s32(tb[NETNSA_TARGET_NSID]); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci target = rtnl_get_net_ns_capable(NETLINK_CB(skb).sk, id); 9458c2ecf20Sopenharmony_ci if (IS_ERR(target)) { 9468c2ecf20Sopenharmony_ci NL_SET_BAD_ATTR(extack, tb[NETNSA_TARGET_NSID]); 9478c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, 9488c2ecf20Sopenharmony_ci "Target netns reference is invalid"); 9498c2ecf20Sopenharmony_ci err = PTR_ERR(target); 9508c2ecf20Sopenharmony_ci goto out; 9518c2ecf20Sopenharmony_ci } 9528c2ecf20Sopenharmony_ci fillargs.add_ref = true; 9538c2ecf20Sopenharmony_ci fillargs.ref_nsid = peernet2id(net, peer); 9548c2ecf20Sopenharmony_ci } 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci msg = nlmsg_new(rtnl_net_get_size(), GFP_KERNEL); 9578c2ecf20Sopenharmony_ci if (!msg) { 9588c2ecf20Sopenharmony_ci err = -ENOMEM; 9598c2ecf20Sopenharmony_ci goto out; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci fillargs.nsid = peernet2id(target, peer); 9638c2ecf20Sopenharmony_ci err = rtnl_net_fill(msg, &fillargs); 9648c2ecf20Sopenharmony_ci if (err < 0) 9658c2ecf20Sopenharmony_ci goto err_out; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci err = rtnl_unicast(msg, net, NETLINK_CB(skb).portid); 9688c2ecf20Sopenharmony_ci goto out; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_cierr_out: 9718c2ecf20Sopenharmony_ci nlmsg_free(msg); 9728c2ecf20Sopenharmony_ciout: 9738c2ecf20Sopenharmony_ci if (fillargs.add_ref) 9748c2ecf20Sopenharmony_ci put_net(target); 9758c2ecf20Sopenharmony_ci put_net(peer); 9768c2ecf20Sopenharmony_ci return err; 9778c2ecf20Sopenharmony_ci} 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_cistruct rtnl_net_dump_cb { 9808c2ecf20Sopenharmony_ci struct net *tgt_net; 9818c2ecf20Sopenharmony_ci struct net *ref_net; 9828c2ecf20Sopenharmony_ci struct sk_buff *skb; 9838c2ecf20Sopenharmony_ci struct net_fill_args fillargs; 9848c2ecf20Sopenharmony_ci int idx; 9858c2ecf20Sopenharmony_ci int s_idx; 9868c2ecf20Sopenharmony_ci}; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci/* Runs in RCU-critical section. */ 9898c2ecf20Sopenharmony_cistatic int rtnl_net_dumpid_one(int id, void *peer, void *data) 9908c2ecf20Sopenharmony_ci{ 9918c2ecf20Sopenharmony_ci struct rtnl_net_dump_cb *net_cb = (struct rtnl_net_dump_cb *)data; 9928c2ecf20Sopenharmony_ci int ret; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci if (net_cb->idx < net_cb->s_idx) 9958c2ecf20Sopenharmony_ci goto cont; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci net_cb->fillargs.nsid = id; 9988c2ecf20Sopenharmony_ci if (net_cb->fillargs.add_ref) 9998c2ecf20Sopenharmony_ci net_cb->fillargs.ref_nsid = __peernet2id(net_cb->ref_net, peer); 10008c2ecf20Sopenharmony_ci ret = rtnl_net_fill(net_cb->skb, &net_cb->fillargs); 10018c2ecf20Sopenharmony_ci if (ret < 0) 10028c2ecf20Sopenharmony_ci return ret; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_cicont: 10058c2ecf20Sopenharmony_ci net_cb->idx++; 10068c2ecf20Sopenharmony_ci return 0; 10078c2ecf20Sopenharmony_ci} 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_cistatic int rtnl_valid_dump_net_req(const struct nlmsghdr *nlh, struct sock *sk, 10108c2ecf20Sopenharmony_ci struct rtnl_net_dump_cb *net_cb, 10118c2ecf20Sopenharmony_ci struct netlink_callback *cb) 10128c2ecf20Sopenharmony_ci{ 10138c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack = cb->extack; 10148c2ecf20Sopenharmony_ci struct nlattr *tb[NETNSA_MAX + 1]; 10158c2ecf20Sopenharmony_ci int err, i; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct rtgenmsg), tb, 10188c2ecf20Sopenharmony_ci NETNSA_MAX, rtnl_net_policy, 10198c2ecf20Sopenharmony_ci extack); 10208c2ecf20Sopenharmony_ci if (err < 0) 10218c2ecf20Sopenharmony_ci return err; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci for (i = 0; i <= NETNSA_MAX; i++) { 10248c2ecf20Sopenharmony_ci if (!tb[i]) 10258c2ecf20Sopenharmony_ci continue; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci if (i == NETNSA_TARGET_NSID) { 10288c2ecf20Sopenharmony_ci struct net *net; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci net = rtnl_get_net_ns_capable(sk, nla_get_s32(tb[i])); 10318c2ecf20Sopenharmony_ci if (IS_ERR(net)) { 10328c2ecf20Sopenharmony_ci NL_SET_BAD_ATTR(extack, tb[i]); 10338c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, 10348c2ecf20Sopenharmony_ci "Invalid target network namespace id"); 10358c2ecf20Sopenharmony_ci return PTR_ERR(net); 10368c2ecf20Sopenharmony_ci } 10378c2ecf20Sopenharmony_ci net_cb->fillargs.add_ref = true; 10388c2ecf20Sopenharmony_ci net_cb->ref_net = net_cb->tgt_net; 10398c2ecf20Sopenharmony_ci net_cb->tgt_net = net; 10408c2ecf20Sopenharmony_ci } else { 10418c2ecf20Sopenharmony_ci NL_SET_BAD_ATTR(extack, tb[i]); 10428c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, 10438c2ecf20Sopenharmony_ci "Unsupported attribute in dump request"); 10448c2ecf20Sopenharmony_ci return -EINVAL; 10458c2ecf20Sopenharmony_ci } 10468c2ecf20Sopenharmony_ci } 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci return 0; 10498c2ecf20Sopenharmony_ci} 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_cistatic int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb) 10528c2ecf20Sopenharmony_ci{ 10538c2ecf20Sopenharmony_ci struct rtnl_net_dump_cb net_cb = { 10548c2ecf20Sopenharmony_ci .tgt_net = sock_net(skb->sk), 10558c2ecf20Sopenharmony_ci .skb = skb, 10568c2ecf20Sopenharmony_ci .fillargs = { 10578c2ecf20Sopenharmony_ci .portid = NETLINK_CB(cb->skb).portid, 10588c2ecf20Sopenharmony_ci .seq = cb->nlh->nlmsg_seq, 10598c2ecf20Sopenharmony_ci .flags = NLM_F_MULTI, 10608c2ecf20Sopenharmony_ci .cmd = RTM_NEWNSID, 10618c2ecf20Sopenharmony_ci }, 10628c2ecf20Sopenharmony_ci .idx = 0, 10638c2ecf20Sopenharmony_ci .s_idx = cb->args[0], 10648c2ecf20Sopenharmony_ci }; 10658c2ecf20Sopenharmony_ci int err = 0; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci if (cb->strict_check) { 10688c2ecf20Sopenharmony_ci err = rtnl_valid_dump_net_req(cb->nlh, skb->sk, &net_cb, cb); 10698c2ecf20Sopenharmony_ci if (err < 0) 10708c2ecf20Sopenharmony_ci goto end; 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci rcu_read_lock(); 10748c2ecf20Sopenharmony_ci idr_for_each(&net_cb.tgt_net->netns_ids, rtnl_net_dumpid_one, &net_cb); 10758c2ecf20Sopenharmony_ci rcu_read_unlock(); 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci cb->args[0] = net_cb.idx; 10788c2ecf20Sopenharmony_ciend: 10798c2ecf20Sopenharmony_ci if (net_cb.fillargs.add_ref) 10808c2ecf20Sopenharmony_ci put_net(net_cb.tgt_net); 10818c2ecf20Sopenharmony_ci return err < 0 ? err : skb->len; 10828c2ecf20Sopenharmony_ci} 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_cistatic void rtnl_net_notifyid(struct net *net, int cmd, int id, u32 portid, 10858c2ecf20Sopenharmony_ci struct nlmsghdr *nlh, gfp_t gfp) 10868c2ecf20Sopenharmony_ci{ 10878c2ecf20Sopenharmony_ci struct net_fill_args fillargs = { 10888c2ecf20Sopenharmony_ci .portid = portid, 10898c2ecf20Sopenharmony_ci .seq = nlh ? nlh->nlmsg_seq : 0, 10908c2ecf20Sopenharmony_ci .cmd = cmd, 10918c2ecf20Sopenharmony_ci .nsid = id, 10928c2ecf20Sopenharmony_ci }; 10938c2ecf20Sopenharmony_ci struct sk_buff *msg; 10948c2ecf20Sopenharmony_ci int err = -ENOMEM; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci msg = nlmsg_new(rtnl_net_get_size(), gfp); 10978c2ecf20Sopenharmony_ci if (!msg) 10988c2ecf20Sopenharmony_ci goto out; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci err = rtnl_net_fill(msg, &fillargs); 11018c2ecf20Sopenharmony_ci if (err < 0) 11028c2ecf20Sopenharmony_ci goto err_out; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci rtnl_notify(msg, net, portid, RTNLGRP_NSID, nlh, gfp); 11058c2ecf20Sopenharmony_ci return; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_cierr_out: 11088c2ecf20Sopenharmony_ci nlmsg_free(msg); 11098c2ecf20Sopenharmony_ciout: 11108c2ecf20Sopenharmony_ci rtnl_set_sk_err(net, RTNLGRP_NSID, err); 11118c2ecf20Sopenharmony_ci} 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_cistatic int __init net_ns_init(void) 11148c2ecf20Sopenharmony_ci{ 11158c2ecf20Sopenharmony_ci struct net_generic *ng; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_NS 11188c2ecf20Sopenharmony_ci net_cachep = kmem_cache_create("net_namespace", sizeof(struct net), 11198c2ecf20Sopenharmony_ci SMP_CACHE_BYTES, 11208c2ecf20Sopenharmony_ci SLAB_PANIC|SLAB_ACCOUNT, NULL); 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci /* Create workqueue for cleanup */ 11238c2ecf20Sopenharmony_ci netns_wq = create_singlethread_workqueue("netns"); 11248c2ecf20Sopenharmony_ci if (!netns_wq) 11258c2ecf20Sopenharmony_ci panic("Could not create netns workq"); 11268c2ecf20Sopenharmony_ci#endif 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci ng = net_alloc_generic(); 11298c2ecf20Sopenharmony_ci if (!ng) 11308c2ecf20Sopenharmony_ci panic("Could not allocate generic netns"); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci rcu_assign_pointer(init_net.gen, ng); 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci preempt_disable(); 11358c2ecf20Sopenharmony_ci __net_gen_cookie(&init_net); 11368c2ecf20Sopenharmony_ci preempt_enable(); 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci down_write(&pernet_ops_rwsem); 11398c2ecf20Sopenharmony_ci if (setup_net(&init_net, &init_user_ns)) 11408c2ecf20Sopenharmony_ci panic("Could not setup the initial network namespace"); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci init_net_initialized = true; 11438c2ecf20Sopenharmony_ci up_write(&pernet_ops_rwsem); 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci if (register_pernet_subsys(&net_ns_ops)) 11468c2ecf20Sopenharmony_ci panic("Could not register network namespace subsystems"); 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci rtnl_register(PF_UNSPEC, RTM_NEWNSID, rtnl_net_newid, NULL, 11498c2ecf20Sopenharmony_ci RTNL_FLAG_DOIT_UNLOCKED); 11508c2ecf20Sopenharmony_ci rtnl_register(PF_UNSPEC, RTM_GETNSID, rtnl_net_getid, rtnl_net_dumpid, 11518c2ecf20Sopenharmony_ci RTNL_FLAG_DOIT_UNLOCKED); 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci return 0; 11548c2ecf20Sopenharmony_ci} 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_cipure_initcall(net_ns_init); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_NS 11598c2ecf20Sopenharmony_cistatic int __register_pernet_operations(struct list_head *list, 11608c2ecf20Sopenharmony_ci struct pernet_operations *ops) 11618c2ecf20Sopenharmony_ci{ 11628c2ecf20Sopenharmony_ci struct net *net; 11638c2ecf20Sopenharmony_ci int error; 11648c2ecf20Sopenharmony_ci LIST_HEAD(net_exit_list); 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci list_add_tail(&ops->list, list); 11678c2ecf20Sopenharmony_ci if (ops->init || (ops->id && ops->size)) { 11688c2ecf20Sopenharmony_ci /* We held write locked pernet_ops_rwsem, and parallel 11698c2ecf20Sopenharmony_ci * setup_net() and cleanup_net() are not possible. 11708c2ecf20Sopenharmony_ci */ 11718c2ecf20Sopenharmony_ci for_each_net(net) { 11728c2ecf20Sopenharmony_ci error = ops_init(ops, net); 11738c2ecf20Sopenharmony_ci if (error) 11748c2ecf20Sopenharmony_ci goto out_undo; 11758c2ecf20Sopenharmony_ci list_add_tail(&net->exit_list, &net_exit_list); 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci } 11788c2ecf20Sopenharmony_ci return 0; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ciout_undo: 11818c2ecf20Sopenharmony_ci /* If I have an error cleanup all namespaces I initialized */ 11828c2ecf20Sopenharmony_ci list_del(&ops->list); 11838c2ecf20Sopenharmony_ci ops_pre_exit_list(ops, &net_exit_list); 11848c2ecf20Sopenharmony_ci synchronize_rcu(); 11858c2ecf20Sopenharmony_ci ops_exit_list(ops, &net_exit_list); 11868c2ecf20Sopenharmony_ci ops_free_list(ops, &net_exit_list); 11878c2ecf20Sopenharmony_ci return error; 11888c2ecf20Sopenharmony_ci} 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_cistatic void __unregister_pernet_operations(struct pernet_operations *ops) 11918c2ecf20Sopenharmony_ci{ 11928c2ecf20Sopenharmony_ci struct net *net; 11938c2ecf20Sopenharmony_ci LIST_HEAD(net_exit_list); 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci list_del(&ops->list); 11968c2ecf20Sopenharmony_ci /* See comment in __register_pernet_operations() */ 11978c2ecf20Sopenharmony_ci for_each_net(net) 11988c2ecf20Sopenharmony_ci list_add_tail(&net->exit_list, &net_exit_list); 11998c2ecf20Sopenharmony_ci ops_pre_exit_list(ops, &net_exit_list); 12008c2ecf20Sopenharmony_ci synchronize_rcu(); 12018c2ecf20Sopenharmony_ci ops_exit_list(ops, &net_exit_list); 12028c2ecf20Sopenharmony_ci ops_free_list(ops, &net_exit_list); 12038c2ecf20Sopenharmony_ci} 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci#else 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_cistatic int __register_pernet_operations(struct list_head *list, 12088c2ecf20Sopenharmony_ci struct pernet_operations *ops) 12098c2ecf20Sopenharmony_ci{ 12108c2ecf20Sopenharmony_ci if (!init_net_initialized) { 12118c2ecf20Sopenharmony_ci list_add_tail(&ops->list, list); 12128c2ecf20Sopenharmony_ci return 0; 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci return ops_init(ops, &init_net); 12168c2ecf20Sopenharmony_ci} 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_cistatic void __unregister_pernet_operations(struct pernet_operations *ops) 12198c2ecf20Sopenharmony_ci{ 12208c2ecf20Sopenharmony_ci if (!init_net_initialized) { 12218c2ecf20Sopenharmony_ci list_del(&ops->list); 12228c2ecf20Sopenharmony_ci } else { 12238c2ecf20Sopenharmony_ci LIST_HEAD(net_exit_list); 12248c2ecf20Sopenharmony_ci list_add(&init_net.exit_list, &net_exit_list); 12258c2ecf20Sopenharmony_ci ops_pre_exit_list(ops, &net_exit_list); 12268c2ecf20Sopenharmony_ci synchronize_rcu(); 12278c2ecf20Sopenharmony_ci ops_exit_list(ops, &net_exit_list); 12288c2ecf20Sopenharmony_ci ops_free_list(ops, &net_exit_list); 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci} 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci#endif /* CONFIG_NET_NS */ 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_cistatic DEFINE_IDA(net_generic_ids); 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_cistatic int register_pernet_operations(struct list_head *list, 12378c2ecf20Sopenharmony_ci struct pernet_operations *ops) 12388c2ecf20Sopenharmony_ci{ 12398c2ecf20Sopenharmony_ci int error; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci if (ops->id) { 12428c2ecf20Sopenharmony_ci error = ida_alloc_min(&net_generic_ids, MIN_PERNET_OPS_ID, 12438c2ecf20Sopenharmony_ci GFP_KERNEL); 12448c2ecf20Sopenharmony_ci if (error < 0) 12458c2ecf20Sopenharmony_ci return error; 12468c2ecf20Sopenharmony_ci *ops->id = error; 12478c2ecf20Sopenharmony_ci /* This does not require READ_ONCE as writers already hold 12488c2ecf20Sopenharmony_ci * pernet_ops_rwsem. But WRITE_ONCE is needed to protect 12498c2ecf20Sopenharmony_ci * net_alloc_generic. 12508c2ecf20Sopenharmony_ci */ 12518c2ecf20Sopenharmony_ci WRITE_ONCE(max_gen_ptrs, max(max_gen_ptrs, *ops->id + 1)); 12528c2ecf20Sopenharmony_ci } 12538c2ecf20Sopenharmony_ci error = __register_pernet_operations(list, ops); 12548c2ecf20Sopenharmony_ci if (error) { 12558c2ecf20Sopenharmony_ci rcu_barrier(); 12568c2ecf20Sopenharmony_ci if (ops->id) 12578c2ecf20Sopenharmony_ci ida_free(&net_generic_ids, *ops->id); 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci return error; 12618c2ecf20Sopenharmony_ci} 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_cistatic void unregister_pernet_operations(struct pernet_operations *ops) 12648c2ecf20Sopenharmony_ci{ 12658c2ecf20Sopenharmony_ci __unregister_pernet_operations(ops); 12668c2ecf20Sopenharmony_ci rcu_barrier(); 12678c2ecf20Sopenharmony_ci if (ops->id) 12688c2ecf20Sopenharmony_ci ida_free(&net_generic_ids, *ops->id); 12698c2ecf20Sopenharmony_ci} 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci/** 12728c2ecf20Sopenharmony_ci * register_pernet_subsys - register a network namespace subsystem 12738c2ecf20Sopenharmony_ci * @ops: pernet operations structure for the subsystem 12748c2ecf20Sopenharmony_ci * 12758c2ecf20Sopenharmony_ci * Register a subsystem which has init and exit functions 12768c2ecf20Sopenharmony_ci * that are called when network namespaces are created and 12778c2ecf20Sopenharmony_ci * destroyed respectively. 12788c2ecf20Sopenharmony_ci * 12798c2ecf20Sopenharmony_ci * When registered all network namespace init functions are 12808c2ecf20Sopenharmony_ci * called for every existing network namespace. Allowing kernel 12818c2ecf20Sopenharmony_ci * modules to have a race free view of the set of network namespaces. 12828c2ecf20Sopenharmony_ci * 12838c2ecf20Sopenharmony_ci * When a new network namespace is created all of the init 12848c2ecf20Sopenharmony_ci * methods are called in the order in which they were registered. 12858c2ecf20Sopenharmony_ci * 12868c2ecf20Sopenharmony_ci * When a network namespace is destroyed all of the exit methods 12878c2ecf20Sopenharmony_ci * are called in the reverse of the order with which they were 12888c2ecf20Sopenharmony_ci * registered. 12898c2ecf20Sopenharmony_ci */ 12908c2ecf20Sopenharmony_ciint register_pernet_subsys(struct pernet_operations *ops) 12918c2ecf20Sopenharmony_ci{ 12928c2ecf20Sopenharmony_ci int error; 12938c2ecf20Sopenharmony_ci down_write(&pernet_ops_rwsem); 12948c2ecf20Sopenharmony_ci error = register_pernet_operations(first_device, ops); 12958c2ecf20Sopenharmony_ci up_write(&pernet_ops_rwsem); 12968c2ecf20Sopenharmony_ci return error; 12978c2ecf20Sopenharmony_ci} 12988c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(register_pernet_subsys); 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci/** 13018c2ecf20Sopenharmony_ci * unregister_pernet_subsys - unregister a network namespace subsystem 13028c2ecf20Sopenharmony_ci * @ops: pernet operations structure to manipulate 13038c2ecf20Sopenharmony_ci * 13048c2ecf20Sopenharmony_ci * Remove the pernet operations structure from the list to be 13058c2ecf20Sopenharmony_ci * used when network namespaces are created or destroyed. In 13068c2ecf20Sopenharmony_ci * addition run the exit method for all existing network 13078c2ecf20Sopenharmony_ci * namespaces. 13088c2ecf20Sopenharmony_ci */ 13098c2ecf20Sopenharmony_civoid unregister_pernet_subsys(struct pernet_operations *ops) 13108c2ecf20Sopenharmony_ci{ 13118c2ecf20Sopenharmony_ci down_write(&pernet_ops_rwsem); 13128c2ecf20Sopenharmony_ci unregister_pernet_operations(ops); 13138c2ecf20Sopenharmony_ci up_write(&pernet_ops_rwsem); 13148c2ecf20Sopenharmony_ci} 13158c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(unregister_pernet_subsys); 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci/** 13188c2ecf20Sopenharmony_ci * register_pernet_device - register a network namespace device 13198c2ecf20Sopenharmony_ci * @ops: pernet operations structure for the subsystem 13208c2ecf20Sopenharmony_ci * 13218c2ecf20Sopenharmony_ci * Register a device which has init and exit functions 13228c2ecf20Sopenharmony_ci * that are called when network namespaces are created and 13238c2ecf20Sopenharmony_ci * destroyed respectively. 13248c2ecf20Sopenharmony_ci * 13258c2ecf20Sopenharmony_ci * When registered all network namespace init functions are 13268c2ecf20Sopenharmony_ci * called for every existing network namespace. Allowing kernel 13278c2ecf20Sopenharmony_ci * modules to have a race free view of the set of network namespaces. 13288c2ecf20Sopenharmony_ci * 13298c2ecf20Sopenharmony_ci * When a new network namespace is created all of the init 13308c2ecf20Sopenharmony_ci * methods are called in the order in which they were registered. 13318c2ecf20Sopenharmony_ci * 13328c2ecf20Sopenharmony_ci * When a network namespace is destroyed all of the exit methods 13338c2ecf20Sopenharmony_ci * are called in the reverse of the order with which they were 13348c2ecf20Sopenharmony_ci * registered. 13358c2ecf20Sopenharmony_ci */ 13368c2ecf20Sopenharmony_ciint register_pernet_device(struct pernet_operations *ops) 13378c2ecf20Sopenharmony_ci{ 13388c2ecf20Sopenharmony_ci int error; 13398c2ecf20Sopenharmony_ci down_write(&pernet_ops_rwsem); 13408c2ecf20Sopenharmony_ci error = register_pernet_operations(&pernet_list, ops); 13418c2ecf20Sopenharmony_ci if (!error && (first_device == &pernet_list)) 13428c2ecf20Sopenharmony_ci first_device = &ops->list; 13438c2ecf20Sopenharmony_ci up_write(&pernet_ops_rwsem); 13448c2ecf20Sopenharmony_ci return error; 13458c2ecf20Sopenharmony_ci} 13468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(register_pernet_device); 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci/** 13498c2ecf20Sopenharmony_ci * unregister_pernet_device - unregister a network namespace netdevice 13508c2ecf20Sopenharmony_ci * @ops: pernet operations structure to manipulate 13518c2ecf20Sopenharmony_ci * 13528c2ecf20Sopenharmony_ci * Remove the pernet operations structure from the list to be 13538c2ecf20Sopenharmony_ci * used when network namespaces are created or destroyed. In 13548c2ecf20Sopenharmony_ci * addition run the exit method for all existing network 13558c2ecf20Sopenharmony_ci * namespaces. 13568c2ecf20Sopenharmony_ci */ 13578c2ecf20Sopenharmony_civoid unregister_pernet_device(struct pernet_operations *ops) 13588c2ecf20Sopenharmony_ci{ 13598c2ecf20Sopenharmony_ci down_write(&pernet_ops_rwsem); 13608c2ecf20Sopenharmony_ci if (&ops->list == first_device) 13618c2ecf20Sopenharmony_ci first_device = first_device->next; 13628c2ecf20Sopenharmony_ci unregister_pernet_operations(ops); 13638c2ecf20Sopenharmony_ci up_write(&pernet_ops_rwsem); 13648c2ecf20Sopenharmony_ci} 13658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(unregister_pernet_device); 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_NS 13688c2ecf20Sopenharmony_cistatic struct ns_common *netns_get(struct task_struct *task) 13698c2ecf20Sopenharmony_ci{ 13708c2ecf20Sopenharmony_ci struct net *net = NULL; 13718c2ecf20Sopenharmony_ci struct nsproxy *nsproxy; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci task_lock(task); 13748c2ecf20Sopenharmony_ci nsproxy = task->nsproxy; 13758c2ecf20Sopenharmony_ci if (nsproxy) 13768c2ecf20Sopenharmony_ci net = get_net(nsproxy->net_ns); 13778c2ecf20Sopenharmony_ci task_unlock(task); 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci return net ? &net->ns : NULL; 13808c2ecf20Sopenharmony_ci} 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_cistatic inline struct net *to_net_ns(struct ns_common *ns) 13838c2ecf20Sopenharmony_ci{ 13848c2ecf20Sopenharmony_ci return container_of(ns, struct net, ns); 13858c2ecf20Sopenharmony_ci} 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_cistatic void netns_put(struct ns_common *ns) 13888c2ecf20Sopenharmony_ci{ 13898c2ecf20Sopenharmony_ci put_net(to_net_ns(ns)); 13908c2ecf20Sopenharmony_ci} 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_cistatic int netns_install(struct nsset *nsset, struct ns_common *ns) 13938c2ecf20Sopenharmony_ci{ 13948c2ecf20Sopenharmony_ci struct nsproxy *nsproxy = nsset->nsproxy; 13958c2ecf20Sopenharmony_ci struct net *net = to_net_ns(ns); 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci if (!ns_capable(net->user_ns, CAP_SYS_ADMIN) || 13988c2ecf20Sopenharmony_ci !ns_capable(nsset->cred->user_ns, CAP_SYS_ADMIN)) 13998c2ecf20Sopenharmony_ci return -EPERM; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci put_net(nsproxy->net_ns); 14028c2ecf20Sopenharmony_ci nsproxy->net_ns = get_net(net); 14038c2ecf20Sopenharmony_ci return 0; 14048c2ecf20Sopenharmony_ci} 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_cistatic struct user_namespace *netns_owner(struct ns_common *ns) 14078c2ecf20Sopenharmony_ci{ 14088c2ecf20Sopenharmony_ci return to_net_ns(ns)->user_ns; 14098c2ecf20Sopenharmony_ci} 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ciconst struct proc_ns_operations netns_operations = { 14128c2ecf20Sopenharmony_ci .name = "net", 14138c2ecf20Sopenharmony_ci .type = CLONE_NEWNET, 14148c2ecf20Sopenharmony_ci .get = netns_get, 14158c2ecf20Sopenharmony_ci .put = netns_put, 14168c2ecf20Sopenharmony_ci .install = netns_install, 14178c2ecf20Sopenharmony_ci .owner = netns_owner, 14188c2ecf20Sopenharmony_ci}; 14198c2ecf20Sopenharmony_ci#endif 1420