18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  linux/fs/proc/net.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2007
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  Author: Eric Biederman <ebiederm@xmission.com>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci *  proc net directory handling functions
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/errno.h>
158c2ecf20Sopenharmony_ci#include <linux/time.h>
168c2ecf20Sopenharmony_ci#include <linux/proc_fs.h>
178c2ecf20Sopenharmony_ci#include <linux/stat.h>
188c2ecf20Sopenharmony_ci#include <linux/slab.h>
198c2ecf20Sopenharmony_ci#include <linux/init.h>
208c2ecf20Sopenharmony_ci#include <linux/sched.h>
218c2ecf20Sopenharmony_ci#include <linux/sched/task.h>
228c2ecf20Sopenharmony_ci#include <linux/module.h>
238c2ecf20Sopenharmony_ci#include <linux/bitops.h>
248c2ecf20Sopenharmony_ci#include <linux/mount.h>
258c2ecf20Sopenharmony_ci#include <linux/nsproxy.h>
268c2ecf20Sopenharmony_ci#include <linux/uidgid.h>
278c2ecf20Sopenharmony_ci#include <net/net_namespace.h>
288c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include "internal.h"
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic inline struct net *PDE_NET(struct proc_dir_entry *pde)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	return pde->parent->data;
358c2ecf20Sopenharmony_ci}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic struct net *get_proc_net(const struct inode *inode)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	return maybe_get_net(PDE_NET(PDE(inode)));
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic int seq_open_net(struct inode *inode, struct file *file)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	unsigned int state_size = PDE(inode)->state_size;
458c2ecf20Sopenharmony_ci	struct seq_net_private *p;
468c2ecf20Sopenharmony_ci	struct net *net;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	WARN_ON_ONCE(state_size < sizeof(*p));
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	if (file->f_mode & FMODE_WRITE && !PDE(inode)->write)
518c2ecf20Sopenharmony_ci		return -EACCES;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	net = get_proc_net(inode);
548c2ecf20Sopenharmony_ci	if (!net)
558c2ecf20Sopenharmony_ci		return -ENXIO;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	p = __seq_open_private(file, PDE(inode)->seq_ops, state_size);
588c2ecf20Sopenharmony_ci	if (!p) {
598c2ecf20Sopenharmony_ci		put_net(net);
608c2ecf20Sopenharmony_ci		return -ENOMEM;
618c2ecf20Sopenharmony_ci	}
628c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_NS
638c2ecf20Sopenharmony_ci	p->net = net;
648c2ecf20Sopenharmony_ci#endif
658c2ecf20Sopenharmony_ci	return 0;
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic int seq_release_net(struct inode *ino, struct file *f)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	struct seq_file *seq = f->private_data;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	put_net(seq_file_net(seq));
738c2ecf20Sopenharmony_ci	seq_release_private(ino, f);
748c2ecf20Sopenharmony_ci	return 0;
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic const struct proc_ops proc_net_seq_ops = {
788c2ecf20Sopenharmony_ci	.proc_open	= seq_open_net,
798c2ecf20Sopenharmony_ci	.proc_read	= seq_read,
808c2ecf20Sopenharmony_ci	.proc_write	= proc_simple_write,
818c2ecf20Sopenharmony_ci	.proc_lseek	= seq_lseek,
828c2ecf20Sopenharmony_ci	.proc_release	= seq_release_net,
838c2ecf20Sopenharmony_ci};
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ciint bpf_iter_init_seq_net(void *priv_data, struct bpf_iter_aux_info *aux)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_NS
888c2ecf20Sopenharmony_ci	struct seq_net_private *p = priv_data;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	p->net = get_net(current->nsproxy->net_ns);
918c2ecf20Sopenharmony_ci#endif
928c2ecf20Sopenharmony_ci	return 0;
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_civoid bpf_iter_fini_seq_net(void *priv_data)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_NS
988c2ecf20Sopenharmony_ci	struct seq_net_private *p = priv_data;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	put_net(p->net);
1018c2ecf20Sopenharmony_ci#endif
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistruct proc_dir_entry *proc_create_net_data(const char *name, umode_t mode,
1058c2ecf20Sopenharmony_ci		struct proc_dir_entry *parent, const struct seq_operations *ops,
1068c2ecf20Sopenharmony_ci		unsigned int state_size, void *data)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	struct proc_dir_entry *p;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	p = proc_create_reg(name, mode, &parent, data);
1118c2ecf20Sopenharmony_ci	if (!p)
1128c2ecf20Sopenharmony_ci		return NULL;
1138c2ecf20Sopenharmony_ci	pde_force_lookup(p);
1148c2ecf20Sopenharmony_ci	p->proc_ops = &proc_net_seq_ops;
1158c2ecf20Sopenharmony_ci	p->seq_ops = ops;
1168c2ecf20Sopenharmony_ci	p->state_size = state_size;
1178c2ecf20Sopenharmony_ci	return proc_register(parent, p);
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(proc_create_net_data);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci/**
1228c2ecf20Sopenharmony_ci * proc_create_net_data_write - Create a writable net_ns-specific proc file
1238c2ecf20Sopenharmony_ci * @name: The name of the file.
1248c2ecf20Sopenharmony_ci * @mode: The file's access mode.
1258c2ecf20Sopenharmony_ci * @parent: The parent directory in which to create.
1268c2ecf20Sopenharmony_ci * @ops: The seq_file ops with which to read the file.
1278c2ecf20Sopenharmony_ci * @write: The write method which which to 'modify' the file.
1288c2ecf20Sopenharmony_ci * @data: Data for retrieval by PDE_DATA().
1298c2ecf20Sopenharmony_ci *
1308c2ecf20Sopenharmony_ci * Create a network namespaced proc file in the @parent directory with the
1318c2ecf20Sopenharmony_ci * specified @name and @mode that allows reading of a file that displays a
1328c2ecf20Sopenharmony_ci * series of elements and also provides for the file accepting writes that have
1338c2ecf20Sopenharmony_ci * some arbitrary effect.
1348c2ecf20Sopenharmony_ci *
1358c2ecf20Sopenharmony_ci * The functions in the @ops table are used to iterate over items to be
1368c2ecf20Sopenharmony_ci * presented and extract the readable content using the seq_file interface.
1378c2ecf20Sopenharmony_ci *
1388c2ecf20Sopenharmony_ci * The @write function is called with the data copied into a kernel space
1398c2ecf20Sopenharmony_ci * scratch buffer and has a NUL appended for convenience.  The buffer may be
1408c2ecf20Sopenharmony_ci * modified by the @write function.  @write should return 0 on success.
1418c2ecf20Sopenharmony_ci *
1428c2ecf20Sopenharmony_ci * The @data value is accessible from the @show and @write functions by calling
1438c2ecf20Sopenharmony_ci * PDE_DATA() on the file inode.  The network namespace must be accessed by
1448c2ecf20Sopenharmony_ci * calling seq_file_net() on the seq_file struct.
1458c2ecf20Sopenharmony_ci */
1468c2ecf20Sopenharmony_cistruct proc_dir_entry *proc_create_net_data_write(const char *name, umode_t mode,
1478c2ecf20Sopenharmony_ci						  struct proc_dir_entry *parent,
1488c2ecf20Sopenharmony_ci						  const struct seq_operations *ops,
1498c2ecf20Sopenharmony_ci						  proc_write_t write,
1508c2ecf20Sopenharmony_ci						  unsigned int state_size, void *data)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	struct proc_dir_entry *p;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	p = proc_create_reg(name, mode, &parent, data);
1558c2ecf20Sopenharmony_ci	if (!p)
1568c2ecf20Sopenharmony_ci		return NULL;
1578c2ecf20Sopenharmony_ci	pde_force_lookup(p);
1588c2ecf20Sopenharmony_ci	p->proc_ops = &proc_net_seq_ops;
1598c2ecf20Sopenharmony_ci	p->seq_ops = ops;
1608c2ecf20Sopenharmony_ci	p->state_size = state_size;
1618c2ecf20Sopenharmony_ci	p->write = write;
1628c2ecf20Sopenharmony_ci	return proc_register(parent, p);
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(proc_create_net_data_write);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic int single_open_net(struct inode *inode, struct file *file)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	struct proc_dir_entry *de = PDE(inode);
1698c2ecf20Sopenharmony_ci	struct net *net;
1708c2ecf20Sopenharmony_ci	int err;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	net = get_proc_net(inode);
1738c2ecf20Sopenharmony_ci	if (!net)
1748c2ecf20Sopenharmony_ci		return -ENXIO;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	err = single_open(file, de->single_show, net);
1778c2ecf20Sopenharmony_ci	if (err)
1788c2ecf20Sopenharmony_ci		put_net(net);
1798c2ecf20Sopenharmony_ci	return err;
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic int single_release_net(struct inode *ino, struct file *f)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	struct seq_file *seq = f->private_data;
1858c2ecf20Sopenharmony_ci	put_net(seq->private);
1868c2ecf20Sopenharmony_ci	return single_release(ino, f);
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic const struct proc_ops proc_net_single_ops = {
1908c2ecf20Sopenharmony_ci	.proc_open	= single_open_net,
1918c2ecf20Sopenharmony_ci	.proc_read	= seq_read,
1928c2ecf20Sopenharmony_ci	.proc_write	= proc_simple_write,
1938c2ecf20Sopenharmony_ci	.proc_lseek	= seq_lseek,
1948c2ecf20Sopenharmony_ci	.proc_release	= single_release_net,
1958c2ecf20Sopenharmony_ci};
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistruct proc_dir_entry *proc_create_net_single(const char *name, umode_t mode,
1988c2ecf20Sopenharmony_ci		struct proc_dir_entry *parent,
1998c2ecf20Sopenharmony_ci		int (*show)(struct seq_file *, void *), void *data)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	struct proc_dir_entry *p;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	p = proc_create_reg(name, mode, &parent, data);
2048c2ecf20Sopenharmony_ci	if (!p)
2058c2ecf20Sopenharmony_ci		return NULL;
2068c2ecf20Sopenharmony_ci	pde_force_lookup(p);
2078c2ecf20Sopenharmony_ci	p->proc_ops = &proc_net_single_ops;
2088c2ecf20Sopenharmony_ci	p->single_show = show;
2098c2ecf20Sopenharmony_ci	return proc_register(parent, p);
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(proc_create_net_single);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci/**
2148c2ecf20Sopenharmony_ci * proc_create_net_single_write - Create a writable net_ns-specific proc file
2158c2ecf20Sopenharmony_ci * @name: The name of the file.
2168c2ecf20Sopenharmony_ci * @mode: The file's access mode.
2178c2ecf20Sopenharmony_ci * @parent: The parent directory in which to create.
2188c2ecf20Sopenharmony_ci * @show: The seqfile show method with which to read the file.
2198c2ecf20Sopenharmony_ci * @write: The write method which which to 'modify' the file.
2208c2ecf20Sopenharmony_ci * @data: Data for retrieval by PDE_DATA().
2218c2ecf20Sopenharmony_ci *
2228c2ecf20Sopenharmony_ci * Create a network-namespaced proc file in the @parent directory with the
2238c2ecf20Sopenharmony_ci * specified @name and @mode that allows reading of a file that displays a
2248c2ecf20Sopenharmony_ci * single element rather than a series and also provides for the file accepting
2258c2ecf20Sopenharmony_ci * writes that have some arbitrary effect.
2268c2ecf20Sopenharmony_ci *
2278c2ecf20Sopenharmony_ci * The @show function is called to extract the readable content via the
2288c2ecf20Sopenharmony_ci * seq_file interface.
2298c2ecf20Sopenharmony_ci *
2308c2ecf20Sopenharmony_ci * The @write function is called with the data copied into a kernel space
2318c2ecf20Sopenharmony_ci * scratch buffer and has a NUL appended for convenience.  The buffer may be
2328c2ecf20Sopenharmony_ci * modified by the @write function.  @write should return 0 on success.
2338c2ecf20Sopenharmony_ci *
2348c2ecf20Sopenharmony_ci * The @data value is accessible from the @show and @write functions by calling
2358c2ecf20Sopenharmony_ci * PDE_DATA() on the file inode.  The network namespace must be accessed by
2368c2ecf20Sopenharmony_ci * calling seq_file_single_net() on the seq_file struct.
2378c2ecf20Sopenharmony_ci */
2388c2ecf20Sopenharmony_cistruct proc_dir_entry *proc_create_net_single_write(const char *name, umode_t mode,
2398c2ecf20Sopenharmony_ci						    struct proc_dir_entry *parent,
2408c2ecf20Sopenharmony_ci						    int (*show)(struct seq_file *, void *),
2418c2ecf20Sopenharmony_ci						    proc_write_t write,
2428c2ecf20Sopenharmony_ci						    void *data)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	struct proc_dir_entry *p;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	p = proc_create_reg(name, mode, &parent, data);
2478c2ecf20Sopenharmony_ci	if (!p)
2488c2ecf20Sopenharmony_ci		return NULL;
2498c2ecf20Sopenharmony_ci	pde_force_lookup(p);
2508c2ecf20Sopenharmony_ci	p->proc_ops = &proc_net_single_ops;
2518c2ecf20Sopenharmony_ci	p->single_show = show;
2528c2ecf20Sopenharmony_ci	p->write = write;
2538c2ecf20Sopenharmony_ci	return proc_register(parent, p);
2548c2ecf20Sopenharmony_ci}
2558c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(proc_create_net_single_write);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_cistatic struct net *get_proc_task_net(struct inode *dir)
2588c2ecf20Sopenharmony_ci{
2598c2ecf20Sopenharmony_ci	struct task_struct *task;
2608c2ecf20Sopenharmony_ci	struct nsproxy *ns;
2618c2ecf20Sopenharmony_ci	struct net *net = NULL;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	rcu_read_lock();
2648c2ecf20Sopenharmony_ci	task = pid_task(proc_pid(dir), PIDTYPE_PID);
2658c2ecf20Sopenharmony_ci	if (task != NULL) {
2668c2ecf20Sopenharmony_ci		task_lock(task);
2678c2ecf20Sopenharmony_ci		ns = task->nsproxy;
2688c2ecf20Sopenharmony_ci		if (ns != NULL)
2698c2ecf20Sopenharmony_ci			net = get_net(ns->net_ns);
2708c2ecf20Sopenharmony_ci		task_unlock(task);
2718c2ecf20Sopenharmony_ci	}
2728c2ecf20Sopenharmony_ci	rcu_read_unlock();
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	return net;
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_cistatic struct dentry *proc_tgid_net_lookup(struct inode *dir,
2788c2ecf20Sopenharmony_ci		struct dentry *dentry, unsigned int flags)
2798c2ecf20Sopenharmony_ci{
2808c2ecf20Sopenharmony_ci	struct dentry *de;
2818c2ecf20Sopenharmony_ci	struct net *net;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	de = ERR_PTR(-ENOENT);
2848c2ecf20Sopenharmony_ci	net = get_proc_task_net(dir);
2858c2ecf20Sopenharmony_ci	if (net != NULL) {
2868c2ecf20Sopenharmony_ci		de = proc_lookup_de(dir, dentry, net->proc_net);
2878c2ecf20Sopenharmony_ci		put_net(net);
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci	return de;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic int proc_tgid_net_getattr(const struct path *path, struct kstat *stat,
2938c2ecf20Sopenharmony_ci				 u32 request_mask, unsigned int query_flags)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	struct inode *inode = d_inode(path->dentry);
2968c2ecf20Sopenharmony_ci	struct net *net;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	net = get_proc_task_net(inode);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	generic_fillattr(inode, stat);
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	if (net != NULL) {
3038c2ecf20Sopenharmony_ci		stat->nlink = net->proc_net->nlink;
3048c2ecf20Sopenharmony_ci		put_net(net);
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	return 0;
3088c2ecf20Sopenharmony_ci}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ciconst struct inode_operations proc_net_inode_operations = {
3118c2ecf20Sopenharmony_ci	.lookup		= proc_tgid_net_lookup,
3128c2ecf20Sopenharmony_ci	.getattr	= proc_tgid_net_getattr,
3138c2ecf20Sopenharmony_ci};
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_cistatic int proc_tgid_net_readdir(struct file *file, struct dir_context *ctx)
3168c2ecf20Sopenharmony_ci{
3178c2ecf20Sopenharmony_ci	int ret;
3188c2ecf20Sopenharmony_ci	struct net *net;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	ret = -EINVAL;
3218c2ecf20Sopenharmony_ci	net = get_proc_task_net(file_inode(file));
3228c2ecf20Sopenharmony_ci	if (net != NULL) {
3238c2ecf20Sopenharmony_ci		ret = proc_readdir_de(file, ctx, net->proc_net);
3248c2ecf20Sopenharmony_ci		put_net(net);
3258c2ecf20Sopenharmony_ci	}
3268c2ecf20Sopenharmony_ci	return ret;
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ciconst struct file_operations proc_net_operations = {
3308c2ecf20Sopenharmony_ci	.llseek		= generic_file_llseek,
3318c2ecf20Sopenharmony_ci	.read		= generic_read_dir,
3328c2ecf20Sopenharmony_ci	.iterate_shared	= proc_tgid_net_readdir,
3338c2ecf20Sopenharmony_ci};
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic __net_init int proc_net_ns_init(struct net *net)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	struct proc_dir_entry *netd, *net_statd;
3388c2ecf20Sopenharmony_ci	kuid_t uid;
3398c2ecf20Sopenharmony_ci	kgid_t gid;
3408c2ecf20Sopenharmony_ci	int err;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	err = -ENOMEM;
3438c2ecf20Sopenharmony_ci	netd = kmem_cache_zalloc(proc_dir_entry_cache, GFP_KERNEL);
3448c2ecf20Sopenharmony_ci	if (!netd)
3458c2ecf20Sopenharmony_ci		goto out;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	netd->subdir = RB_ROOT;
3488c2ecf20Sopenharmony_ci	netd->data = net;
3498c2ecf20Sopenharmony_ci	netd->nlink = 2;
3508c2ecf20Sopenharmony_ci	netd->namelen = 3;
3518c2ecf20Sopenharmony_ci	netd->parent = &proc_root;
3528c2ecf20Sopenharmony_ci	netd->name = netd->inline_name;
3538c2ecf20Sopenharmony_ci	memcpy(netd->name, "net", 4);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	uid = make_kuid(net->user_ns, 0);
3568c2ecf20Sopenharmony_ci	if (!uid_valid(uid))
3578c2ecf20Sopenharmony_ci		uid = netd->uid;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	gid = make_kgid(net->user_ns, 0);
3608c2ecf20Sopenharmony_ci	if (!gid_valid(gid))
3618c2ecf20Sopenharmony_ci		gid = netd->gid;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	proc_set_user(netd, uid, gid);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	/* Seed dentry revalidation for /proc/${pid}/net */
3668c2ecf20Sopenharmony_ci	pde_force_lookup(netd);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	err = -EEXIST;
3698c2ecf20Sopenharmony_ci	net_statd = proc_net_mkdir(net, "stat", netd);
3708c2ecf20Sopenharmony_ci	if (!net_statd)
3718c2ecf20Sopenharmony_ci		goto free_net;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	net->proc_net = netd;
3748c2ecf20Sopenharmony_ci	net->proc_net_stat = net_statd;
3758c2ecf20Sopenharmony_ci	return 0;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_cifree_net:
3788c2ecf20Sopenharmony_ci	pde_free(netd);
3798c2ecf20Sopenharmony_ciout:
3808c2ecf20Sopenharmony_ci	return err;
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistatic __net_exit void proc_net_ns_exit(struct net *net)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	remove_proc_entry("stat", net->proc_net);
3868c2ecf20Sopenharmony_ci	pde_free(net->proc_net);
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_cistatic struct pernet_operations __net_initdata proc_net_ns_ops = {
3908c2ecf20Sopenharmony_ci	.init = proc_net_ns_init,
3918c2ecf20Sopenharmony_ci	.exit = proc_net_ns_exit,
3928c2ecf20Sopenharmony_ci};
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ciint __init proc_net_init(void)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	proc_symlink("net", NULL, "self/net");
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	return register_pernet_subsys(&proc_net_ns_ops);
3998c2ecf20Sopenharmony_ci}
400