linux/fs/proc/namespaces.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/proc_fs.h>
   3#include <linux/nsproxy.h>
   4#include <linux/ptrace.h>
   5#include <linux/namei.h>
   6#include <linux/file.h>
   7#include <linux/utsname.h>
   8#include <net/net_namespace.h>
   9#include <linux/ipc_namespace.h>
  10#include <linux/pid_namespace.h>
  11#include <linux/user_namespace.h>
  12#include "internal.h"
  13
  14
  15static const struct proc_ns_operations *ns_entries[] = {
  16#ifdef CONFIG_NET_NS
  17        &netns_operations,
  18#endif
  19#ifdef CONFIG_UTS_NS
  20        &utsns_operations,
  21#endif
  22#ifdef CONFIG_IPC_NS
  23        &ipcns_operations,
  24#endif
  25#ifdef CONFIG_PID_NS
  26        &pidns_operations,
  27        &pidns_for_children_operations,
  28#endif
  29#ifdef CONFIG_USER_NS
  30        &userns_operations,
  31#endif
  32        &mntns_operations,
  33#ifdef CONFIG_CGROUPS
  34        &cgroupns_operations,
  35#endif
  36};
  37
  38static const char *proc_ns_get_link(struct dentry *dentry,
  39                                    struct inode *inode,
  40                                    struct delayed_call *done)
  41{
  42        const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops;
  43        struct task_struct *task;
  44        struct path ns_path;
  45        void *error = ERR_PTR(-EACCES);
  46
  47        if (!dentry)
  48                return ERR_PTR(-ECHILD);
  49
  50        task = get_proc_task(inode);
  51        if (!task)
  52                return error;
  53
  54        if (ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) {
  55                error = ns_get_path(&ns_path, task, ns_ops);
  56                if (!error)
  57                        nd_jump_link(&ns_path);
  58        }
  59        put_task_struct(task);
  60        return error;
  61}
  62
  63static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int buflen)
  64{
  65        struct inode *inode = d_inode(dentry);
  66        const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops;
  67        struct task_struct *task;
  68        char name[50];
  69        int res = -EACCES;
  70
  71        task = get_proc_task(inode);
  72        if (!task)
  73                return res;
  74
  75        if (ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) {
  76                res = ns_get_name(name, sizeof(name), task, ns_ops);
  77                if (res >= 0)
  78                        res = readlink_copy(buffer, buflen, name);
  79        }
  80        put_task_struct(task);
  81        return res;
  82}
  83
  84static const struct inode_operations proc_ns_link_inode_operations = {
  85        .readlink       = proc_ns_readlink,
  86        .get_link       = proc_ns_get_link,
  87        .setattr        = proc_setattr,
  88};
  89
  90static struct dentry *proc_ns_instantiate(struct dentry *dentry,
  91        struct task_struct *task, const void *ptr)
  92{
  93        const struct proc_ns_operations *ns_ops = ptr;
  94        struct inode *inode;
  95        struct proc_inode *ei;
  96
  97        inode = proc_pid_make_inode(dentry->d_sb, task, S_IFLNK | S_IRWXUGO);
  98        if (!inode)
  99                return ERR_PTR(-ENOENT);
 100
 101        ei = PROC_I(inode);
 102        inode->i_op = &proc_ns_link_inode_operations;
 103        ei->ns_ops = ns_ops;
 104        pid_update_inode(task, inode);
 105
 106        d_set_d_op(dentry, &pid_dentry_operations);
 107        return d_splice_alias(inode, dentry);
 108}
 109
 110static int proc_ns_dir_readdir(struct file *file, struct dir_context *ctx)
 111{
 112        struct task_struct *task = get_proc_task(file_inode(file));
 113        const struct proc_ns_operations **entry, **last;
 114
 115        if (!task)
 116                return -ENOENT;
 117
 118        if (!dir_emit_dots(file, ctx))
 119                goto out;
 120        if (ctx->pos >= 2 + ARRAY_SIZE(ns_entries))
 121                goto out;
 122        entry = ns_entries + (ctx->pos - 2);
 123        last = &ns_entries[ARRAY_SIZE(ns_entries) - 1];
 124        while (entry <= last) {
 125                const struct proc_ns_operations *ops = *entry;
 126                if (!proc_fill_cache(file, ctx, ops->name, strlen(ops->name),
 127                                     proc_ns_instantiate, task, ops))
 128                        break;
 129                ctx->pos++;
 130                entry++;
 131        }
 132out:
 133        put_task_struct(task);
 134        return 0;
 135}
 136
 137const struct file_operations proc_ns_dir_operations = {
 138        .read           = generic_read_dir,
 139        .iterate_shared = proc_ns_dir_readdir,
 140        .llseek         = generic_file_llseek,
 141};
 142
 143static struct dentry *proc_ns_dir_lookup(struct inode *dir,
 144                                struct dentry *dentry, unsigned int flags)
 145{
 146        struct task_struct *task = get_proc_task(dir);
 147        const struct proc_ns_operations **entry, **last;
 148        unsigned int len = dentry->d_name.len;
 149        struct dentry *res = ERR_PTR(-ENOENT);
 150
 151        if (!task)
 152                goto out_no_task;
 153
 154        last = &ns_entries[ARRAY_SIZE(ns_entries)];
 155        for (entry = ns_entries; entry < last; entry++) {
 156                if (strlen((*entry)->name) != len)
 157                        continue;
 158                if (!memcmp(dentry->d_name.name, (*entry)->name, len))
 159                        break;
 160        }
 161        if (entry == last)
 162                goto out;
 163
 164        res = proc_ns_instantiate(dentry, task, *entry);
 165out:
 166        put_task_struct(task);
 167out_no_task:
 168        return res;
 169}
 170
 171const struct inode_operations proc_ns_dir_inode_operations = {
 172        .lookup         = proc_ns_dir_lookup,
 173        .getattr        = pid_getattr,
 174        .setattr        = proc_setattr,
 175};
 176