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 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 127 static 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 142 static 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 160 const struct inode_operations proc_net_inode_operations = { 161 .lookup = proc_tgid_net_lookup, 162 .getattr = proc_tgid_net_getattr, 163 }; 164 165 static 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 179 const struct file_operations proc_net_operations = { 180 .llseek = generic_file_llseek, 181 .read = generic_read_dir, 182 .iterate = proc_tgid_net_readdir, 183 }; 184 185 static __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 211 free_net: 212 kfree(netd); 213 out: 214 return err; 215 } 216 217 static __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 223 static struct pernet_operations __net_initdata proc_net_ns_ops = { 224 .init = proc_net_ns_init, 225 .exit = proc_net_ns_exit, 226 }; 227 228 int __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