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