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 29 static inline struct net *PDE_NET(struct proc_dir_entry *pde) 30 { 31 return pde->parent->data; 32 } 33 34 static struct net *get_proc_net(const struct inode *inode) 35 { 36 return maybe_get_net(PDE_NET(PDE(inode))); 37 } 38 39 int 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 } 61 EXPORT_SYMBOL_GPL(seq_open_net); 62 63 int 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 80 err_open: 81 put_net(net); 82 err_net: 83 return err; 84 } 85 EXPORT_SYMBOL_GPL(single_open_net); 86 87 int 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 } 97 EXPORT_SYMBOL_GPL(seq_release_net); 98 99 int 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 } 105 EXPORT_SYMBOL_GPL(single_release_net); 106 107 static 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 125 static 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 140 static 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 158 const struct inode_operations proc_net_inode_operations = { 159 .lookup = proc_tgid_net_lookup, 160 .getattr = proc_tgid_net_getattr, 161 }; 162 163 static 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 177 const struct file_operations proc_net_operations = { 178 .llseek = generic_file_llseek, 179 .read = generic_read_dir, 180 .iterate = proc_tgid_net_readdir, 181 }; 182 183 static __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 208 free_net: 209 kfree(netd); 210 out: 211 return err; 212 } 213 214 static __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 220 static struct pernet_operations __net_initdata proc_net_ns_ops = { 221 .init = proc_net_ns_init, 222 .exit = proc_net_ns_exit, 223 }; 224 225 int __init proc_net_init(void) 226 { 227 proc_symlink("net", NULL, "self/net"); 228 229 return register_pernet_subsys(&proc_net_ns_ops); 230 } 231