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