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