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