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 task_lock(task); 117 ns = task->nsproxy; 118 if (ns != NULL) 119 net = get_net(ns->net_ns); 120 task_unlock(task); 121 } 122 rcu_read_unlock(); 123 124 return net; 125} 126 127static struct dentry *proc_tgid_net_lookup(struct inode *dir, 128 struct dentry *dentry, unsigned int flags) 129{ 130 struct dentry *de; 131 struct net *net; 132 133 de = ERR_PTR(-ENOENT); 134 net = get_proc_task_net(dir); 135 if (net != NULL) { 136 de = proc_lookup_de(net->proc_net, dir, dentry); 137 put_net(net); 138 } 139 return de; 140} 141 142static int proc_tgid_net_getattr(struct vfsmount *mnt, struct dentry *dentry, 143 struct kstat *stat) 144{ 145 struct inode *inode = d_inode(dentry); 146 struct net *net; 147 148 net = get_proc_task_net(inode); 149 150 generic_fillattr(inode, stat); 151 152 if (net != NULL) { 153 stat->nlink = net->proc_net->nlink; 154 put_net(net); 155 } 156 157 return 0; 158} 159 160const struct inode_operations proc_net_inode_operations = { 161 .lookup = proc_tgid_net_lookup, 162 .getattr = proc_tgid_net_getattr, 163}; 164 165static int proc_tgid_net_readdir(struct file *file, struct dir_context *ctx) 166{ 167 int ret; 168 struct net *net; 169 170 ret = -EINVAL; 171 net = get_proc_task_net(file_inode(file)); 172 if (net != NULL) { 173 ret = proc_readdir_de(net->proc_net, file, ctx); 174 put_net(net); 175 } 176 return ret; 177} 178 179const struct file_operations proc_net_operations = { 180 .llseek = generic_file_llseek, 181 .read = generic_read_dir, 182 .iterate = proc_tgid_net_readdir, 183}; 184 185static __net_init int proc_net_ns_init(struct net *net) 186{ 187 struct proc_dir_entry *netd, *net_statd; 188 int err; 189 190 err = -ENOMEM; 191 netd = kzalloc(sizeof(*netd) + 4, GFP_KERNEL); 192 if (!netd) 193 goto out; 194 195 netd->subdir = RB_ROOT; 196 netd->data = net; 197 netd->nlink = 2; 198 netd->namelen = 3; 199 netd->parent = &proc_root; 200 memcpy(netd->name, "net", 4); 201 202 err = -EEXIST; 203 net_statd = proc_net_mkdir(net, "stat", netd); 204 if (!net_statd) 205 goto free_net; 206 207 net->proc_net = netd; 208 net->proc_net_stat = net_statd; 209 return 0; 210 211free_net: 212 kfree(netd); 213out: 214 return err; 215} 216 217static __net_exit void proc_net_ns_exit(struct net *net) 218{ 219 remove_proc_entry("stat", net->proc_net); 220 kfree(net->proc_net); 221} 222 223static struct pernet_operations __net_initdata proc_net_ns_ops = { 224 .init = proc_net_ns_init, 225 .exit = proc_net_ns_exit, 226}; 227 228int __init proc_net_init(void) 229{ 230 proc_symlink("net", NULL, "self/net"); 231 232 return register_pernet_subsys(&proc_net_ns_ops); 233} 234