419 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * linux/fs/proc/net.c4 *5 * Copyright (C) 20076 *7 * Author: Eric Biederman <ebiederm@xmission.com>8 *9 * proc net directory handling functions10 */11#include <linux/errno.h>12#include <linux/time.h>13#include <linux/proc_fs.h>14#include <linux/stat.h>15#include <linux/slab.h>16#include <linux/init.h>17#include <linux/sched.h>18#include <linux/sched/task.h>19#include <linux/module.h>20#include <linux/bitops.h>21#include <linux/mount.h>22#include <linux/nsproxy.h>23#include <linux/uidgid.h>24#include <net/net_namespace.h>25#include <linux/seq_file.h>26 27#include "internal.h"28 29static inline struct net *PDE_NET(struct proc_dir_entry *pde)30{31 return pde->parent->data;32}33 34static struct net *get_proc_net(const struct inode *inode)35{36 return maybe_get_net(PDE_NET(PDE(inode)));37}38 39static int seq_open_net(struct inode *inode, struct file *file)40{41 unsigned int state_size = PDE(inode)->state_size;42 struct seq_net_private *p;43 struct net *net;44 45 WARN_ON_ONCE(state_size < sizeof(*p));46 47 if (file->f_mode & FMODE_WRITE && !PDE(inode)->write)48 return -EACCES;49 50 net = get_proc_net(inode);51 if (!net)52 return -ENXIO;53 54 p = __seq_open_private(file, PDE(inode)->seq_ops, state_size);55 if (!p) {56 put_net(net);57 return -ENOMEM;58 }59#ifdef CONFIG_NET_NS60 p->net = net;61 netns_tracker_alloc(net, &p->ns_tracker, GFP_KERNEL);62#endif63 return 0;64}65 66static void seq_file_net_put_net(struct seq_file *seq)67{68#ifdef CONFIG_NET_NS69 struct seq_net_private *priv = seq->private;70 71 put_net_track(priv->net, &priv->ns_tracker);72#else73 put_net(&init_net);74#endif75}76 77static int seq_release_net(struct inode *ino, struct file *f)78{79 struct seq_file *seq = f->private_data;80 81 seq_file_net_put_net(seq);82 seq_release_private(ino, f);83 return 0;84}85 86static const struct proc_ops proc_net_seq_ops = {87 .proc_open = seq_open_net,88 .proc_read = seq_read,89 .proc_write = proc_simple_write,90 .proc_lseek = seq_lseek,91 .proc_release = seq_release_net,92};93 94int bpf_iter_init_seq_net(void *priv_data, struct bpf_iter_aux_info *aux)95{96#ifdef CONFIG_NET_NS97 struct seq_net_private *p = priv_data;98 99 p->net = get_net_track(current->nsproxy->net_ns, &p->ns_tracker,100 GFP_KERNEL);101#endif102 return 0;103}104 105void bpf_iter_fini_seq_net(void *priv_data)106{107#ifdef CONFIG_NET_NS108 struct seq_net_private *p = priv_data;109 110 put_net_track(p->net, &p->ns_tracker);111#endif112}113 114struct proc_dir_entry *proc_create_net_data(const char *name, umode_t mode,115 struct proc_dir_entry *parent, const struct seq_operations *ops,116 unsigned int state_size, void *data)117{118 struct proc_dir_entry *p;119 120 p = proc_create_reg(name, mode, &parent, data);121 if (!p)122 return NULL;123 pde_force_lookup(p);124 p->proc_ops = &proc_net_seq_ops;125 p->seq_ops = ops;126 p->state_size = state_size;127 return proc_register(parent, p);128}129EXPORT_SYMBOL_GPL(proc_create_net_data);130 131/**132 * proc_create_net_data_write - Create a writable net_ns-specific proc file133 * @name: The name of the file.134 * @mode: The file's access mode.135 * @parent: The parent directory in which to create.136 * @ops: The seq_file ops with which to read the file.137 * @write: The write method with which to 'modify' the file.138 * @state_size: The size of the per-file private state to allocate.139 * @data: Data for retrieval by pde_data().140 *141 * Create a network namespaced proc file in the @parent directory with the142 * specified @name and @mode that allows reading of a file that displays a143 * series of elements and also provides for the file accepting writes that have144 * some arbitrary effect.145 *146 * The functions in the @ops table are used to iterate over items to be147 * presented and extract the readable content using the seq_file interface.148 *149 * The @write function is called with the data copied into a kernel space150 * scratch buffer and has a NUL appended for convenience. The buffer may be151 * modified by the @write function. @write should return 0 on success.152 *153 * The @data value is accessible from the @show and @write functions by calling154 * pde_data() on the file inode. The network namespace must be accessed by155 * calling seq_file_net() on the seq_file struct.156 */157struct proc_dir_entry *proc_create_net_data_write(const char *name, umode_t mode,158 struct proc_dir_entry *parent,159 const struct seq_operations *ops,160 proc_write_t write,161 unsigned int state_size, void *data)162{163 struct proc_dir_entry *p;164 165 p = proc_create_reg(name, mode, &parent, data);166 if (!p)167 return NULL;168 pde_force_lookup(p);169 p->proc_ops = &proc_net_seq_ops;170 p->seq_ops = ops;171 p->state_size = state_size;172 p->write = write;173 return proc_register(parent, p);174}175EXPORT_SYMBOL_GPL(proc_create_net_data_write);176 177static int single_open_net(struct inode *inode, struct file *file)178{179 struct proc_dir_entry *de = PDE(inode);180 struct net *net;181 int err;182 183 net = get_proc_net(inode);184 if (!net)185 return -ENXIO;186 187 err = single_open(file, de->single_show, net);188 if (err)189 put_net(net);190 return err;191}192 193static int single_release_net(struct inode *ino, struct file *f)194{195 struct seq_file *seq = f->private_data;196 put_net(seq->private);197 return single_release(ino, f);198}199 200static const struct proc_ops proc_net_single_ops = {201 .proc_open = single_open_net,202 .proc_read = seq_read,203 .proc_write = proc_simple_write,204 .proc_lseek = seq_lseek,205 .proc_release = single_release_net,206};207 208struct proc_dir_entry *proc_create_net_single(const char *name, umode_t mode,209 struct proc_dir_entry *parent,210 int (*show)(struct seq_file *, void *), void *data)211{212 struct proc_dir_entry *p;213 214 p = proc_create_reg(name, mode, &parent, data);215 if (!p)216 return NULL;217 pde_force_lookup(p);218 p->proc_ops = &proc_net_single_ops;219 p->single_show = show;220 return proc_register(parent, p);221}222EXPORT_SYMBOL_GPL(proc_create_net_single);223 224/**225 * proc_create_net_single_write - Create a writable net_ns-specific proc file226 * @name: The name of the file.227 * @mode: The file's access mode.228 * @parent: The parent directory in which to create.229 * @show: The seqfile show method with which to read the file.230 * @write: The write method with which to 'modify' the file.231 * @data: Data for retrieval by pde_data().232 *233 * Create a network-namespaced proc file in the @parent directory with the234 * specified @name and @mode that allows reading of a file that displays a235 * single element rather than a series and also provides for the file accepting236 * writes that have some arbitrary effect.237 *238 * The @show function is called to extract the readable content via the239 * seq_file interface.240 *241 * The @write function is called with the data copied into a kernel space242 * scratch buffer and has a NUL appended for convenience. The buffer may be243 * modified by the @write function. @write should return 0 on success.244 *245 * The @data value is accessible from the @show and @write functions by calling246 * pde_data() on the file inode. The network namespace must be accessed by247 * calling seq_file_single_net() on the seq_file struct.248 */249struct proc_dir_entry *proc_create_net_single_write(const char *name, umode_t mode,250 struct proc_dir_entry *parent,251 int (*show)(struct seq_file *, void *),252 proc_write_t write,253 void *data)254{255 struct proc_dir_entry *p;256 257 p = proc_create_reg(name, mode, &parent, data);258 if (!p)259 return NULL;260 pde_force_lookup(p);261 p->proc_ops = &proc_net_single_ops;262 p->single_show = show;263 p->write = write;264 return proc_register(parent, p);265}266EXPORT_SYMBOL_GPL(proc_create_net_single_write);267 268static struct net *get_proc_task_net(struct inode *dir)269{270 struct task_struct *task;271 struct nsproxy *ns;272 struct net *net = NULL;273 274 rcu_read_lock();275 task = pid_task(proc_pid(dir), PIDTYPE_PID);276 if (task != NULL) {277 task_lock(task);278 ns = task->nsproxy;279 if (ns != NULL)280 net = get_net(ns->net_ns);281 task_unlock(task);282 }283 rcu_read_unlock();284 285 return net;286}287 288static struct dentry *proc_tgid_net_lookup(struct inode *dir,289 struct dentry *dentry, unsigned int flags)290{291 struct dentry *de;292 struct net *net;293 294 de = ERR_PTR(-ENOENT);295 net = get_proc_task_net(dir);296 if (net != NULL) {297 de = proc_lookup_de(dir, dentry, net->proc_net);298 put_net(net);299 }300 return de;301}302 303static int proc_tgid_net_getattr(struct mnt_idmap *idmap,304 const struct path *path, struct kstat *stat,305 u32 request_mask, unsigned int query_flags)306{307 struct inode *inode = d_inode(path->dentry);308 struct net *net;309 310 net = get_proc_task_net(inode);311 312 generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);313 314 if (net != NULL) {315 stat->nlink = net->proc_net->nlink;316 put_net(net);317 }318 319 return 0;320}321 322const struct inode_operations proc_net_inode_operations = {323 .lookup = proc_tgid_net_lookup,324 .getattr = proc_tgid_net_getattr,325 .setattr = proc_setattr,326};327 328static int proc_tgid_net_readdir(struct file *file, struct dir_context *ctx)329{330 int ret;331 struct net *net;332 333 ret = -EINVAL;334 net = get_proc_task_net(file_inode(file));335 if (net != NULL) {336 ret = proc_readdir_de(file, ctx, net->proc_net);337 put_net(net);338 }339 return ret;340}341 342const struct file_operations proc_net_operations = {343 .llseek = generic_file_llseek,344 .read = generic_read_dir,345 .iterate_shared = proc_tgid_net_readdir,346};347 348static __net_init int proc_net_ns_init(struct net *net)349{350 struct proc_dir_entry *netd, *net_statd;351 kuid_t uid;352 kgid_t gid;353 int err;354 355 /*356 * This PDE acts only as an anchor for /proc/${pid}/net hierarchy.357 * Corresponding inode (PDE(inode) == net->proc_net) is never358 * instantiated therefore blanket zeroing is fine.359 * net->proc_net_stat inode is instantiated normally.360 */361 err = -ENOMEM;362 netd = kmem_cache_zalloc(proc_dir_entry_cache, GFP_KERNEL);363 if (!netd)364 goto out;365 366 netd->subdir = RB_ROOT;367 netd->data = net;368 netd->nlink = 2;369 netd->namelen = 3;370 netd->parent = &proc_root;371 netd->name = netd->inline_name;372 memcpy(netd->name, "net", 4);373 374 uid = make_kuid(net->user_ns, 0);375 if (!uid_valid(uid))376 uid = netd->uid;377 378 gid = make_kgid(net->user_ns, 0);379 if (!gid_valid(gid))380 gid = netd->gid;381 382 proc_set_user(netd, uid, gid);383 384 /* Seed dentry revalidation for /proc/${pid}/net */385 pde_force_lookup(netd);386 387 err = -EEXIST;388 net_statd = proc_net_mkdir(net, "stat", netd);389 if (!net_statd)390 goto free_net;391 392 net->proc_net = netd;393 net->proc_net_stat = net_statd;394 return 0;395 396free_net:397 pde_free(netd);398out:399 return err;400}401 402static __net_exit void proc_net_ns_exit(struct net *net)403{404 remove_proc_entry("stat", net->proc_net);405 pde_free(net->proc_net);406}407 408static struct pernet_operations __net_initdata proc_net_ns_ops = {409 .init = proc_net_ns_init,410 .exit = proc_net_ns_exit,411};412 413int __init proc_net_init(void)414{415 proc_symlink("net", NULL, "self/net");416 417 return register_pernet_subsys(&proc_net_ns_ops);418}419