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