162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/workqueue.h> 562306a36Sopenharmony_ci#include <linux/rtnetlink.h> 662306a36Sopenharmony_ci#include <linux/cache.h> 762306a36Sopenharmony_ci#include <linux/slab.h> 862306a36Sopenharmony_ci#include <linux/list.h> 962306a36Sopenharmony_ci#include <linux/delay.h> 1062306a36Sopenharmony_ci#include <linux/sched.h> 1162306a36Sopenharmony_ci#include <linux/idr.h> 1262306a36Sopenharmony_ci#include <linux/rculist.h> 1362306a36Sopenharmony_ci#include <linux/nsproxy.h> 1462306a36Sopenharmony_ci#include <linux/fs.h> 1562306a36Sopenharmony_ci#include <linux/proc_ns.h> 1662306a36Sopenharmony_ci#include <linux/file.h> 1762306a36Sopenharmony_ci#include <linux/export.h> 1862306a36Sopenharmony_ci#include <linux/user_namespace.h> 1962306a36Sopenharmony_ci#include <linux/net_namespace.h> 2062306a36Sopenharmony_ci#include <linux/sched/task.h> 2162306a36Sopenharmony_ci#include <linux/uidgid.h> 2262306a36Sopenharmony_ci#include <linux/cookie.h> 2362306a36Sopenharmony_ci#include <linux/proc_fs.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include <net/sock.h> 2662306a36Sopenharmony_ci#include <net/netlink.h> 2762306a36Sopenharmony_ci#include <net/net_namespace.h> 2862306a36Sopenharmony_ci#include <net/netns/generic.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* 3162306a36Sopenharmony_ci * Our network namespace constructor/destructor lists 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic LIST_HEAD(pernet_list); 3562306a36Sopenharmony_cistatic struct list_head *first_device = &pernet_list; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ciLIST_HEAD(net_namespace_list); 3862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(net_namespace_list); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* Protects net_namespace_list. Nests iside rtnl_lock() */ 4162306a36Sopenharmony_ciDECLARE_RWSEM(net_rwsem); 4262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(net_rwsem); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#ifdef CONFIG_KEYS 4562306a36Sopenharmony_cistatic struct key_tag init_net_key_domain = { .usage = REFCOUNT_INIT(1) }; 4662306a36Sopenharmony_ci#endif 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistruct net init_net; 4962306a36Sopenharmony_ciEXPORT_SYMBOL(init_net); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic bool init_net_initialized; 5262306a36Sopenharmony_ci/* 5362306a36Sopenharmony_ci * pernet_ops_rwsem: protects: pernet_list, net_generic_ids, 5462306a36Sopenharmony_ci * init_net_initialized and first_device pointer. 5562306a36Sopenharmony_ci * This is internal net namespace object. Please, don't use it 5662306a36Sopenharmony_ci * outside. 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_ciDECLARE_RWSEM(pernet_ops_rwsem); 5962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pernet_ops_rwsem); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define MIN_PERNET_OPS_ID \ 6262306a36Sopenharmony_ci ((sizeof(struct net_generic) + sizeof(void *) - 1) / sizeof(void *)) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#define INITIAL_NET_GEN_PTRS 13 /* +1 for len +2 for rcu_head */ 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic unsigned int max_gen_ptrs = INITIAL_NET_GEN_PTRS; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ciDEFINE_COOKIE(net_cookie); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic struct net_generic *net_alloc_generic(void) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct net_generic *ng; 7362306a36Sopenharmony_ci unsigned int generic_size = offsetof(struct net_generic, ptr[max_gen_ptrs]); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci ng = kzalloc(generic_size, GFP_KERNEL); 7662306a36Sopenharmony_ci if (ng) 7762306a36Sopenharmony_ci ng->s.len = max_gen_ptrs; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci return ng; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic int net_assign_generic(struct net *net, unsigned int id, void *data) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct net_generic *ng, *old_ng; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci BUG_ON(id < MIN_PERNET_OPS_ID); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci old_ng = rcu_dereference_protected(net->gen, 8962306a36Sopenharmony_ci lockdep_is_held(&pernet_ops_rwsem)); 9062306a36Sopenharmony_ci if (old_ng->s.len > id) { 9162306a36Sopenharmony_ci old_ng->ptr[id] = data; 9262306a36Sopenharmony_ci return 0; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci ng = net_alloc_generic(); 9662306a36Sopenharmony_ci if (!ng) 9762306a36Sopenharmony_ci return -ENOMEM; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* 10062306a36Sopenharmony_ci * Some synchronisation notes: 10162306a36Sopenharmony_ci * 10262306a36Sopenharmony_ci * The net_generic explores the net->gen array inside rcu 10362306a36Sopenharmony_ci * read section. Besides once set the net->gen->ptr[x] 10462306a36Sopenharmony_ci * pointer never changes (see rules in netns/generic.h). 10562306a36Sopenharmony_ci * 10662306a36Sopenharmony_ci * That said, we simply duplicate this array and schedule 10762306a36Sopenharmony_ci * the old copy for kfree after a grace period. 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci memcpy(&ng->ptr[MIN_PERNET_OPS_ID], &old_ng->ptr[MIN_PERNET_OPS_ID], 11162306a36Sopenharmony_ci (old_ng->s.len - MIN_PERNET_OPS_ID) * sizeof(void *)); 11262306a36Sopenharmony_ci ng->ptr[id] = data; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci rcu_assign_pointer(net->gen, ng); 11562306a36Sopenharmony_ci kfree_rcu(old_ng, s.rcu); 11662306a36Sopenharmony_ci return 0; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic int ops_init(const struct pernet_operations *ops, struct net *net) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci struct net_generic *ng; 12262306a36Sopenharmony_ci int err = -ENOMEM; 12362306a36Sopenharmony_ci void *data = NULL; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (ops->id && ops->size) { 12662306a36Sopenharmony_ci data = kzalloc(ops->size, GFP_KERNEL); 12762306a36Sopenharmony_ci if (!data) 12862306a36Sopenharmony_ci goto out; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci err = net_assign_generic(net, *ops->id, data); 13162306a36Sopenharmony_ci if (err) 13262306a36Sopenharmony_ci goto cleanup; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci err = 0; 13562306a36Sopenharmony_ci if (ops->init) 13662306a36Sopenharmony_ci err = ops->init(net); 13762306a36Sopenharmony_ci if (!err) 13862306a36Sopenharmony_ci return 0; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if (ops->id && ops->size) { 14162306a36Sopenharmony_ci ng = rcu_dereference_protected(net->gen, 14262306a36Sopenharmony_ci lockdep_is_held(&pernet_ops_rwsem)); 14362306a36Sopenharmony_ci ng->ptr[*ops->id] = NULL; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cicleanup: 14762306a36Sopenharmony_ci kfree(data); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ciout: 15062306a36Sopenharmony_ci return err; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic void ops_pre_exit_list(const struct pernet_operations *ops, 15462306a36Sopenharmony_ci struct list_head *net_exit_list) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct net *net; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if (ops->pre_exit) { 15962306a36Sopenharmony_ci list_for_each_entry(net, net_exit_list, exit_list) 16062306a36Sopenharmony_ci ops->pre_exit(net); 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic void ops_exit_list(const struct pernet_operations *ops, 16562306a36Sopenharmony_ci struct list_head *net_exit_list) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct net *net; 16862306a36Sopenharmony_ci if (ops->exit) { 16962306a36Sopenharmony_ci list_for_each_entry(net, net_exit_list, exit_list) { 17062306a36Sopenharmony_ci ops->exit(net); 17162306a36Sopenharmony_ci cond_resched(); 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci if (ops->exit_batch) 17562306a36Sopenharmony_ci ops->exit_batch(net_exit_list); 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic void ops_free_list(const struct pernet_operations *ops, 17962306a36Sopenharmony_ci struct list_head *net_exit_list) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct net *net; 18262306a36Sopenharmony_ci if (ops->size && ops->id) { 18362306a36Sopenharmony_ci list_for_each_entry(net, net_exit_list, exit_list) 18462306a36Sopenharmony_ci kfree(net_generic(net, *ops->id)); 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci/* should be called with nsid_lock held */ 18962306a36Sopenharmony_cistatic int alloc_netid(struct net *net, struct net *peer, int reqid) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci int min = 0, max = 0; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (reqid >= 0) { 19462306a36Sopenharmony_ci min = reqid; 19562306a36Sopenharmony_ci max = reqid + 1; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci return idr_alloc(&net->netns_ids, peer, min, max, GFP_ATOMIC); 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci/* This function is used by idr_for_each(). If net is equal to peer, the 20262306a36Sopenharmony_ci * function returns the id so that idr_for_each() stops. Because we cannot 20362306a36Sopenharmony_ci * returns the id 0 (idr_for_each() will not stop), we return the magic value 20462306a36Sopenharmony_ci * NET_ID_ZERO (-1) for it. 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_ci#define NET_ID_ZERO -1 20762306a36Sopenharmony_cistatic int net_eq_idr(int id, void *net, void *peer) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci if (net_eq(net, peer)) 21062306a36Sopenharmony_ci return id ? : NET_ID_ZERO; 21162306a36Sopenharmony_ci return 0; 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci/* Must be called from RCU-critical section or with nsid_lock held */ 21562306a36Sopenharmony_cistatic int __peernet2id(const struct net *net, struct net *peer) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci int id = idr_for_each(&net->netns_ids, net_eq_idr, peer); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* Magic value for id 0. */ 22062306a36Sopenharmony_ci if (id == NET_ID_ZERO) 22162306a36Sopenharmony_ci return 0; 22262306a36Sopenharmony_ci if (id > 0) 22362306a36Sopenharmony_ci return id; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci return NETNSA_NSID_NOT_ASSIGNED; 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic void rtnl_net_notifyid(struct net *net, int cmd, int id, u32 portid, 22962306a36Sopenharmony_ci struct nlmsghdr *nlh, gfp_t gfp); 23062306a36Sopenharmony_ci/* This function returns the id of a peer netns. If no id is assigned, one will 23162306a36Sopenharmony_ci * be allocated and returned. 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_ciint peernet2id_alloc(struct net *net, struct net *peer, gfp_t gfp) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci int id; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (refcount_read(&net->ns.count) == 0) 23862306a36Sopenharmony_ci return NETNSA_NSID_NOT_ASSIGNED; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci spin_lock_bh(&net->nsid_lock); 24162306a36Sopenharmony_ci id = __peernet2id(net, peer); 24262306a36Sopenharmony_ci if (id >= 0) { 24362306a36Sopenharmony_ci spin_unlock_bh(&net->nsid_lock); 24462306a36Sopenharmony_ci return id; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* When peer is obtained from RCU lists, we may race with 24862306a36Sopenharmony_ci * its cleanup. Check whether it's alive, and this guarantees 24962306a36Sopenharmony_ci * we never hash a peer back to net->netns_ids, after it has 25062306a36Sopenharmony_ci * just been idr_remove()'d from there in cleanup_net(). 25162306a36Sopenharmony_ci */ 25262306a36Sopenharmony_ci if (!maybe_get_net(peer)) { 25362306a36Sopenharmony_ci spin_unlock_bh(&net->nsid_lock); 25462306a36Sopenharmony_ci return NETNSA_NSID_NOT_ASSIGNED; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci id = alloc_netid(net, peer, -1); 25862306a36Sopenharmony_ci spin_unlock_bh(&net->nsid_lock); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci put_net(peer); 26162306a36Sopenharmony_ci if (id < 0) 26262306a36Sopenharmony_ci return NETNSA_NSID_NOT_ASSIGNED; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci rtnl_net_notifyid(net, RTM_NEWNSID, id, 0, NULL, gfp); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci return id; 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(peernet2id_alloc); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci/* This function returns, if assigned, the id of a peer netns. */ 27162306a36Sopenharmony_ciint peernet2id(const struct net *net, struct net *peer) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci int id; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci rcu_read_lock(); 27662306a36Sopenharmony_ci id = __peernet2id(net, peer); 27762306a36Sopenharmony_ci rcu_read_unlock(); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci return id; 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ciEXPORT_SYMBOL(peernet2id); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci/* This function returns true is the peer netns has an id assigned into the 28462306a36Sopenharmony_ci * current netns. 28562306a36Sopenharmony_ci */ 28662306a36Sopenharmony_cibool peernet_has_id(const struct net *net, struct net *peer) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci return peernet2id(net, peer) >= 0; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistruct net *get_net_ns_by_id(const struct net *net, int id) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci struct net *peer; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (id < 0) 29662306a36Sopenharmony_ci return NULL; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci rcu_read_lock(); 29962306a36Sopenharmony_ci peer = idr_find(&net->netns_ids, id); 30062306a36Sopenharmony_ci if (peer) 30162306a36Sopenharmony_ci peer = maybe_get_net(peer); 30262306a36Sopenharmony_ci rcu_read_unlock(); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci return peer; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(get_net_ns_by_id); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci/* init code that must occur even if setup_net() is not called. */ 30962306a36Sopenharmony_cistatic __net_init void preinit_net(struct net *net) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci ref_tracker_dir_init(&net->notrefcnt_tracker, 128, "net notrefcnt"); 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci/* 31562306a36Sopenharmony_ci * setup_net runs the initializers for the network namespace object. 31662306a36Sopenharmony_ci */ 31762306a36Sopenharmony_cistatic __net_init int setup_net(struct net *net, struct user_namespace *user_ns) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci /* Must be called with pernet_ops_rwsem held */ 32062306a36Sopenharmony_ci const struct pernet_operations *ops, *saved_ops; 32162306a36Sopenharmony_ci int error = 0; 32262306a36Sopenharmony_ci LIST_HEAD(net_exit_list); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci refcount_set(&net->ns.count, 1); 32562306a36Sopenharmony_ci ref_tracker_dir_init(&net->refcnt_tracker, 128, "net refcnt"); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci refcount_set(&net->passive, 1); 32862306a36Sopenharmony_ci get_random_bytes(&net->hash_mix, sizeof(u32)); 32962306a36Sopenharmony_ci preempt_disable(); 33062306a36Sopenharmony_ci net->net_cookie = gen_cookie_next(&net_cookie); 33162306a36Sopenharmony_ci preempt_enable(); 33262306a36Sopenharmony_ci net->dev_base_seq = 1; 33362306a36Sopenharmony_ci net->user_ns = user_ns; 33462306a36Sopenharmony_ci idr_init(&net->netns_ids); 33562306a36Sopenharmony_ci spin_lock_init(&net->nsid_lock); 33662306a36Sopenharmony_ci mutex_init(&net->ipv4.ra_mutex); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci list_for_each_entry(ops, &pernet_list, list) { 33962306a36Sopenharmony_ci error = ops_init(ops, net); 34062306a36Sopenharmony_ci if (error < 0) 34162306a36Sopenharmony_ci goto out_undo; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci down_write(&net_rwsem); 34462306a36Sopenharmony_ci list_add_tail_rcu(&net->list, &net_namespace_list); 34562306a36Sopenharmony_ci up_write(&net_rwsem); 34662306a36Sopenharmony_ciout: 34762306a36Sopenharmony_ci return error; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ciout_undo: 35062306a36Sopenharmony_ci /* Walk through the list backwards calling the exit functions 35162306a36Sopenharmony_ci * for the pernet modules whose init functions did not fail. 35262306a36Sopenharmony_ci */ 35362306a36Sopenharmony_ci list_add(&net->exit_list, &net_exit_list); 35462306a36Sopenharmony_ci saved_ops = ops; 35562306a36Sopenharmony_ci list_for_each_entry_continue_reverse(ops, &pernet_list, list) 35662306a36Sopenharmony_ci ops_pre_exit_list(ops, &net_exit_list); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci synchronize_rcu(); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci ops = saved_ops; 36162306a36Sopenharmony_ci list_for_each_entry_continue_reverse(ops, &pernet_list, list) 36262306a36Sopenharmony_ci ops_exit_list(ops, &net_exit_list); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci ops = saved_ops; 36562306a36Sopenharmony_ci list_for_each_entry_continue_reverse(ops, &pernet_list, list) 36662306a36Sopenharmony_ci ops_free_list(ops, &net_exit_list); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci rcu_barrier(); 36962306a36Sopenharmony_ci goto out; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic int __net_init net_defaults_init_net(struct net *net) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci net->core.sysctl_somaxconn = SOMAXCONN; 37562306a36Sopenharmony_ci net->core.sysctl_txrehash = SOCK_TXREHASH_ENABLED; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci return 0; 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic struct pernet_operations net_defaults_ops = { 38162306a36Sopenharmony_ci .init = net_defaults_init_net, 38262306a36Sopenharmony_ci}; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic __init int net_defaults_init(void) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci if (register_pernet_subsys(&net_defaults_ops)) 38762306a36Sopenharmony_ci panic("Cannot initialize net default settings"); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci return 0; 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cicore_initcall(net_defaults_init); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci#ifdef CONFIG_NET_NS 39562306a36Sopenharmony_cistatic struct ucounts *inc_net_namespaces(struct user_namespace *ns) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci return inc_ucount(ns, current_euid(), UCOUNT_NET_NAMESPACES); 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic void dec_net_namespaces(struct ucounts *ucounts) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci dec_ucount(ucounts, UCOUNT_NET_NAMESPACES); 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic struct kmem_cache *net_cachep __ro_after_init; 40662306a36Sopenharmony_cistatic struct workqueue_struct *netns_wq; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic struct net *net_alloc(void) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci struct net *net = NULL; 41162306a36Sopenharmony_ci struct net_generic *ng; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci ng = net_alloc_generic(); 41462306a36Sopenharmony_ci if (!ng) 41562306a36Sopenharmony_ci goto out; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci net = kmem_cache_zalloc(net_cachep, GFP_KERNEL); 41862306a36Sopenharmony_ci if (!net) 41962306a36Sopenharmony_ci goto out_free; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci#ifdef CONFIG_KEYS 42262306a36Sopenharmony_ci net->key_domain = kzalloc(sizeof(struct key_tag), GFP_KERNEL); 42362306a36Sopenharmony_ci if (!net->key_domain) 42462306a36Sopenharmony_ci goto out_free_2; 42562306a36Sopenharmony_ci refcount_set(&net->key_domain->usage, 1); 42662306a36Sopenharmony_ci#endif 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci rcu_assign_pointer(net->gen, ng); 42962306a36Sopenharmony_ciout: 43062306a36Sopenharmony_ci return net; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci#ifdef CONFIG_KEYS 43362306a36Sopenharmony_ciout_free_2: 43462306a36Sopenharmony_ci kmem_cache_free(net_cachep, net); 43562306a36Sopenharmony_ci net = NULL; 43662306a36Sopenharmony_ci#endif 43762306a36Sopenharmony_ciout_free: 43862306a36Sopenharmony_ci kfree(ng); 43962306a36Sopenharmony_ci goto out; 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic void net_free(struct net *net) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci if (refcount_dec_and_test(&net->passive)) { 44562306a36Sopenharmony_ci kfree(rcu_access_pointer(net->gen)); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci /* There should not be any trackers left there. */ 44862306a36Sopenharmony_ci ref_tracker_dir_exit(&net->notrefcnt_tracker); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci kmem_cache_free(net_cachep, net); 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_civoid net_drop_ns(void *p) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci struct net *net = (struct net *)p; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (net) 45962306a36Sopenharmony_ci net_free(net); 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistruct net *copy_net_ns(unsigned long flags, 46362306a36Sopenharmony_ci struct user_namespace *user_ns, struct net *old_net) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci struct ucounts *ucounts; 46662306a36Sopenharmony_ci struct net *net; 46762306a36Sopenharmony_ci int rv; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (!(flags & CLONE_NEWNET)) 47062306a36Sopenharmony_ci return get_net(old_net); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci ucounts = inc_net_namespaces(user_ns); 47362306a36Sopenharmony_ci if (!ucounts) 47462306a36Sopenharmony_ci return ERR_PTR(-ENOSPC); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci net = net_alloc(); 47762306a36Sopenharmony_ci if (!net) { 47862306a36Sopenharmony_ci rv = -ENOMEM; 47962306a36Sopenharmony_ci goto dec_ucounts; 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci preinit_net(net); 48362306a36Sopenharmony_ci refcount_set(&net->passive, 1); 48462306a36Sopenharmony_ci net->ucounts = ucounts; 48562306a36Sopenharmony_ci get_user_ns(user_ns); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci rv = down_read_killable(&pernet_ops_rwsem); 48862306a36Sopenharmony_ci if (rv < 0) 48962306a36Sopenharmony_ci goto put_userns; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci rv = setup_net(net, user_ns); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci up_read(&pernet_ops_rwsem); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci if (rv < 0) { 49662306a36Sopenharmony_ciput_userns: 49762306a36Sopenharmony_ci#ifdef CONFIG_KEYS 49862306a36Sopenharmony_ci key_remove_domain(net->key_domain); 49962306a36Sopenharmony_ci#endif 50062306a36Sopenharmony_ci put_user_ns(user_ns); 50162306a36Sopenharmony_ci net_free(net); 50262306a36Sopenharmony_cidec_ucounts: 50362306a36Sopenharmony_ci dec_net_namespaces(ucounts); 50462306a36Sopenharmony_ci return ERR_PTR(rv); 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci return net; 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci/** 51062306a36Sopenharmony_ci * net_ns_get_ownership - get sysfs ownership data for @net 51162306a36Sopenharmony_ci * @net: network namespace in question (can be NULL) 51262306a36Sopenharmony_ci * @uid: kernel user ID for sysfs objects 51362306a36Sopenharmony_ci * @gid: kernel group ID for sysfs objects 51462306a36Sopenharmony_ci * 51562306a36Sopenharmony_ci * Returns the uid/gid pair of root in the user namespace associated with the 51662306a36Sopenharmony_ci * given network namespace. 51762306a36Sopenharmony_ci */ 51862306a36Sopenharmony_civoid net_ns_get_ownership(const struct net *net, kuid_t *uid, kgid_t *gid) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci if (net) { 52162306a36Sopenharmony_ci kuid_t ns_root_uid = make_kuid(net->user_ns, 0); 52262306a36Sopenharmony_ci kgid_t ns_root_gid = make_kgid(net->user_ns, 0); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (uid_valid(ns_root_uid)) 52562306a36Sopenharmony_ci *uid = ns_root_uid; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci if (gid_valid(ns_root_gid)) 52862306a36Sopenharmony_ci *gid = ns_root_gid; 52962306a36Sopenharmony_ci } else { 53062306a36Sopenharmony_ci *uid = GLOBAL_ROOT_UID; 53162306a36Sopenharmony_ci *gid = GLOBAL_ROOT_GID; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(net_ns_get_ownership); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic void unhash_nsid(struct net *net, struct net *last) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci struct net *tmp; 53962306a36Sopenharmony_ci /* This function is only called from cleanup_net() work, 54062306a36Sopenharmony_ci * and this work is the only process, that may delete 54162306a36Sopenharmony_ci * a net from net_namespace_list. So, when the below 54262306a36Sopenharmony_ci * is executing, the list may only grow. Thus, we do not 54362306a36Sopenharmony_ci * use for_each_net_rcu() or net_rwsem. 54462306a36Sopenharmony_ci */ 54562306a36Sopenharmony_ci for_each_net(tmp) { 54662306a36Sopenharmony_ci int id; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci spin_lock_bh(&tmp->nsid_lock); 54962306a36Sopenharmony_ci id = __peernet2id(tmp, net); 55062306a36Sopenharmony_ci if (id >= 0) 55162306a36Sopenharmony_ci idr_remove(&tmp->netns_ids, id); 55262306a36Sopenharmony_ci spin_unlock_bh(&tmp->nsid_lock); 55362306a36Sopenharmony_ci if (id >= 0) 55462306a36Sopenharmony_ci rtnl_net_notifyid(tmp, RTM_DELNSID, id, 0, NULL, 55562306a36Sopenharmony_ci GFP_KERNEL); 55662306a36Sopenharmony_ci if (tmp == last) 55762306a36Sopenharmony_ci break; 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci spin_lock_bh(&net->nsid_lock); 56062306a36Sopenharmony_ci idr_destroy(&net->netns_ids); 56162306a36Sopenharmony_ci spin_unlock_bh(&net->nsid_lock); 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_cistatic LLIST_HEAD(cleanup_list); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_cistatic void cleanup_net(struct work_struct *work) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci const struct pernet_operations *ops; 56962306a36Sopenharmony_ci struct net *net, *tmp, *last; 57062306a36Sopenharmony_ci struct llist_node *net_kill_list; 57162306a36Sopenharmony_ci LIST_HEAD(net_exit_list); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci /* Atomically snapshot the list of namespaces to cleanup */ 57462306a36Sopenharmony_ci net_kill_list = llist_del_all(&cleanup_list); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci down_read(&pernet_ops_rwsem); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci /* Don't let anyone else find us. */ 57962306a36Sopenharmony_ci down_write(&net_rwsem); 58062306a36Sopenharmony_ci llist_for_each_entry(net, net_kill_list, cleanup_list) 58162306a36Sopenharmony_ci list_del_rcu(&net->list); 58262306a36Sopenharmony_ci /* Cache last net. After we unlock rtnl, no one new net 58362306a36Sopenharmony_ci * added to net_namespace_list can assign nsid pointer 58462306a36Sopenharmony_ci * to a net from net_kill_list (see peernet2id_alloc()). 58562306a36Sopenharmony_ci * So, we skip them in unhash_nsid(). 58662306a36Sopenharmony_ci * 58762306a36Sopenharmony_ci * Note, that unhash_nsid() does not delete nsid links 58862306a36Sopenharmony_ci * between net_kill_list's nets, as they've already 58962306a36Sopenharmony_ci * deleted from net_namespace_list. But, this would be 59062306a36Sopenharmony_ci * useless anyway, as netns_ids are destroyed there. 59162306a36Sopenharmony_ci */ 59262306a36Sopenharmony_ci last = list_last_entry(&net_namespace_list, struct net, list); 59362306a36Sopenharmony_ci up_write(&net_rwsem); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci llist_for_each_entry(net, net_kill_list, cleanup_list) { 59662306a36Sopenharmony_ci unhash_nsid(net, last); 59762306a36Sopenharmony_ci list_add_tail(&net->exit_list, &net_exit_list); 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci /* Run all of the network namespace pre_exit methods */ 60162306a36Sopenharmony_ci list_for_each_entry_reverse(ops, &pernet_list, list) 60262306a36Sopenharmony_ci ops_pre_exit_list(ops, &net_exit_list); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci /* 60562306a36Sopenharmony_ci * Another CPU might be rcu-iterating the list, wait for it. 60662306a36Sopenharmony_ci * This needs to be before calling the exit() notifiers, so 60762306a36Sopenharmony_ci * the rcu_barrier() below isn't sufficient alone. 60862306a36Sopenharmony_ci * Also the pre_exit() and exit() methods need this barrier. 60962306a36Sopenharmony_ci */ 61062306a36Sopenharmony_ci synchronize_rcu(); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci /* Run all of the network namespace exit methods */ 61362306a36Sopenharmony_ci list_for_each_entry_reverse(ops, &pernet_list, list) 61462306a36Sopenharmony_ci ops_exit_list(ops, &net_exit_list); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci /* Free the net generic variables */ 61762306a36Sopenharmony_ci list_for_each_entry_reverse(ops, &pernet_list, list) 61862306a36Sopenharmony_ci ops_free_list(ops, &net_exit_list); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci up_read(&pernet_ops_rwsem); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci /* Ensure there are no outstanding rcu callbacks using this 62362306a36Sopenharmony_ci * network namespace. 62462306a36Sopenharmony_ci */ 62562306a36Sopenharmony_ci rcu_barrier(); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci /* Finally it is safe to free my network namespace structure */ 62862306a36Sopenharmony_ci list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) { 62962306a36Sopenharmony_ci list_del_init(&net->exit_list); 63062306a36Sopenharmony_ci dec_net_namespaces(net->ucounts); 63162306a36Sopenharmony_ci#ifdef CONFIG_KEYS 63262306a36Sopenharmony_ci key_remove_domain(net->key_domain); 63362306a36Sopenharmony_ci#endif 63462306a36Sopenharmony_ci put_user_ns(net->user_ns); 63562306a36Sopenharmony_ci net_free(net); 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci} 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci/** 64062306a36Sopenharmony_ci * net_ns_barrier - wait until concurrent net_cleanup_work is done 64162306a36Sopenharmony_ci * 64262306a36Sopenharmony_ci * cleanup_net runs from work queue and will first remove namespaces 64362306a36Sopenharmony_ci * from the global list, then run net exit functions. 64462306a36Sopenharmony_ci * 64562306a36Sopenharmony_ci * Call this in module exit path to make sure that all netns 64662306a36Sopenharmony_ci * ->exit ops have been invoked before the function is removed. 64762306a36Sopenharmony_ci */ 64862306a36Sopenharmony_civoid net_ns_barrier(void) 64962306a36Sopenharmony_ci{ 65062306a36Sopenharmony_ci down_write(&pernet_ops_rwsem); 65162306a36Sopenharmony_ci up_write(&pernet_ops_rwsem); 65262306a36Sopenharmony_ci} 65362306a36Sopenharmony_ciEXPORT_SYMBOL(net_ns_barrier); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_cistatic DECLARE_WORK(net_cleanup_work, cleanup_net); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_civoid __put_net(struct net *net) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci ref_tracker_dir_exit(&net->refcnt_tracker); 66062306a36Sopenharmony_ci /* Cleanup the network namespace in process context */ 66162306a36Sopenharmony_ci if (llist_add(&net->cleanup_list, &cleanup_list)) 66262306a36Sopenharmony_ci queue_work(netns_wq, &net_cleanup_work); 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__put_net); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci/** 66762306a36Sopenharmony_ci * get_net_ns - increment the refcount of the network namespace 66862306a36Sopenharmony_ci * @ns: common namespace (net) 66962306a36Sopenharmony_ci * 67062306a36Sopenharmony_ci * Returns the net's common namespace. 67162306a36Sopenharmony_ci */ 67262306a36Sopenharmony_cistruct ns_common *get_net_ns(struct ns_common *ns) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci return &get_net(container_of(ns, struct net, ns))->ns; 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(get_net_ns); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_cistruct net *get_net_ns_by_fd(int fd) 67962306a36Sopenharmony_ci{ 68062306a36Sopenharmony_ci struct fd f = fdget(fd); 68162306a36Sopenharmony_ci struct net *net = ERR_PTR(-EINVAL); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci if (!f.file) 68462306a36Sopenharmony_ci return ERR_PTR(-EBADF); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (proc_ns_file(f.file)) { 68762306a36Sopenharmony_ci struct ns_common *ns = get_proc_ns(file_inode(f.file)); 68862306a36Sopenharmony_ci if (ns->ops == &netns_operations) 68962306a36Sopenharmony_ci net = get_net(container_of(ns, struct net, ns)); 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci fdput(f); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci return net; 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(get_net_ns_by_fd); 69662306a36Sopenharmony_ci#endif 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_cistruct net *get_net_ns_by_pid(pid_t pid) 69962306a36Sopenharmony_ci{ 70062306a36Sopenharmony_ci struct task_struct *tsk; 70162306a36Sopenharmony_ci struct net *net; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci /* Lookup the network namespace */ 70462306a36Sopenharmony_ci net = ERR_PTR(-ESRCH); 70562306a36Sopenharmony_ci rcu_read_lock(); 70662306a36Sopenharmony_ci tsk = find_task_by_vpid(pid); 70762306a36Sopenharmony_ci if (tsk) { 70862306a36Sopenharmony_ci struct nsproxy *nsproxy; 70962306a36Sopenharmony_ci task_lock(tsk); 71062306a36Sopenharmony_ci nsproxy = tsk->nsproxy; 71162306a36Sopenharmony_ci if (nsproxy) 71262306a36Sopenharmony_ci net = get_net(nsproxy->net_ns); 71362306a36Sopenharmony_ci task_unlock(tsk); 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci rcu_read_unlock(); 71662306a36Sopenharmony_ci return net; 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(get_net_ns_by_pid); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic __net_init int net_ns_net_init(struct net *net) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci#ifdef CONFIG_NET_NS 72362306a36Sopenharmony_ci net->ns.ops = &netns_operations; 72462306a36Sopenharmony_ci#endif 72562306a36Sopenharmony_ci return ns_alloc_inum(&net->ns); 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_cistatic __net_exit void net_ns_net_exit(struct net *net) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci ns_free_inum(&net->ns); 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistatic struct pernet_operations __net_initdata net_ns_ops = { 73462306a36Sopenharmony_ci .init = net_ns_net_init, 73562306a36Sopenharmony_ci .exit = net_ns_net_exit, 73662306a36Sopenharmony_ci}; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_cistatic const struct nla_policy rtnl_net_policy[NETNSA_MAX + 1] = { 73962306a36Sopenharmony_ci [NETNSA_NONE] = { .type = NLA_UNSPEC }, 74062306a36Sopenharmony_ci [NETNSA_NSID] = { .type = NLA_S32 }, 74162306a36Sopenharmony_ci [NETNSA_PID] = { .type = NLA_U32 }, 74262306a36Sopenharmony_ci [NETNSA_FD] = { .type = NLA_U32 }, 74362306a36Sopenharmony_ci [NETNSA_TARGET_NSID] = { .type = NLA_S32 }, 74462306a36Sopenharmony_ci}; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_cistatic int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh, 74762306a36Sopenharmony_ci struct netlink_ext_ack *extack) 74862306a36Sopenharmony_ci{ 74962306a36Sopenharmony_ci struct net *net = sock_net(skb->sk); 75062306a36Sopenharmony_ci struct nlattr *tb[NETNSA_MAX + 1]; 75162306a36Sopenharmony_ci struct nlattr *nla; 75262306a36Sopenharmony_ci struct net *peer; 75362306a36Sopenharmony_ci int nsid, err; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci err = nlmsg_parse_deprecated(nlh, sizeof(struct rtgenmsg), tb, 75662306a36Sopenharmony_ci NETNSA_MAX, rtnl_net_policy, extack); 75762306a36Sopenharmony_ci if (err < 0) 75862306a36Sopenharmony_ci return err; 75962306a36Sopenharmony_ci if (!tb[NETNSA_NSID]) { 76062306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "nsid is missing"); 76162306a36Sopenharmony_ci return -EINVAL; 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci nsid = nla_get_s32(tb[NETNSA_NSID]); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci if (tb[NETNSA_PID]) { 76662306a36Sopenharmony_ci peer = get_net_ns_by_pid(nla_get_u32(tb[NETNSA_PID])); 76762306a36Sopenharmony_ci nla = tb[NETNSA_PID]; 76862306a36Sopenharmony_ci } else if (tb[NETNSA_FD]) { 76962306a36Sopenharmony_ci peer = get_net_ns_by_fd(nla_get_u32(tb[NETNSA_FD])); 77062306a36Sopenharmony_ci nla = tb[NETNSA_FD]; 77162306a36Sopenharmony_ci } else { 77262306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "Peer netns reference is missing"); 77362306a36Sopenharmony_ci return -EINVAL; 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci if (IS_ERR(peer)) { 77662306a36Sopenharmony_ci NL_SET_BAD_ATTR(extack, nla); 77762306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "Peer netns reference is invalid"); 77862306a36Sopenharmony_ci return PTR_ERR(peer); 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci spin_lock_bh(&net->nsid_lock); 78262306a36Sopenharmony_ci if (__peernet2id(net, peer) >= 0) { 78362306a36Sopenharmony_ci spin_unlock_bh(&net->nsid_lock); 78462306a36Sopenharmony_ci err = -EEXIST; 78562306a36Sopenharmony_ci NL_SET_BAD_ATTR(extack, nla); 78662306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, 78762306a36Sopenharmony_ci "Peer netns already has a nsid assigned"); 78862306a36Sopenharmony_ci goto out; 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci err = alloc_netid(net, peer, nsid); 79262306a36Sopenharmony_ci spin_unlock_bh(&net->nsid_lock); 79362306a36Sopenharmony_ci if (err >= 0) { 79462306a36Sopenharmony_ci rtnl_net_notifyid(net, RTM_NEWNSID, err, NETLINK_CB(skb).portid, 79562306a36Sopenharmony_ci nlh, GFP_KERNEL); 79662306a36Sopenharmony_ci err = 0; 79762306a36Sopenharmony_ci } else if (err == -ENOSPC && nsid >= 0) { 79862306a36Sopenharmony_ci err = -EEXIST; 79962306a36Sopenharmony_ci NL_SET_BAD_ATTR(extack, tb[NETNSA_NSID]); 80062306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "The specified nsid is already used"); 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ciout: 80362306a36Sopenharmony_ci put_net(peer); 80462306a36Sopenharmony_ci return err; 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_cistatic int rtnl_net_get_size(void) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci return NLMSG_ALIGN(sizeof(struct rtgenmsg)) 81062306a36Sopenharmony_ci + nla_total_size(sizeof(s32)) /* NETNSA_NSID */ 81162306a36Sopenharmony_ci + nla_total_size(sizeof(s32)) /* NETNSA_CURRENT_NSID */ 81262306a36Sopenharmony_ci ; 81362306a36Sopenharmony_ci} 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_cistruct net_fill_args { 81662306a36Sopenharmony_ci u32 portid; 81762306a36Sopenharmony_ci u32 seq; 81862306a36Sopenharmony_ci int flags; 81962306a36Sopenharmony_ci int cmd; 82062306a36Sopenharmony_ci int nsid; 82162306a36Sopenharmony_ci bool add_ref; 82262306a36Sopenharmony_ci int ref_nsid; 82362306a36Sopenharmony_ci}; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_cistatic int rtnl_net_fill(struct sk_buff *skb, struct net_fill_args *args) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci struct nlmsghdr *nlh; 82862306a36Sopenharmony_ci struct rtgenmsg *rth; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci nlh = nlmsg_put(skb, args->portid, args->seq, args->cmd, sizeof(*rth), 83162306a36Sopenharmony_ci args->flags); 83262306a36Sopenharmony_ci if (!nlh) 83362306a36Sopenharmony_ci return -EMSGSIZE; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci rth = nlmsg_data(nlh); 83662306a36Sopenharmony_ci rth->rtgen_family = AF_UNSPEC; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci if (nla_put_s32(skb, NETNSA_NSID, args->nsid)) 83962306a36Sopenharmony_ci goto nla_put_failure; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci if (args->add_ref && 84262306a36Sopenharmony_ci nla_put_s32(skb, NETNSA_CURRENT_NSID, args->ref_nsid)) 84362306a36Sopenharmony_ci goto nla_put_failure; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci nlmsg_end(skb, nlh); 84662306a36Sopenharmony_ci return 0; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_cinla_put_failure: 84962306a36Sopenharmony_ci nlmsg_cancel(skb, nlh); 85062306a36Sopenharmony_ci return -EMSGSIZE; 85162306a36Sopenharmony_ci} 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_cistatic int rtnl_net_valid_getid_req(struct sk_buff *skb, 85462306a36Sopenharmony_ci const struct nlmsghdr *nlh, 85562306a36Sopenharmony_ci struct nlattr **tb, 85662306a36Sopenharmony_ci struct netlink_ext_ack *extack) 85762306a36Sopenharmony_ci{ 85862306a36Sopenharmony_ci int i, err; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci if (!netlink_strict_get_check(skb)) 86162306a36Sopenharmony_ci return nlmsg_parse_deprecated(nlh, sizeof(struct rtgenmsg), 86262306a36Sopenharmony_ci tb, NETNSA_MAX, rtnl_net_policy, 86362306a36Sopenharmony_ci extack); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct rtgenmsg), tb, 86662306a36Sopenharmony_ci NETNSA_MAX, rtnl_net_policy, 86762306a36Sopenharmony_ci extack); 86862306a36Sopenharmony_ci if (err) 86962306a36Sopenharmony_ci return err; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci for (i = 0; i <= NETNSA_MAX; i++) { 87262306a36Sopenharmony_ci if (!tb[i]) 87362306a36Sopenharmony_ci continue; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci switch (i) { 87662306a36Sopenharmony_ci case NETNSA_PID: 87762306a36Sopenharmony_ci case NETNSA_FD: 87862306a36Sopenharmony_ci case NETNSA_NSID: 87962306a36Sopenharmony_ci case NETNSA_TARGET_NSID: 88062306a36Sopenharmony_ci break; 88162306a36Sopenharmony_ci default: 88262306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "Unsupported attribute in peer netns getid request"); 88362306a36Sopenharmony_ci return -EINVAL; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci } 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci return 0; 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_cistatic int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh, 89162306a36Sopenharmony_ci struct netlink_ext_ack *extack) 89262306a36Sopenharmony_ci{ 89362306a36Sopenharmony_ci struct net *net = sock_net(skb->sk); 89462306a36Sopenharmony_ci struct nlattr *tb[NETNSA_MAX + 1]; 89562306a36Sopenharmony_ci struct net_fill_args fillargs = { 89662306a36Sopenharmony_ci .portid = NETLINK_CB(skb).portid, 89762306a36Sopenharmony_ci .seq = nlh->nlmsg_seq, 89862306a36Sopenharmony_ci .cmd = RTM_NEWNSID, 89962306a36Sopenharmony_ci }; 90062306a36Sopenharmony_ci struct net *peer, *target = net; 90162306a36Sopenharmony_ci struct nlattr *nla; 90262306a36Sopenharmony_ci struct sk_buff *msg; 90362306a36Sopenharmony_ci int err; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci err = rtnl_net_valid_getid_req(skb, nlh, tb, extack); 90662306a36Sopenharmony_ci if (err < 0) 90762306a36Sopenharmony_ci return err; 90862306a36Sopenharmony_ci if (tb[NETNSA_PID]) { 90962306a36Sopenharmony_ci peer = get_net_ns_by_pid(nla_get_u32(tb[NETNSA_PID])); 91062306a36Sopenharmony_ci nla = tb[NETNSA_PID]; 91162306a36Sopenharmony_ci } else if (tb[NETNSA_FD]) { 91262306a36Sopenharmony_ci peer = get_net_ns_by_fd(nla_get_u32(tb[NETNSA_FD])); 91362306a36Sopenharmony_ci nla = tb[NETNSA_FD]; 91462306a36Sopenharmony_ci } else if (tb[NETNSA_NSID]) { 91562306a36Sopenharmony_ci peer = get_net_ns_by_id(net, nla_get_s32(tb[NETNSA_NSID])); 91662306a36Sopenharmony_ci if (!peer) 91762306a36Sopenharmony_ci peer = ERR_PTR(-ENOENT); 91862306a36Sopenharmony_ci nla = tb[NETNSA_NSID]; 91962306a36Sopenharmony_ci } else { 92062306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "Peer netns reference is missing"); 92162306a36Sopenharmony_ci return -EINVAL; 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci if (IS_ERR(peer)) { 92562306a36Sopenharmony_ci NL_SET_BAD_ATTR(extack, nla); 92662306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "Peer netns reference is invalid"); 92762306a36Sopenharmony_ci return PTR_ERR(peer); 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci if (tb[NETNSA_TARGET_NSID]) { 93162306a36Sopenharmony_ci int id = nla_get_s32(tb[NETNSA_TARGET_NSID]); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci target = rtnl_get_net_ns_capable(NETLINK_CB(skb).sk, id); 93462306a36Sopenharmony_ci if (IS_ERR(target)) { 93562306a36Sopenharmony_ci NL_SET_BAD_ATTR(extack, tb[NETNSA_TARGET_NSID]); 93662306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, 93762306a36Sopenharmony_ci "Target netns reference is invalid"); 93862306a36Sopenharmony_ci err = PTR_ERR(target); 93962306a36Sopenharmony_ci goto out; 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci fillargs.add_ref = true; 94262306a36Sopenharmony_ci fillargs.ref_nsid = peernet2id(net, peer); 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci msg = nlmsg_new(rtnl_net_get_size(), GFP_KERNEL); 94662306a36Sopenharmony_ci if (!msg) { 94762306a36Sopenharmony_ci err = -ENOMEM; 94862306a36Sopenharmony_ci goto out; 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci fillargs.nsid = peernet2id(target, peer); 95262306a36Sopenharmony_ci err = rtnl_net_fill(msg, &fillargs); 95362306a36Sopenharmony_ci if (err < 0) 95462306a36Sopenharmony_ci goto err_out; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci err = rtnl_unicast(msg, net, NETLINK_CB(skb).portid); 95762306a36Sopenharmony_ci goto out; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_cierr_out: 96062306a36Sopenharmony_ci nlmsg_free(msg); 96162306a36Sopenharmony_ciout: 96262306a36Sopenharmony_ci if (fillargs.add_ref) 96362306a36Sopenharmony_ci put_net(target); 96462306a36Sopenharmony_ci put_net(peer); 96562306a36Sopenharmony_ci return err; 96662306a36Sopenharmony_ci} 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_cistruct rtnl_net_dump_cb { 96962306a36Sopenharmony_ci struct net *tgt_net; 97062306a36Sopenharmony_ci struct net *ref_net; 97162306a36Sopenharmony_ci struct sk_buff *skb; 97262306a36Sopenharmony_ci struct net_fill_args fillargs; 97362306a36Sopenharmony_ci int idx; 97462306a36Sopenharmony_ci int s_idx; 97562306a36Sopenharmony_ci}; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci/* Runs in RCU-critical section. */ 97862306a36Sopenharmony_cistatic int rtnl_net_dumpid_one(int id, void *peer, void *data) 97962306a36Sopenharmony_ci{ 98062306a36Sopenharmony_ci struct rtnl_net_dump_cb *net_cb = (struct rtnl_net_dump_cb *)data; 98162306a36Sopenharmony_ci int ret; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci if (net_cb->idx < net_cb->s_idx) 98462306a36Sopenharmony_ci goto cont; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci net_cb->fillargs.nsid = id; 98762306a36Sopenharmony_ci if (net_cb->fillargs.add_ref) 98862306a36Sopenharmony_ci net_cb->fillargs.ref_nsid = __peernet2id(net_cb->ref_net, peer); 98962306a36Sopenharmony_ci ret = rtnl_net_fill(net_cb->skb, &net_cb->fillargs); 99062306a36Sopenharmony_ci if (ret < 0) 99162306a36Sopenharmony_ci return ret; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_cicont: 99462306a36Sopenharmony_ci net_cb->idx++; 99562306a36Sopenharmony_ci return 0; 99662306a36Sopenharmony_ci} 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_cistatic int rtnl_valid_dump_net_req(const struct nlmsghdr *nlh, struct sock *sk, 99962306a36Sopenharmony_ci struct rtnl_net_dump_cb *net_cb, 100062306a36Sopenharmony_ci struct netlink_callback *cb) 100162306a36Sopenharmony_ci{ 100262306a36Sopenharmony_ci struct netlink_ext_ack *extack = cb->extack; 100362306a36Sopenharmony_ci struct nlattr *tb[NETNSA_MAX + 1]; 100462306a36Sopenharmony_ci int err, i; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct rtgenmsg), tb, 100762306a36Sopenharmony_ci NETNSA_MAX, rtnl_net_policy, 100862306a36Sopenharmony_ci extack); 100962306a36Sopenharmony_ci if (err < 0) 101062306a36Sopenharmony_ci return err; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci for (i = 0; i <= NETNSA_MAX; i++) { 101362306a36Sopenharmony_ci if (!tb[i]) 101462306a36Sopenharmony_ci continue; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci if (i == NETNSA_TARGET_NSID) { 101762306a36Sopenharmony_ci struct net *net; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci net = rtnl_get_net_ns_capable(sk, nla_get_s32(tb[i])); 102062306a36Sopenharmony_ci if (IS_ERR(net)) { 102162306a36Sopenharmony_ci NL_SET_BAD_ATTR(extack, tb[i]); 102262306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, 102362306a36Sopenharmony_ci "Invalid target network namespace id"); 102462306a36Sopenharmony_ci return PTR_ERR(net); 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci net_cb->fillargs.add_ref = true; 102762306a36Sopenharmony_ci net_cb->ref_net = net_cb->tgt_net; 102862306a36Sopenharmony_ci net_cb->tgt_net = net; 102962306a36Sopenharmony_ci } else { 103062306a36Sopenharmony_ci NL_SET_BAD_ATTR(extack, tb[i]); 103162306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, 103262306a36Sopenharmony_ci "Unsupported attribute in dump request"); 103362306a36Sopenharmony_ci return -EINVAL; 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci } 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci return 0; 103862306a36Sopenharmony_ci} 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_cistatic int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb) 104162306a36Sopenharmony_ci{ 104262306a36Sopenharmony_ci struct rtnl_net_dump_cb net_cb = { 104362306a36Sopenharmony_ci .tgt_net = sock_net(skb->sk), 104462306a36Sopenharmony_ci .skb = skb, 104562306a36Sopenharmony_ci .fillargs = { 104662306a36Sopenharmony_ci .portid = NETLINK_CB(cb->skb).portid, 104762306a36Sopenharmony_ci .seq = cb->nlh->nlmsg_seq, 104862306a36Sopenharmony_ci .flags = NLM_F_MULTI, 104962306a36Sopenharmony_ci .cmd = RTM_NEWNSID, 105062306a36Sopenharmony_ci }, 105162306a36Sopenharmony_ci .idx = 0, 105262306a36Sopenharmony_ci .s_idx = cb->args[0], 105362306a36Sopenharmony_ci }; 105462306a36Sopenharmony_ci int err = 0; 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci if (cb->strict_check) { 105762306a36Sopenharmony_ci err = rtnl_valid_dump_net_req(cb->nlh, skb->sk, &net_cb, cb); 105862306a36Sopenharmony_ci if (err < 0) 105962306a36Sopenharmony_ci goto end; 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci rcu_read_lock(); 106362306a36Sopenharmony_ci idr_for_each(&net_cb.tgt_net->netns_ids, rtnl_net_dumpid_one, &net_cb); 106462306a36Sopenharmony_ci rcu_read_unlock(); 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci cb->args[0] = net_cb.idx; 106762306a36Sopenharmony_ciend: 106862306a36Sopenharmony_ci if (net_cb.fillargs.add_ref) 106962306a36Sopenharmony_ci put_net(net_cb.tgt_net); 107062306a36Sopenharmony_ci return err < 0 ? err : skb->len; 107162306a36Sopenharmony_ci} 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_cistatic void rtnl_net_notifyid(struct net *net, int cmd, int id, u32 portid, 107462306a36Sopenharmony_ci struct nlmsghdr *nlh, gfp_t gfp) 107562306a36Sopenharmony_ci{ 107662306a36Sopenharmony_ci struct net_fill_args fillargs = { 107762306a36Sopenharmony_ci .portid = portid, 107862306a36Sopenharmony_ci .seq = nlh ? nlh->nlmsg_seq : 0, 107962306a36Sopenharmony_ci .cmd = cmd, 108062306a36Sopenharmony_ci .nsid = id, 108162306a36Sopenharmony_ci }; 108262306a36Sopenharmony_ci struct sk_buff *msg; 108362306a36Sopenharmony_ci int err = -ENOMEM; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci msg = nlmsg_new(rtnl_net_get_size(), gfp); 108662306a36Sopenharmony_ci if (!msg) 108762306a36Sopenharmony_ci goto out; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci err = rtnl_net_fill(msg, &fillargs); 109062306a36Sopenharmony_ci if (err < 0) 109162306a36Sopenharmony_ci goto err_out; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci rtnl_notify(msg, net, portid, RTNLGRP_NSID, nlh, gfp); 109462306a36Sopenharmony_ci return; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_cierr_out: 109762306a36Sopenharmony_ci nlmsg_free(msg); 109862306a36Sopenharmony_ciout: 109962306a36Sopenharmony_ci rtnl_set_sk_err(net, RTNLGRP_NSID, err); 110062306a36Sopenharmony_ci} 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_civoid __init net_ns_init(void) 110362306a36Sopenharmony_ci{ 110462306a36Sopenharmony_ci struct net_generic *ng; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci#ifdef CONFIG_NET_NS 110762306a36Sopenharmony_ci net_cachep = kmem_cache_create("net_namespace", sizeof(struct net), 110862306a36Sopenharmony_ci SMP_CACHE_BYTES, 110962306a36Sopenharmony_ci SLAB_PANIC|SLAB_ACCOUNT, NULL); 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci /* Create workqueue for cleanup */ 111262306a36Sopenharmony_ci netns_wq = create_singlethread_workqueue("netns"); 111362306a36Sopenharmony_ci if (!netns_wq) 111462306a36Sopenharmony_ci panic("Could not create netns workq"); 111562306a36Sopenharmony_ci#endif 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci ng = net_alloc_generic(); 111862306a36Sopenharmony_ci if (!ng) 111962306a36Sopenharmony_ci panic("Could not allocate generic netns"); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci rcu_assign_pointer(init_net.gen, ng); 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci#ifdef CONFIG_KEYS 112462306a36Sopenharmony_ci init_net.key_domain = &init_net_key_domain; 112562306a36Sopenharmony_ci#endif 112662306a36Sopenharmony_ci down_write(&pernet_ops_rwsem); 112762306a36Sopenharmony_ci preinit_net(&init_net); 112862306a36Sopenharmony_ci if (setup_net(&init_net, &init_user_ns)) 112962306a36Sopenharmony_ci panic("Could not setup the initial network namespace"); 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci init_net_initialized = true; 113262306a36Sopenharmony_ci up_write(&pernet_ops_rwsem); 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci if (register_pernet_subsys(&net_ns_ops)) 113562306a36Sopenharmony_ci panic("Could not register network namespace subsystems"); 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci rtnl_register(PF_UNSPEC, RTM_NEWNSID, rtnl_net_newid, NULL, 113862306a36Sopenharmony_ci RTNL_FLAG_DOIT_UNLOCKED); 113962306a36Sopenharmony_ci rtnl_register(PF_UNSPEC, RTM_GETNSID, rtnl_net_getid, rtnl_net_dumpid, 114062306a36Sopenharmony_ci RTNL_FLAG_DOIT_UNLOCKED); 114162306a36Sopenharmony_ci} 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_cistatic void free_exit_list(struct pernet_operations *ops, struct list_head *net_exit_list) 114462306a36Sopenharmony_ci{ 114562306a36Sopenharmony_ci ops_pre_exit_list(ops, net_exit_list); 114662306a36Sopenharmony_ci synchronize_rcu(); 114762306a36Sopenharmony_ci ops_exit_list(ops, net_exit_list); 114862306a36Sopenharmony_ci ops_free_list(ops, net_exit_list); 114962306a36Sopenharmony_ci} 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci#ifdef CONFIG_NET_NS 115262306a36Sopenharmony_cistatic int __register_pernet_operations(struct list_head *list, 115362306a36Sopenharmony_ci struct pernet_operations *ops) 115462306a36Sopenharmony_ci{ 115562306a36Sopenharmony_ci struct net *net; 115662306a36Sopenharmony_ci int error; 115762306a36Sopenharmony_ci LIST_HEAD(net_exit_list); 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci list_add_tail(&ops->list, list); 116062306a36Sopenharmony_ci if (ops->init || (ops->id && ops->size)) { 116162306a36Sopenharmony_ci /* We held write locked pernet_ops_rwsem, and parallel 116262306a36Sopenharmony_ci * setup_net() and cleanup_net() are not possible. 116362306a36Sopenharmony_ci */ 116462306a36Sopenharmony_ci for_each_net(net) { 116562306a36Sopenharmony_ci error = ops_init(ops, net); 116662306a36Sopenharmony_ci if (error) 116762306a36Sopenharmony_ci goto out_undo; 116862306a36Sopenharmony_ci list_add_tail(&net->exit_list, &net_exit_list); 116962306a36Sopenharmony_ci } 117062306a36Sopenharmony_ci } 117162306a36Sopenharmony_ci return 0; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ciout_undo: 117462306a36Sopenharmony_ci /* If I have an error cleanup all namespaces I initialized */ 117562306a36Sopenharmony_ci list_del(&ops->list); 117662306a36Sopenharmony_ci free_exit_list(ops, &net_exit_list); 117762306a36Sopenharmony_ci return error; 117862306a36Sopenharmony_ci} 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_cistatic void __unregister_pernet_operations(struct pernet_operations *ops) 118162306a36Sopenharmony_ci{ 118262306a36Sopenharmony_ci struct net *net; 118362306a36Sopenharmony_ci LIST_HEAD(net_exit_list); 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci list_del(&ops->list); 118662306a36Sopenharmony_ci /* See comment in __register_pernet_operations() */ 118762306a36Sopenharmony_ci for_each_net(net) 118862306a36Sopenharmony_ci list_add_tail(&net->exit_list, &net_exit_list); 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci free_exit_list(ops, &net_exit_list); 119162306a36Sopenharmony_ci} 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci#else 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_cistatic int __register_pernet_operations(struct list_head *list, 119662306a36Sopenharmony_ci struct pernet_operations *ops) 119762306a36Sopenharmony_ci{ 119862306a36Sopenharmony_ci if (!init_net_initialized) { 119962306a36Sopenharmony_ci list_add_tail(&ops->list, list); 120062306a36Sopenharmony_ci return 0; 120162306a36Sopenharmony_ci } 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci return ops_init(ops, &init_net); 120462306a36Sopenharmony_ci} 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_cistatic void __unregister_pernet_operations(struct pernet_operations *ops) 120762306a36Sopenharmony_ci{ 120862306a36Sopenharmony_ci if (!init_net_initialized) { 120962306a36Sopenharmony_ci list_del(&ops->list); 121062306a36Sopenharmony_ci } else { 121162306a36Sopenharmony_ci LIST_HEAD(net_exit_list); 121262306a36Sopenharmony_ci list_add(&init_net.exit_list, &net_exit_list); 121362306a36Sopenharmony_ci free_exit_list(ops, &net_exit_list); 121462306a36Sopenharmony_ci } 121562306a36Sopenharmony_ci} 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci#endif /* CONFIG_NET_NS */ 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_cistatic DEFINE_IDA(net_generic_ids); 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_cistatic int register_pernet_operations(struct list_head *list, 122262306a36Sopenharmony_ci struct pernet_operations *ops) 122362306a36Sopenharmony_ci{ 122462306a36Sopenharmony_ci int error; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci if (ops->id) { 122762306a36Sopenharmony_ci error = ida_alloc_min(&net_generic_ids, MIN_PERNET_OPS_ID, 122862306a36Sopenharmony_ci GFP_KERNEL); 122962306a36Sopenharmony_ci if (error < 0) 123062306a36Sopenharmony_ci return error; 123162306a36Sopenharmony_ci *ops->id = error; 123262306a36Sopenharmony_ci max_gen_ptrs = max(max_gen_ptrs, *ops->id + 1); 123362306a36Sopenharmony_ci } 123462306a36Sopenharmony_ci error = __register_pernet_operations(list, ops); 123562306a36Sopenharmony_ci if (error) { 123662306a36Sopenharmony_ci rcu_barrier(); 123762306a36Sopenharmony_ci if (ops->id) 123862306a36Sopenharmony_ci ida_free(&net_generic_ids, *ops->id); 123962306a36Sopenharmony_ci } 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci return error; 124262306a36Sopenharmony_ci} 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_cistatic void unregister_pernet_operations(struct pernet_operations *ops) 124562306a36Sopenharmony_ci{ 124662306a36Sopenharmony_ci __unregister_pernet_operations(ops); 124762306a36Sopenharmony_ci rcu_barrier(); 124862306a36Sopenharmony_ci if (ops->id) 124962306a36Sopenharmony_ci ida_free(&net_generic_ids, *ops->id); 125062306a36Sopenharmony_ci} 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci/** 125362306a36Sopenharmony_ci * register_pernet_subsys - register a network namespace subsystem 125462306a36Sopenharmony_ci * @ops: pernet operations structure for the subsystem 125562306a36Sopenharmony_ci * 125662306a36Sopenharmony_ci * Register a subsystem which has init and exit functions 125762306a36Sopenharmony_ci * that are called when network namespaces are created and 125862306a36Sopenharmony_ci * destroyed respectively. 125962306a36Sopenharmony_ci * 126062306a36Sopenharmony_ci * When registered all network namespace init functions are 126162306a36Sopenharmony_ci * called for every existing network namespace. Allowing kernel 126262306a36Sopenharmony_ci * modules to have a race free view of the set of network namespaces. 126362306a36Sopenharmony_ci * 126462306a36Sopenharmony_ci * When a new network namespace is created all of the init 126562306a36Sopenharmony_ci * methods are called in the order in which they were registered. 126662306a36Sopenharmony_ci * 126762306a36Sopenharmony_ci * When a network namespace is destroyed all of the exit methods 126862306a36Sopenharmony_ci * are called in the reverse of the order with which they were 126962306a36Sopenharmony_ci * registered. 127062306a36Sopenharmony_ci */ 127162306a36Sopenharmony_ciint register_pernet_subsys(struct pernet_operations *ops) 127262306a36Sopenharmony_ci{ 127362306a36Sopenharmony_ci int error; 127462306a36Sopenharmony_ci down_write(&pernet_ops_rwsem); 127562306a36Sopenharmony_ci error = register_pernet_operations(first_device, ops); 127662306a36Sopenharmony_ci up_write(&pernet_ops_rwsem); 127762306a36Sopenharmony_ci return error; 127862306a36Sopenharmony_ci} 127962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(register_pernet_subsys); 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci/** 128262306a36Sopenharmony_ci * unregister_pernet_subsys - unregister a network namespace subsystem 128362306a36Sopenharmony_ci * @ops: pernet operations structure to manipulate 128462306a36Sopenharmony_ci * 128562306a36Sopenharmony_ci * Remove the pernet operations structure from the list to be 128662306a36Sopenharmony_ci * used when network namespaces are created or destroyed. In 128762306a36Sopenharmony_ci * addition run the exit method for all existing network 128862306a36Sopenharmony_ci * namespaces. 128962306a36Sopenharmony_ci */ 129062306a36Sopenharmony_civoid unregister_pernet_subsys(struct pernet_operations *ops) 129162306a36Sopenharmony_ci{ 129262306a36Sopenharmony_ci down_write(&pernet_ops_rwsem); 129362306a36Sopenharmony_ci unregister_pernet_operations(ops); 129462306a36Sopenharmony_ci up_write(&pernet_ops_rwsem); 129562306a36Sopenharmony_ci} 129662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(unregister_pernet_subsys); 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci/** 129962306a36Sopenharmony_ci * register_pernet_device - register a network namespace device 130062306a36Sopenharmony_ci * @ops: pernet operations structure for the subsystem 130162306a36Sopenharmony_ci * 130262306a36Sopenharmony_ci * Register a device which has init and exit functions 130362306a36Sopenharmony_ci * that are called when network namespaces are created and 130462306a36Sopenharmony_ci * destroyed respectively. 130562306a36Sopenharmony_ci * 130662306a36Sopenharmony_ci * When registered all network namespace init functions are 130762306a36Sopenharmony_ci * called for every existing network namespace. Allowing kernel 130862306a36Sopenharmony_ci * modules to have a race free view of the set of network namespaces. 130962306a36Sopenharmony_ci * 131062306a36Sopenharmony_ci * When a new network namespace is created all of the init 131162306a36Sopenharmony_ci * methods are called in the order in which they were registered. 131262306a36Sopenharmony_ci * 131362306a36Sopenharmony_ci * When a network namespace is destroyed all of the exit methods 131462306a36Sopenharmony_ci * are called in the reverse of the order with which they were 131562306a36Sopenharmony_ci * registered. 131662306a36Sopenharmony_ci */ 131762306a36Sopenharmony_ciint register_pernet_device(struct pernet_operations *ops) 131862306a36Sopenharmony_ci{ 131962306a36Sopenharmony_ci int error; 132062306a36Sopenharmony_ci down_write(&pernet_ops_rwsem); 132162306a36Sopenharmony_ci error = register_pernet_operations(&pernet_list, ops); 132262306a36Sopenharmony_ci if (!error && (first_device == &pernet_list)) 132362306a36Sopenharmony_ci first_device = &ops->list; 132462306a36Sopenharmony_ci up_write(&pernet_ops_rwsem); 132562306a36Sopenharmony_ci return error; 132662306a36Sopenharmony_ci} 132762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(register_pernet_device); 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci/** 133062306a36Sopenharmony_ci * unregister_pernet_device - unregister a network namespace netdevice 133162306a36Sopenharmony_ci * @ops: pernet operations structure to manipulate 133262306a36Sopenharmony_ci * 133362306a36Sopenharmony_ci * Remove the pernet operations structure from the list to be 133462306a36Sopenharmony_ci * used when network namespaces are created or destroyed. In 133562306a36Sopenharmony_ci * addition run the exit method for all existing network 133662306a36Sopenharmony_ci * namespaces. 133762306a36Sopenharmony_ci */ 133862306a36Sopenharmony_civoid unregister_pernet_device(struct pernet_operations *ops) 133962306a36Sopenharmony_ci{ 134062306a36Sopenharmony_ci down_write(&pernet_ops_rwsem); 134162306a36Sopenharmony_ci if (&ops->list == first_device) 134262306a36Sopenharmony_ci first_device = first_device->next; 134362306a36Sopenharmony_ci unregister_pernet_operations(ops); 134462306a36Sopenharmony_ci up_write(&pernet_ops_rwsem); 134562306a36Sopenharmony_ci} 134662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(unregister_pernet_device); 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci#ifdef CONFIG_NET_NS 134962306a36Sopenharmony_cistatic struct ns_common *netns_get(struct task_struct *task) 135062306a36Sopenharmony_ci{ 135162306a36Sopenharmony_ci struct net *net = NULL; 135262306a36Sopenharmony_ci struct nsproxy *nsproxy; 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci task_lock(task); 135562306a36Sopenharmony_ci nsproxy = task->nsproxy; 135662306a36Sopenharmony_ci if (nsproxy) 135762306a36Sopenharmony_ci net = get_net(nsproxy->net_ns); 135862306a36Sopenharmony_ci task_unlock(task); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci return net ? &net->ns : NULL; 136162306a36Sopenharmony_ci} 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_cistatic inline struct net *to_net_ns(struct ns_common *ns) 136462306a36Sopenharmony_ci{ 136562306a36Sopenharmony_ci return container_of(ns, struct net, ns); 136662306a36Sopenharmony_ci} 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_cistatic void netns_put(struct ns_common *ns) 136962306a36Sopenharmony_ci{ 137062306a36Sopenharmony_ci put_net(to_net_ns(ns)); 137162306a36Sopenharmony_ci} 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_cistatic int netns_install(struct nsset *nsset, struct ns_common *ns) 137462306a36Sopenharmony_ci{ 137562306a36Sopenharmony_ci struct nsproxy *nsproxy = nsset->nsproxy; 137662306a36Sopenharmony_ci struct net *net = to_net_ns(ns); 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci if (!ns_capable(net->user_ns, CAP_SYS_ADMIN) || 137962306a36Sopenharmony_ci !ns_capable(nsset->cred->user_ns, CAP_SYS_ADMIN)) 138062306a36Sopenharmony_ci return -EPERM; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci put_net(nsproxy->net_ns); 138362306a36Sopenharmony_ci nsproxy->net_ns = get_net(net); 138462306a36Sopenharmony_ci return 0; 138562306a36Sopenharmony_ci} 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_cistatic struct user_namespace *netns_owner(struct ns_common *ns) 138862306a36Sopenharmony_ci{ 138962306a36Sopenharmony_ci return to_net_ns(ns)->user_ns; 139062306a36Sopenharmony_ci} 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ciconst struct proc_ns_operations netns_operations = { 139362306a36Sopenharmony_ci .name = "net", 139462306a36Sopenharmony_ci .type = CLONE_NEWNET, 139562306a36Sopenharmony_ci .get = netns_get, 139662306a36Sopenharmony_ci .put = netns_put, 139762306a36Sopenharmony_ci .install = netns_install, 139862306a36Sopenharmony_ci .owner = netns_owner, 139962306a36Sopenharmony_ci}; 140062306a36Sopenharmony_ci#endif 1401