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