at v4.13-rc5 247 lines 4.8 kB view raw
1/* 2 * linux/fs/proc/net.c 3 * 4 * Copyright (C) 2007 5 * 6 * Author: Eric Biederman <ebiederm@xmission.com> 7 * 8 * proc net directory handling functions 9 */ 10 11#include <linux/uaccess.h> 12 13#include <linux/errno.h> 14#include <linux/time.h> 15#include <linux/proc_fs.h> 16#include <linux/stat.h> 17#include <linux/slab.h> 18#include <linux/init.h> 19#include <linux/sched.h> 20#include <linux/sched/task.h> 21#include <linux/module.h> 22#include <linux/bitops.h> 23#include <linux/mount.h> 24#include <linux/nsproxy.h> 25#include <linux/uidgid.h> 26#include <net/net_namespace.h> 27#include <linux/seq_file.h> 28 29#include "internal.h" 30 31static inline struct net *PDE_NET(struct proc_dir_entry *pde) 32{ 33 return pde->parent->data; 34} 35 36static struct net *get_proc_net(const struct inode *inode) 37{ 38 return maybe_get_net(PDE_NET(PDE(inode))); 39} 40 41int seq_open_net(struct inode *ino, struct file *f, 42 const struct seq_operations *ops, int size) 43{ 44 struct net *net; 45 struct seq_net_private *p; 46 47 BUG_ON(size < sizeof(*p)); 48 49 net = get_proc_net(ino); 50 if (net == NULL) 51 return -ENXIO; 52 53 p = __seq_open_private(f, ops, size); 54 if (p == NULL) { 55 put_net(net); 56 return -ENOMEM; 57 } 58#ifdef CONFIG_NET_NS 59 p->net = net; 60#endif 61 return 0; 62} 63EXPORT_SYMBOL_GPL(seq_open_net); 64 65int single_open_net(struct inode *inode, struct file *file, 66 int (*show)(struct seq_file *, void *)) 67{ 68 int err; 69 struct net *net; 70 71 err = -ENXIO; 72 net = get_proc_net(inode); 73 if (net == NULL) 74 goto err_net; 75 76 err = single_open(file, show, net); 77 if (err < 0) 78 goto err_open; 79 80 return 0; 81 82err_open: 83 put_net(net); 84err_net: 85 return err; 86} 87EXPORT_SYMBOL_GPL(single_open_net); 88 89int seq_release_net(struct inode *ino, struct file *f) 90{ 91 struct seq_file *seq; 92 93 seq = f->private_data; 94 95 put_net(seq_file_net(seq)); 96 seq_release_private(ino, f); 97 return 0; 98} 99EXPORT_SYMBOL_GPL(seq_release_net); 100 101int single_release_net(struct inode *ino, struct file *f) 102{ 103 struct seq_file *seq = f->private_data; 104 put_net(seq->private); 105 return single_release(ino, f); 106} 107EXPORT_SYMBOL_GPL(single_release_net); 108 109static struct net *get_proc_task_net(struct inode *dir) 110{ 111 struct task_struct *task; 112 struct nsproxy *ns; 113 struct net *net = NULL; 114 115 rcu_read_lock(); 116 task = pid_task(proc_pid(dir), PIDTYPE_PID); 117 if (task != NULL) { 118 task_lock(task); 119 ns = task->nsproxy; 120 if (ns != NULL) 121 net = get_net(ns->net_ns); 122 task_unlock(task); 123 } 124 rcu_read_unlock(); 125 126 return net; 127} 128 129static struct dentry *proc_tgid_net_lookup(struct inode *dir, 130 struct dentry *dentry, unsigned int flags) 131{ 132 struct dentry *de; 133 struct net *net; 134 135 de = ERR_PTR(-ENOENT); 136 net = get_proc_task_net(dir); 137 if (net != NULL) { 138 de = proc_lookup_de(net->proc_net, dir, dentry); 139 put_net(net); 140 } 141 return de; 142} 143 144static int proc_tgid_net_getattr(const struct path *path, struct kstat *stat, 145 u32 request_mask, unsigned int query_flags) 146{ 147 struct inode *inode = d_inode(path->dentry); 148 struct net *net; 149 150 net = get_proc_task_net(inode); 151 152 generic_fillattr(inode, stat); 153 154 if (net != NULL) { 155 stat->nlink = net->proc_net->nlink; 156 put_net(net); 157 } 158 159 return 0; 160} 161 162const struct inode_operations proc_net_inode_operations = { 163 .lookup = proc_tgid_net_lookup, 164 .getattr = proc_tgid_net_getattr, 165}; 166 167static int proc_tgid_net_readdir(struct file *file, struct dir_context *ctx) 168{ 169 int ret; 170 struct net *net; 171 172 ret = -EINVAL; 173 net = get_proc_task_net(file_inode(file)); 174 if (net != NULL) { 175 ret = proc_readdir_de(net->proc_net, file, ctx); 176 put_net(net); 177 } 178 return ret; 179} 180 181const struct file_operations proc_net_operations = { 182 .llseek = generic_file_llseek, 183 .read = generic_read_dir, 184 .iterate_shared = proc_tgid_net_readdir, 185}; 186 187static __net_init int proc_net_ns_init(struct net *net) 188{ 189 struct proc_dir_entry *netd, *net_statd; 190 kuid_t uid; 191 kgid_t gid; 192 int err; 193 194 err = -ENOMEM; 195 netd = kzalloc(sizeof(*netd) + 4, GFP_KERNEL); 196 if (!netd) 197 goto out; 198 199 netd->subdir = RB_ROOT; 200 netd->data = net; 201 netd->nlink = 2; 202 netd->namelen = 3; 203 netd->parent = &proc_root; 204 memcpy(netd->name, "net", 4); 205 206 uid = make_kuid(net->user_ns, 0); 207 if (!uid_valid(uid)) 208 uid = netd->uid; 209 210 gid = make_kgid(net->user_ns, 0); 211 if (!gid_valid(gid)) 212 gid = netd->gid; 213 214 proc_set_user(netd, uid, gid); 215 216 err = -EEXIST; 217 net_statd = proc_net_mkdir(net, "stat", netd); 218 if (!net_statd) 219 goto free_net; 220 221 net->proc_net = netd; 222 net->proc_net_stat = net_statd; 223 return 0; 224 225free_net: 226 kfree(netd); 227out: 228 return err; 229} 230 231static __net_exit void proc_net_ns_exit(struct net *net) 232{ 233 remove_proc_entry("stat", net->proc_net); 234 kfree(net->proc_net); 235} 236 237static struct pernet_operations __net_initdata proc_net_ns_ops = { 238 .init = proc_net_ns_init, 239 .exit = proc_net_ns_exit, 240}; 241 242int __init proc_net_init(void) 243{ 244 proc_symlink("net", NULL, "self/net"); 245 246 return register_pernet_subsys(&proc_net_ns_ops); 247}