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