Branch data Line data Source code
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 : 37 : 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 : 0 : 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 [ + - ]: 30 : if (net == NULL)
49 : : return -ENXIO;
50 : :
51 : 30 : p = __seq_open_private(f, ops, size);
52 [ + - ]: 30 : if (p == NULL) {
53 : : put_net(net);
54 : : return -ENOMEM;
55 : : }
56 : : #ifdef CONFIG_NET_NS
57 : : p->net = net;
58 : : #endif
59 : 30 : return 0;
60 : : }
61 : : EXPORT_SYMBOL_GPL(seq_open_net);
62 : :
63 : 0 : 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 [ + - ]: 7 : if (net == NULL)
72 : : goto err_net;
73 : :
74 : 7 : err = single_open(file, show, net);
75 [ - + ]: 7 : if (err < 0)
76 : : goto err_open;
77 : :
78 : : return 0;
79 : :
80 : : err_open:
81 : : put_net(net);
82 : : err_net:
83 : 0 : return err;
84 : : }
85 : : EXPORT_SYMBOL_GPL(single_open_net);
86 : :
87 : 0 : 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 : 30 : seq_release_private(ino, f);
95 : 30 : return 0;
96 : : }
97 : : EXPORT_SYMBOL_GPL(seq_release_net);
98 : :
99 : 0 : 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 : 7 : return single_release(ino, f);
104 : : }
105 : : EXPORT_SYMBOL_GPL(single_release_net);
106 : :
107 : 0 : 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 : 93 : task = pid_task(proc_pid(dir), PIDTYPE_PID);
115 [ + - ]: 93 : if (task != NULL) {
116 : : ns = task_nsproxy(task);
117 [ + - ]: 93 : if (ns != NULL)
118 : 93 : net = get_net(ns->net_ns);
119 : : }
120 : : rcu_read_unlock();
121 : :
122 : 93 : return net;
123 : : }
124 : :
125 : 0 : 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 : 90 : net = get_proc_task_net(dir);
133 [ + - ]: 90 : if (net != NULL) {
134 : 90 : de = proc_lookup_de(net->proc_net, dir, dentry);
135 : : put_net(net);
136 : : }
137 : 0 : return de;
138 : : }
139 : :
140 : 0 : static int proc_tgid_net_getattr(struct vfsmount *mnt, struct dentry *dentry,
141 : : struct kstat *stat)
142 : : {
143 : 1 : struct inode *inode = dentry->d_inode;
144 : : struct net *net;
145 : :
146 : 1 : net = get_proc_task_net(inode);
147 : :
148 : 1 : generic_fillattr(inode, stat);
149 : :
150 [ + - ]: 1 : if (net != NULL) {
151 : 1 : stat->nlink = net->proc_net->nlink;
152 : : put_net(net);
153 : : }
154 : :
155 : 0 : 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 : 0 : 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 : 2 : net = get_proc_task_net(file_inode(file));
170 [ + - ]: 2 : if (net != NULL) {
171 : 2 : ret = proc_readdir_de(net->proc_net, file, ctx);
172 : : put_net(net);
173 : : }
174 : 0 : 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 : 0 : 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 [ # # ]: 0 : if (!netd)
191 : : goto out;
192 : :
193 : 0 : netd->data = net;
194 : 0 : netd->nlink = 2;
195 : 0 : netd->namelen = 3;
196 : 0 : netd->parent = &proc_root;
197 : 0 : memcpy(netd->name, "net", 4);
198 : :
199 : : err = -EEXIST;
200 : : net_statd = proc_net_mkdir(net, "stat", netd);
201 [ # # ]: 0 : if (!net_statd)
202 : : goto free_net;
203 : :
204 : 0 : net->proc_net = netd;
205 : 0 : net->proc_net_stat = net_statd;
206 : 0 : return 0;
207 : :
208 : : free_net:
209 : 0 : kfree(netd);
210 : : out:
211 : 0 : return err;
212 : : }
213 : :
214 : 0 : static __net_exit void proc_net_ns_exit(struct net *net)
215 : : {
216 : 0 : remove_proc_entry("stat", net->proc_net);
217 : 0 : kfree(net->proc_net);
218 : 0 : }
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 : 0 : int __init proc_net_init(void)
226 : : {
227 : 0 : proc_symlink("net", NULL, "self/net");
228 : :
229 : 0 : return register_pernet_subsys(&proc_net_ns_ops);
230 : : }
|