blob: e1cfeda397f3fb88004854cd15e4087b48e7a54d [file] [log] [blame]
Thomas Gleixner457c8992019-05-19 13:08:55 +01001// SPDX-License-Identifier: GPL-2.0-only
David S. Miller3c12afe2007-09-12 14:18:18 +02002/*
3 * linux/fs/proc/net.c
4 *
5 * Copyright (C) 2007
6 *
7 * Author: Eric Biederman <ebiederm@xmission.com>
8 *
9 * proc net directory handling functions
10 */
11
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080012#include <linux/uaccess.h>
David S. Miller3c12afe2007-09-12 14:18:18 +020013
14#include <linux/errno.h>
15#include <linux/time.h>
16#include <linux/proc_fs.h>
17#include <linux/stat.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090018#include <linux/slab.h>
David S. Miller3c12afe2007-09-12 14:18:18 +020019#include <linux/init.h>
20#include <linux/sched.h>
Ingo Molnarf719ff9b2017-02-06 10:57:33 +010021#include <linux/sched/task.h>
David S. Miller3c12afe2007-09-12 14:18:18 +020022#include <linux/module.h>
23#include <linux/bitops.h>
David S. Miller3c12afe2007-09-12 14:18:18 +020024#include <linux/mount.h>
25#include <linux/nsproxy.h>
Dmitry Torokhovc1104862016-08-10 14:36:01 -070026#include <linux/uidgid.h>
David S. Miller3c12afe2007-09-12 14:18:18 +020027#include <net/net_namespace.h>
Denis V. Luneve372c412007-11-19 22:31:54 -080028#include <linux/seq_file.h>
David S. Miller3c12afe2007-09-12 14:18:18 +020029
30#include "internal.h"
31
David Howells4abfd022013-04-12 02:09:03 +010032static inline struct net *PDE_NET(struct proc_dir_entry *pde)
33{
34 return pde->parent->data;
35}
David S. Miller3c12afe2007-09-12 14:18:18 +020036
Adrian Bunk8086cd42008-07-22 14:19:19 -070037static struct net *get_proc_net(const struct inode *inode)
38{
39 return maybe_get_net(PDE_NET(PDE(inode)));
40}
41
Christoph Hellwigc3506372018-04-10 19:42:55 +020042static int seq_open_net(struct inode *inode, struct file *file)
Denis V. Luneve372c412007-11-19 22:31:54 -080043{
Christoph Hellwigc3506372018-04-10 19:42:55 +020044 unsigned int state_size = PDE(inode)->state_size;
Denis V. Luneve372c412007-11-19 22:31:54 -080045 struct seq_net_private *p;
Christoph Hellwigc3506372018-04-10 19:42:55 +020046 struct net *net;
Denis V. Luneve372c412007-11-19 22:31:54 -080047
Christoph Hellwigc3506372018-04-10 19:42:55 +020048 WARN_ON_ONCE(state_size < sizeof(*p));
Denis V. Luneve372c412007-11-19 22:31:54 -080049
David Howells564def72018-05-18 11:46:15 +010050 if (file->f_mode & FMODE_WRITE && !PDE(inode)->write)
51 return -EACCES;
52
Christoph Hellwigc3506372018-04-10 19:42:55 +020053 net = get_proc_net(inode);
54 if (!net)
Denis V. Luneve372c412007-11-19 22:31:54 -080055 return -ENXIO;
56
Christoph Hellwigc3506372018-04-10 19:42:55 +020057 p = __seq_open_private(file, PDE(inode)->seq_ops, state_size);
58 if (!p) {
Denis V. Luneve372c412007-11-19 22:31:54 -080059 put_net(net);
60 return -ENOMEM;
61 }
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +090062#ifdef CONFIG_NET_NS
Denis V. Luneve372c412007-11-19 22:31:54 -080063 p->net = net;
Eric Dumazet04a931e2021-12-09 23:44:23 -080064 netns_tracker_alloc(net, &p->ns_tracker, GFP_KERNEL);
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +090065#endif
Denis V. Luneve372c412007-11-19 22:31:54 -080066 return 0;
67}
Christoph Hellwigc3506372018-04-10 19:42:55 +020068
Eric Dumazet04a931e2021-12-09 23:44:23 -080069static void seq_file_net_put_net(struct seq_file *seq)
70{
71#ifdef CONFIG_NET_NS
72 struct seq_net_private *priv = seq->private;
73
74 put_net_track(priv->net, &priv->ns_tracker);
75#else
76 put_net(&init_net);
77#endif
78}
79
Christoph Hellwigc3506372018-04-10 19:42:55 +020080static int seq_release_net(struct inode *ino, struct file *f)
81{
82 struct seq_file *seq = f->private_data;
83
Eric Dumazet04a931e2021-12-09 23:44:23 -080084 seq_file_net_put_net(seq);
Christoph Hellwigc3506372018-04-10 19:42:55 +020085 seq_release_private(ino, f);
86 return 0;
87}
88
Alexey Dobriyand56c0d42020-02-03 17:37:14 -080089static const struct proc_ops proc_net_seq_ops = {
90 .proc_open = seq_open_net,
91 .proc_read = seq_read,
92 .proc_write = proc_simple_write,
93 .proc_lseek = seq_lseek,
94 .proc_release = seq_release_net,
Christoph Hellwigc3506372018-04-10 19:42:55 +020095};
96
Yonghong Songf9c79272020-07-23 11:41:10 -070097int bpf_iter_init_seq_net(void *priv_data, struct bpf_iter_aux_info *aux)
Yonghong Song138d0be2020-05-09 10:59:10 -070098{
99#ifdef CONFIG_NET_NS
100 struct seq_net_private *p = priv_data;
101
Eric Dumazet04a931e2021-12-09 23:44:23 -0800102 p->net = get_net_track(current->nsproxy->net_ns, &p->ns_tracker,
103 GFP_KERNEL);
Yonghong Song138d0be2020-05-09 10:59:10 -0700104#endif
105 return 0;
106}
107
108void bpf_iter_fini_seq_net(void *priv_data)
109{
110#ifdef CONFIG_NET_NS
111 struct seq_net_private *p = priv_data;
112
Eric Dumazet04a931e2021-12-09 23:44:23 -0800113 put_net_track(p->net, &p->ns_tracker);
Yonghong Song138d0be2020-05-09 10:59:10 -0700114#endif
115}
116
Christoph Hellwigc3506372018-04-10 19:42:55 +0200117struct proc_dir_entry *proc_create_net_data(const char *name, umode_t mode,
118 struct proc_dir_entry *parent, const struct seq_operations *ops,
119 unsigned int state_size, void *data)
120{
121 struct proc_dir_entry *p;
122
123 p = proc_create_reg(name, mode, &parent, data);
124 if (!p)
125 return NULL;
Alexey Dobriyan1fde6f22019-02-01 14:20:01 -0800126 pde_force_lookup(p);
Alexey Dobriyand56c0d42020-02-03 17:37:14 -0800127 p->proc_ops = &proc_net_seq_ops;
Christoph Hellwigc3506372018-04-10 19:42:55 +0200128 p->seq_ops = ops;
129 p->state_size = state_size;
130 return proc_register(parent, p);
131}
132EXPORT_SYMBOL_GPL(proc_create_net_data);
Denis V. Luneve372c412007-11-19 22:31:54 -0800133
David Howells564def72018-05-18 11:46:15 +0100134/**
135 * proc_create_net_data_write - Create a writable net_ns-specific proc file
136 * @name: The name of the file.
137 * @mode: The file's access mode.
138 * @parent: The parent directory in which to create.
139 * @ops: The seq_file ops with which to read the file.
Randy Dunlapd2928e82020-12-15 20:42:32 -0800140 * @write: The write method with which to 'modify' the file.
Muchun Song359745d2022-01-21 22:14:23 -0800141 * @data: Data for retrieval by pde_data().
David Howells564def72018-05-18 11:46:15 +0100142 *
143 * Create a network namespaced proc file in the @parent directory with the
144 * specified @name and @mode that allows reading of a file that displays a
145 * series of elements and also provides for the file accepting writes that have
146 * some arbitrary effect.
147 *
148 * The functions in the @ops table are used to iterate over items to be
149 * presented and extract the readable content using the seq_file interface.
150 *
151 * The @write function is called with the data copied into a kernel space
152 * scratch buffer and has a NUL appended for convenience. The buffer may be
153 * modified by the @write function. @write should return 0 on success.
154 *
155 * The @data value is accessible from the @show and @write functions by calling
Muchun Song359745d2022-01-21 22:14:23 -0800156 * pde_data() on the file inode. The network namespace must be accessed by
David Howells564def72018-05-18 11:46:15 +0100157 * calling seq_file_net() on the seq_file struct.
158 */
159struct proc_dir_entry *proc_create_net_data_write(const char *name, umode_t mode,
160 struct proc_dir_entry *parent,
161 const struct seq_operations *ops,
162 proc_write_t write,
163 unsigned int state_size, void *data)
164{
165 struct proc_dir_entry *p;
166
167 p = proc_create_reg(name, mode, &parent, data);
168 if (!p)
169 return NULL;
Alexey Dobriyan1fde6f22019-02-01 14:20:01 -0800170 pde_force_lookup(p);
Alexey Dobriyand56c0d42020-02-03 17:37:14 -0800171 p->proc_ops = &proc_net_seq_ops;
David Howells564def72018-05-18 11:46:15 +0100172 p->seq_ops = ops;
173 p->state_size = state_size;
174 p->write = write;
175 return proc_register(parent, p);
176}
177EXPORT_SYMBOL_GPL(proc_create_net_data_write);
178
Christoph Hellwig3617d942018-04-13 20:38:35 +0200179static int single_open_net(struct inode *inode, struct file *file)
Pavel Emelyanovde05c552008-07-18 04:07:21 -0700180{
Christoph Hellwig3617d942018-04-13 20:38:35 +0200181 struct proc_dir_entry *de = PDE(inode);
Pavel Emelyanovde05c552008-07-18 04:07:21 -0700182 struct net *net;
Christoph Hellwig3617d942018-04-13 20:38:35 +0200183 int err;
Pavel Emelyanovde05c552008-07-18 04:07:21 -0700184
Pavel Emelyanovde05c552008-07-18 04:07:21 -0700185 net = get_proc_net(inode);
Christoph Hellwig3617d942018-04-13 20:38:35 +0200186 if (!net)
187 return -ENXIO;
Pavel Emelyanovde05c552008-07-18 04:07:21 -0700188
Christoph Hellwig3617d942018-04-13 20:38:35 +0200189 err = single_open(file, de->single_show, net);
190 if (err)
191 put_net(net);
Pavel Emelyanovde05c552008-07-18 04:07:21 -0700192 return err;
193}
Pavel Emelyanovde05c552008-07-18 04:07:21 -0700194
Christoph Hellwig3617d942018-04-13 20:38:35 +0200195static int single_release_net(struct inode *ino, struct file *f)
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -0700196{
197 struct seq_file *seq = f->private_data;
198 put_net(seq->private);
199 return single_release(ino, f);
200}
Christoph Hellwig3617d942018-04-13 20:38:35 +0200201
Alexey Dobriyand56c0d42020-02-03 17:37:14 -0800202static const struct proc_ops proc_net_single_ops = {
203 .proc_open = single_open_net,
204 .proc_read = seq_read,
205 .proc_write = proc_simple_write,
206 .proc_lseek = seq_lseek,
207 .proc_release = single_release_net,
Christoph Hellwig3617d942018-04-13 20:38:35 +0200208};
209
210struct proc_dir_entry *proc_create_net_single(const char *name, umode_t mode,
211 struct proc_dir_entry *parent,
212 int (*show)(struct seq_file *, void *), void *data)
213{
214 struct proc_dir_entry *p;
215
216 p = proc_create_reg(name, mode, &parent, data);
217 if (!p)
218 return NULL;
Alexey Dobriyan1fde6f22019-02-01 14:20:01 -0800219 pde_force_lookup(p);
Alexey Dobriyand56c0d42020-02-03 17:37:14 -0800220 p->proc_ops = &proc_net_single_ops;
Christoph Hellwig3617d942018-04-13 20:38:35 +0200221 p->single_show = show;
222 return proc_register(parent, p);
223}
224EXPORT_SYMBOL_GPL(proc_create_net_single);
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -0700225
David Howells564def72018-05-18 11:46:15 +0100226/**
227 * proc_create_net_single_write - Create a writable net_ns-specific proc file
228 * @name: The name of the file.
229 * @mode: The file's access mode.
230 * @parent: The parent directory in which to create.
231 * @show: The seqfile show method with which to read the file.
Randy Dunlapd2928e82020-12-15 20:42:32 -0800232 * @write: The write method with which to 'modify' the file.
Muchun Song359745d2022-01-21 22:14:23 -0800233 * @data: Data for retrieval by pde_data().
David Howells564def72018-05-18 11:46:15 +0100234 *
235 * Create a network-namespaced proc file in the @parent directory with the
236 * specified @name and @mode that allows reading of a file that displays a
237 * single element rather than a series and also provides for the file accepting
238 * writes that have some arbitrary effect.
239 *
240 * The @show function is called to extract the readable content via the
241 * seq_file interface.
242 *
243 * The @write function is called with the data copied into a kernel space
244 * scratch buffer and has a NUL appended for convenience. The buffer may be
245 * modified by the @write function. @write should return 0 on success.
246 *
247 * The @data value is accessible from the @show and @write functions by calling
Muchun Song359745d2022-01-21 22:14:23 -0800248 * pde_data() on the file inode. The network namespace must be accessed by
David Howells564def72018-05-18 11:46:15 +0100249 * calling seq_file_single_net() on the seq_file struct.
250 */
251struct proc_dir_entry *proc_create_net_single_write(const char *name, umode_t mode,
252 struct proc_dir_entry *parent,
253 int (*show)(struct seq_file *, void *),
254 proc_write_t write,
255 void *data)
256{
257 struct proc_dir_entry *p;
258
259 p = proc_create_reg(name, mode, &parent, data);
260 if (!p)
261 return NULL;
Alexey Dobriyan1fde6f22019-02-01 14:20:01 -0800262 pde_force_lookup(p);
Alexey Dobriyand56c0d42020-02-03 17:37:14 -0800263 p->proc_ops = &proc_net_single_ops;
David Howells564def72018-05-18 11:46:15 +0100264 p->single_show = show;
265 p->write = write;
266 return proc_register(parent, p);
267}
268EXPORT_SYMBOL_GPL(proc_create_net_single_write);
269
Pavel Emelyanove9720ac2008-03-07 11:08:40 -0800270static struct net *get_proc_task_net(struct inode *dir)
271{
272 struct task_struct *task;
273 struct nsproxy *ns;
274 struct net *net = NULL;
275
276 rcu_read_lock();
277 task = pid_task(proc_pid(dir), PIDTYPE_PID);
278 if (task != NULL) {
Eric W. Biederman728dba32014-02-03 19:13:49 -0800279 task_lock(task);
280 ns = task->nsproxy;
Pavel Emelyanove9720ac2008-03-07 11:08:40 -0800281 if (ns != NULL)
282 net = get_net(ns->net_ns);
Eric W. Biederman728dba32014-02-03 19:13:49 -0800283 task_unlock(task);
Pavel Emelyanove9720ac2008-03-07 11:08:40 -0800284 }
285 rcu_read_unlock();
286
287 return net;
288}
289
290static struct dentry *proc_tgid_net_lookup(struct inode *dir,
Al Viro00cd8dd2012-06-10 17:13:09 -0400291 struct dentry *dentry, unsigned int flags)
Pavel Emelyanove9720ac2008-03-07 11:08:40 -0800292{
293 struct dentry *de;
294 struct net *net;
295
296 de = ERR_PTR(-ENOENT);
297 net = get_proc_task_net(dir);
298 if (net != NULL) {
Alexey Dobriyan93ad5bc2018-02-06 15:37:31 -0800299 de = proc_lookup_de(dir, dentry, net->proc_net);
Pavel Emelyanove9720ac2008-03-07 11:08:40 -0800300 put_net(net);
301 }
302 return de;
303}
304
Christian Brauner549c7292021-01-21 14:19:43 +0100305static int proc_tgid_net_getattr(struct user_namespace *mnt_userns,
306 const struct path *path, struct kstat *stat,
David Howellsa528d352017-01-31 16:46:22 +0000307 u32 request_mask, unsigned int query_flags)
Pavel Emelyanove9720ac2008-03-07 11:08:40 -0800308{
David Howellsa528d352017-01-31 16:46:22 +0000309 struct inode *inode = d_inode(path->dentry);
Pavel Emelyanove9720ac2008-03-07 11:08:40 -0800310 struct net *net;
311
312 net = get_proc_task_net(inode);
313
Christian Brauner0d56a452021-01-21 14:19:30 +0100314 generic_fillattr(&init_user_ns, inode, stat);
Pavel Emelyanove9720ac2008-03-07 11:08:40 -0800315
316 if (net != NULL) {
317 stat->nlink = net->proc_net->nlink;
318 put_net(net);
319 }
320
321 return 0;
322}
323
324const struct inode_operations proc_net_inode_operations = {
325 .lookup = proc_tgid_net_lookup,
326 .getattr = proc_tgid_net_getattr,
327};
328
Al Virof0c3b502013-05-16 12:07:31 -0400329static int proc_tgid_net_readdir(struct file *file, struct dir_context *ctx)
Pavel Emelyanove9720ac2008-03-07 11:08:40 -0800330{
331 int ret;
332 struct net *net;
333
334 ret = -EINVAL;
Al Virof0c3b502013-05-16 12:07:31 -0400335 net = get_proc_task_net(file_inode(file));
Pavel Emelyanove9720ac2008-03-07 11:08:40 -0800336 if (net != NULL) {
Alexey Dobriyan93ad5bc2018-02-06 15:37:31 -0800337 ret = proc_readdir_de(file, ctx, net->proc_net);
Pavel Emelyanove9720ac2008-03-07 11:08:40 -0800338 put_net(net);
339 }
340 return ret;
341}
342
343const struct file_operations proc_net_operations = {
Alexey Dobriyanb4df2b92008-10-27 22:48:36 +0300344 .llseek = generic_file_llseek,
Pavel Emelyanove9720ac2008-03-07 11:08:40 -0800345 .read = generic_read_dir,
Al Virof50752e2016-04-20 17:13:54 -0400346 .iterate_shared = proc_tgid_net_readdir,
Pavel Emelyanove9720ac2008-03-07 11:08:40 -0800347};
348
Pavel Emelyanov46650792007-10-08 20:38:39 -0700349static __net_init int proc_net_ns_init(struct net *net)
David S. Miller3c12afe2007-09-12 14:18:18 +0200350{
Pavel Emelyanove9720ac2008-03-07 11:08:40 -0800351 struct proc_dir_entry *netd, *net_statd;
Dmitry Torokhovc1104862016-08-10 14:36:01 -0700352 kuid_t uid;
353 kgid_t gid;
David S. Miller3c12afe2007-09-12 14:18:18 +0200354 int err;
355
356 err = -ENOMEM;
Alexey Dobriyanb4884f22018-04-10 16:31:52 -0700357 netd = kmem_cache_zalloc(proc_dir_entry_cache, GFP_KERNEL);
Pavel Emelyanove9720ac2008-03-07 11:08:40 -0800358 if (!netd)
David S. Miller3c12afe2007-09-12 14:18:18 +0200359 goto out;
360
Alexey Dobriyan4f113432018-04-10 16:32:20 -0700361 netd->subdir = RB_ROOT;
Pavel Emelyanove9720ac2008-03-07 11:08:40 -0800362 netd->data = net;
363 netd->nlink = 2;
Pavel Emelyanove9720ac2008-03-07 11:08:40 -0800364 netd->namelen = 3;
365 netd->parent = &proc_root;
Alexey Dobriyanb4884f22018-04-10 16:31:52 -0700366 netd->name = netd->inline_name;
David Howells09570f92011-07-27 21:47:03 +0300367 memcpy(netd->name, "net", 4);
David S. Miller3c12afe2007-09-12 14:18:18 +0200368
Dmitry Torokhovc1104862016-08-10 14:36:01 -0700369 uid = make_kuid(net->user_ns, 0);
370 if (!uid_valid(uid))
371 uid = netd->uid;
372
373 gid = make_kgid(net->user_ns, 0);
374 if (!gid_valid(gid))
375 gid = netd->gid;
376
377 proc_set_user(netd, uid, gid);
378
David S. Miller3c12afe2007-09-12 14:18:18 +0200379 err = -EEXIST;
Denis V. Luneve5d69b92008-01-10 03:51:41 -0800380 net_statd = proc_net_mkdir(net, "stat", netd);
David S. Miller3c12afe2007-09-12 14:18:18 +0200381 if (!net_statd)
382 goto free_net;
383
David S. Miller3c12afe2007-09-12 14:18:18 +0200384 net->proc_net = netd;
385 net->proc_net_stat = net_statd;
Pavel Emelyanove9720ac2008-03-07 11:08:40 -0800386 return 0;
David S. Miller3c12afe2007-09-12 14:18:18 +0200387
Pavel Emelyanove9720ac2008-03-07 11:08:40 -0800388free_net:
Alexey Dobriyanb4884f22018-04-10 16:31:52 -0700389 pde_free(netd);
David S. Miller3c12afe2007-09-12 14:18:18 +0200390out:
391 return err;
David S. Miller3c12afe2007-09-12 14:18:18 +0200392}
393
Pavel Emelyanov46650792007-10-08 20:38:39 -0700394static __net_exit void proc_net_ns_exit(struct net *net)
David S. Miller3c12afe2007-09-12 14:18:18 +0200395{
396 remove_proc_entry("stat", net->proc_net);
Alexey Dobriyanb4884f22018-04-10 16:31:52 -0700397 pde_free(net->proc_net);
David S. Miller3c12afe2007-09-12 14:18:18 +0200398}
399
Denis V. Lunev022cbae2007-11-13 03:23:50 -0800400static struct pernet_operations __net_initdata proc_net_ns_ops = {
David S. Miller3c12afe2007-09-12 14:18:18 +0200401 .init = proc_net_ns_init,
402 .exit = proc_net_ns_exit,
403};
404
Pavel Emelyanov46650792007-10-08 20:38:39 -0700405int __init proc_net_init(void)
David S. Miller3c12afe2007-09-12 14:18:18 +0200406{
Linus Torvalds155134f2014-08-10 21:24:59 -0700407 proc_symlink("net", NULL, "self/net");
David S. Miller3c12afe2007-09-12 14:18:18 +0200408
409 return register_pernet_subsys(&proc_net_ns_ops);
410}