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