1560 lines · 37.5 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/workqueue.h>#include <linux/rtnetlink.h>#include <linux/cache.h>#include <linux/slab.h>#include <linux/list.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/idr.h>#include <linux/rculist.h>#include <linux/nsproxy.h>#include <linux/fs.h>#include <linux/proc_ns.h>#include <linux/file.h>#include <linux/export.h>#include <linux/user_namespace.h>#include <linux/net_namespace.h>#include <linux/sched/task.h>#include <linux/uidgid.h>#include <linux/proc_fs.h>#include <linux/nstree.h> #include <net/aligned_data.h>#include <net/sock.h>#include <net/netlink.h>#include <net/net_namespace.h>#include <net/netns/generic.h> /* *	Our network namespace constructor/destructor lists */ static LIST_HEAD(pernet_list);static struct list_head *first_device = &pernet_list; LIST_HEAD(net_namespace_list);EXPORT_SYMBOL_GPL(net_namespace_list); /* Protects net_namespace_list. Nests iside rtnl_lock() */DECLARE_RWSEM(net_rwsem);EXPORT_SYMBOL_GPL(net_rwsem); #ifdef CONFIG_KEYSstatic struct key_tag init_net_key_domain = { .usage = REFCOUNT_INIT(1) };#endif struct net init_net;EXPORT_SYMBOL(init_net); static bool init_net_initialized;/* * pernet_ops_rwsem: protects: pernet_list, net_generic_ids, * init_net_initialized and first_device pointer. * This is internal net namespace object. Please, don't use it * outside. */DECLARE_RWSEM(pernet_ops_rwsem); #define MIN_PERNET_OPS_ID	\	((sizeof(struct net_generic) + sizeof(void *) - 1) / sizeof(void *)) #define INITIAL_NET_GEN_PTRS	13 /* +1 for len +2 for rcu_head */ static unsigned int max_gen_ptrs = INITIAL_NET_GEN_PTRS; static struct net_generic *net_alloc_generic(void){	unsigned int gen_ptrs = READ_ONCE(max_gen_ptrs);	unsigned int generic_size;	struct net_generic *ng; 	generic_size = offsetof(struct net_generic, ptr[gen_ptrs]); 	ng = kzalloc(generic_size, GFP_KERNEL);	if (ng)		ng->s.len = gen_ptrs; 	return ng;} static int net_assign_generic(struct net *net, unsigned int id, void *data){	struct net_generic *ng, *old_ng; 	BUG_ON(id < MIN_PERNET_OPS_ID); 	old_ng = rcu_dereference_protected(net->gen,					   lockdep_is_held(&pernet_ops_rwsem));	if (old_ng->s.len > id) {		old_ng->ptr[id] = data;		return 0;	} 	ng = net_alloc_generic();	if (!ng)		return -ENOMEM; 	/*	 * Some synchronisation notes:	 *	 * The net_generic explores the net->gen array inside rcu	 * read section. Besides once set the net->gen->ptr[x]	 * pointer never changes (see rules in netns/generic.h).	 *	 * That said, we simply duplicate this array and schedule	 * the old copy for kfree after a grace period.	 */ 	memcpy(&ng->ptr[MIN_PERNET_OPS_ID], &old_ng->ptr[MIN_PERNET_OPS_ID],	       (old_ng->s.len - MIN_PERNET_OPS_ID) * sizeof(void *));	ng->ptr[id] = data; 	rcu_assign_pointer(net->gen, ng);	kfree_rcu(old_ng, s.rcu);	return 0;} static int ops_init(const struct pernet_operations *ops, struct net *net){	struct net_generic *ng;	int err = -ENOMEM;	void *data = NULL; 	if (ops->id) {		data = kzalloc(ops->size, GFP_KERNEL);		if (!data)			goto out; 		err = net_assign_generic(net, *ops->id, data);		if (err)			goto cleanup;	}	err = 0;	if (ops->init)		err = ops->init(net);	if (!err)		return 0; 	if (ops->id) {		ng = rcu_dereference_protected(net->gen,					       lockdep_is_held(&pernet_ops_rwsem));		ng->ptr[*ops->id] = NULL;	} cleanup:	kfree(data); out:	return err;} static void ops_pre_exit_list(const struct pernet_operations *ops,			      struct list_head *net_exit_list){	struct net *net; 	if (ops->pre_exit) {		list_for_each_entry(net, net_exit_list, exit_list)			ops->pre_exit(net);	}} static void ops_exit_rtnl_list(const struct list_head *ops_list,			       const struct pernet_operations *ops,			       struct list_head *net_exit_list){	const struct pernet_operations *saved_ops = ops;	LIST_HEAD(dev_kill_list);	struct net *net; 	rtnl_lock(); 	list_for_each_entry(net, net_exit_list, exit_list) {		__rtnl_net_lock(net); 		ops = saved_ops;		list_for_each_entry_continue_reverse(ops, ops_list, list) {			if (ops->exit_rtnl)				ops->exit_rtnl(net, &dev_kill_list);		} 		unregister_netdevice_queue_many_net(net, &dev_kill_list);		__rtnl_net_unlock(net);	} 	unregister_netdevice_many(&dev_kill_list); 	rtnl_unlock();} static void ops_exit_list(const struct pernet_operations *ops,			  struct list_head *net_exit_list){	if (ops->exit) {		struct net *net; 		list_for_each_entry(net, net_exit_list, exit_list) {			ops->exit(net);			cond_resched();		}	} 	if (ops->exit_batch)		ops->exit_batch(net_exit_list);} static void ops_free_list(const struct pernet_operations *ops,			  struct list_head *net_exit_list){	struct net *net; 	if (ops->id) {		list_for_each_entry(net, net_exit_list, exit_list)			kfree(net_generic(net, *ops->id));	}} static void ops_undo_list(const struct list_head *ops_list,			  const struct pernet_operations *ops,			  struct list_head *net_exit_list,			  bool expedite_rcu){	const struct pernet_operations *saved_ops;	bool hold_rtnl = false; 	if (!ops)		ops = list_entry(ops_list, typeof(*ops), list); 	saved_ops = ops; 	list_for_each_entry_continue_reverse(ops, ops_list, list) {		hold_rtnl |= !!ops->exit_rtnl;		ops_pre_exit_list(ops, net_exit_list);	} 	/* Another CPU might be rcu-iterating the list, wait for it.	 * This needs to be before calling the exit() notifiers, so the	 * rcu_barrier() after ops_undo_list() isn't sufficient alone.	 * Also the pre_exit() and exit() methods need this barrier.	 */	if (expedite_rcu)		synchronize_rcu_expedited();	else		synchronize_rcu(); 	if (hold_rtnl)		ops_exit_rtnl_list(ops_list, saved_ops, net_exit_list); 	ops = saved_ops;	list_for_each_entry_continue_reverse(ops, ops_list, list)		ops_exit_list(ops, net_exit_list); 	ops = saved_ops;	list_for_each_entry_continue_reverse(ops, ops_list, list)		ops_free_list(ops, net_exit_list);} static void ops_undo_single(struct pernet_operations *ops,			    struct list_head *net_exit_list){	LIST_HEAD(ops_list); 	list_add(&ops->list, &ops_list);	ops_undo_list(&ops_list, NULL, net_exit_list, false);	list_del(&ops->list);} /* should be called with nsid_lock held */static int alloc_netid(struct net *net, struct net *peer, int reqid){	int min = 0, max = 0; 	if (reqid >= 0) {		min = reqid;		max = reqid + 1;	} 	return idr_alloc(&net->netns_ids, peer, min, max, GFP_ATOMIC);} /* This function is used by idr_for_each(). If net is equal to peer, the * function returns the id so that idr_for_each() stops. Because we cannot * returns the id 0 (idr_for_each() will not stop), we return the magic value * NET_ID_ZERO (-1) for it. */#define NET_ID_ZERO -1static int net_eq_idr(int id, void *net, void *peer){	if (net_eq(net, peer))		return id ? : NET_ID_ZERO;	return 0;} /* Must be called from RCU-critical section or with nsid_lock held */static int __peernet2id(const struct net *net, struct net *peer){	int id = idr_for_each(&net->netns_ids, net_eq_idr, peer); 	/* Magic value for id 0. */	if (id == NET_ID_ZERO)		return 0;	if (id > 0)		return id; 	return NETNSA_NSID_NOT_ASSIGNED;} static void rtnl_net_notifyid(struct net *net, int cmd, int id, u32 portid,			      struct nlmsghdr *nlh, gfp_t gfp);/* This function returns the id of a peer netns. If no id is assigned, one will * be allocated and returned. */int peernet2id_alloc(struct net *net, struct net *peer, gfp_t gfp){	int id; 	if (!check_net(net))		return NETNSA_NSID_NOT_ASSIGNED; 	spin_lock(&net->nsid_lock);	id = __peernet2id(net, peer);	if (id >= 0) {		spin_unlock(&net->nsid_lock);		return id;	} 	/* When peer is obtained from RCU lists, we may race with	 * its cleanup. Check whether it's alive, and this guarantees	 * we never hash a peer back to net->netns_ids, after it has	 * just been idr_remove()'d from there in cleanup_net().	 */	if (!maybe_get_net(peer)) {		spin_unlock(&net->nsid_lock);		return NETNSA_NSID_NOT_ASSIGNED;	} 	id = alloc_netid(net, peer, -1);	spin_unlock(&net->nsid_lock); 	put_net(peer);	if (id < 0)		return NETNSA_NSID_NOT_ASSIGNED; 	rtnl_net_notifyid(net, RTM_NEWNSID, id, 0, NULL, gfp); 	return id;}EXPORT_SYMBOL_GPL(peernet2id_alloc); /* This function returns, if assigned, the id of a peer netns. */int peernet2id(const struct net *net, struct net *peer){	int id; 	rcu_read_lock();	id = __peernet2id(net, peer);	rcu_read_unlock(); 	return id;}EXPORT_SYMBOL(peernet2id); /* This function returns true is the peer netns has an id assigned into the * current netns. */bool peernet_has_id(const struct net *net, struct net *peer){	return peernet2id(net, peer) >= 0;} struct net *get_net_ns_by_id(const struct net *net, int id){	struct net *peer; 	if (id < 0)		return NULL; 	rcu_read_lock();	peer = idr_find(&net->netns_ids, id);	if (peer)		peer = maybe_get_net(peer);	rcu_read_unlock(); 	return peer;}EXPORT_SYMBOL_GPL(get_net_ns_by_id); static __net_init void preinit_net_sysctl(struct net *net){	net->core.sysctl_somaxconn = SOMAXCONN;	/* Limits per socket sk_omem_alloc usage.	 * TCP zerocopy regular usage needs 128 KB.	 */	net->core.sysctl_optmem_max = 128 * 1024;	net->core.sysctl_txrehash = SOCK_TXREHASH_ENABLED;	net->core.sysctl_tstamp_allow_data = 1;	net->core.sysctl_txq_reselection = msecs_to_jiffies(1000);} /* init code that must occur even if setup_net() is not called. */static __net_init void preinit_net(struct net *net, struct user_namespace *user_ns){	refcount_set(&net->passive, 1);	ref_tracker_dir_init(&net->refcnt_tracker, 128, "net_refcnt");	ref_tracker_dir_init(&net->notrefcnt_tracker, 128, "net_notrefcnt"); 	net->hash_mix = get_random_u32();	net->dev_base_seq = 1;	net->user_ns = user_ns; 	idr_init(&net->netns_ids);	spin_lock_init(&net->nsid_lock);	mutex_init(&net->ipv4.ra_mutex); #ifdef CONFIG_DEBUG_NET_SMALL_RTNL	mutex_init(&net->rtnl_mutex);	lock_set_cmp_fn(&net->rtnl_mutex, rtnl_net_lock_cmp_fn, NULL);	INIT_WORK(&net->rtnl_work, rtnl_net_work_func);	INIT_LIST_HEAD(&net->dev_unreg_head);	spin_lock_init(&net->dev_unreg_lock);#endif 	INIT_LIST_HEAD(&net->ptype_all);	INIT_LIST_HEAD(&net->ptype_specific);	preinit_net_sysctl(net);} /* * setup_net runs the initializers for the network namespace object. */static __net_init int setup_net(struct net *net){	/* Must be called with pernet_ops_rwsem held */	const struct pernet_operations *ops;	LIST_HEAD(net_exit_list);	int error = 0; 	net->net_cookie = ns_tree_gen_id(net); 	list_for_each_entry(ops, &pernet_list, list) {		error = ops_init(ops, net);		if (error < 0)			goto out_undo;	}	down_write(&net_rwsem);	list_add_tail_rcu(&net->list, &net_namespace_list);	up_write(&net_rwsem);	ns_tree_add_raw(net);out:	return error; out_undo:	/* Walk through the list backwards calling the exit functions	 * for the pernet modules whose init functions did not fail.	 */	list_add(&net->exit_list, &net_exit_list);	ops_undo_list(&pernet_list, ops, &net_exit_list, false);	rcu_barrier();	goto out;} #ifdef CONFIG_NET_NSstatic struct ucounts *inc_net_namespaces(struct user_namespace *ns){	return inc_ucount(ns, current_euid(), UCOUNT_NET_NAMESPACES);} static void dec_net_namespaces(struct ucounts *ucounts){	dec_ucount(ucounts, UCOUNT_NET_NAMESPACES);} static struct kmem_cache *net_cachep __ro_after_init;static struct workqueue_struct *netns_wq; static struct net *net_alloc(void){	struct net *net = NULL;	struct net_generic *ng; 	ng = net_alloc_generic();	if (!ng)		goto out; 	net = kmem_cache_zalloc(net_cachep, GFP_KERNEL);	if (!net)		goto out_free; #ifdef CONFIG_KEYS	net->key_domain = kzalloc_obj(struct key_tag);	if (!net->key_domain)		goto out_free_2;	refcount_set(&net->key_domain->usage, 1);#endif 	rcu_assign_pointer(net->gen, ng);out:	return net;

Lines 1–500 of 1560.