at master 4.4 kB view raw
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 *const 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#ifdef CONFIG_TIME_NS 37 &timens_operations, 38 &timens_for_children_operations, 39#endif 40}; 41 42static const char *proc_ns_get_link(struct dentry *dentry, 43 struct inode *inode, 44 struct delayed_call *done) 45{ 46 const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops; 47 struct task_struct *task; 48 struct path ns_path; 49 int error = -EACCES; 50 51 if (!dentry) 52 return ERR_PTR(-ECHILD); 53 54 task = get_proc_task(inode); 55 if (!task) 56 return ERR_PTR(-EACCES); 57 58 if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) 59 goto out; 60 61 error = ns_get_path(&ns_path, task, ns_ops); 62 if (error) 63 goto out; 64 65 error = nd_jump_link(&ns_path); 66out: 67 put_task_struct(task); 68 return ERR_PTR(error); 69} 70 71static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int buflen) 72{ 73 struct inode *inode = d_inode(dentry); 74 const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops; 75 struct task_struct *task; 76 char name[50]; 77 int res = -EACCES; 78 79 task = get_proc_task(inode); 80 if (!task) 81 return res; 82 83 if (ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) { 84 res = ns_get_name(name, sizeof(name), task, ns_ops); 85 if (res >= 0) 86 res = readlink_copy(buffer, buflen, name, strlen(name)); 87 } 88 put_task_struct(task); 89 return res; 90} 91 92static const struct inode_operations proc_ns_link_inode_operations = { 93 .readlink = proc_ns_readlink, 94 .get_link = proc_ns_get_link, 95 .setattr = proc_setattr, 96}; 97 98static struct dentry *proc_ns_instantiate(struct dentry *dentry, 99 struct task_struct *task, const void *ptr) 100{ 101 const struct proc_ns_operations *ns_ops = ptr; 102 struct inode *inode; 103 struct proc_inode *ei; 104 105 inode = proc_pid_make_inode(dentry->d_sb, task, S_IFLNK | S_IRWXUGO); 106 if (!inode) 107 return ERR_PTR(-ENOENT); 108 109 ei = PROC_I(inode); 110 inode->i_op = &proc_ns_link_inode_operations; 111 ei->ns_ops = ns_ops; 112 pid_update_inode(task, inode); 113 114 return d_splice_alias_ops(inode, dentry, &pid_dentry_operations); 115} 116 117static int proc_ns_dir_readdir(struct file *file, struct dir_context *ctx) 118{ 119 struct task_struct *task = get_proc_task(file_inode(file)); 120 const struct proc_ns_operations *const *entry, *const *last; 121 122 if (!task) 123 return -ENOENT; 124 125 if (!dir_emit_dots(file, ctx)) 126 goto out; 127 if (ctx->pos >= 2 + ARRAY_SIZE(ns_entries)) 128 goto out; 129 entry = ns_entries + (ctx->pos - 2); 130 last = &ns_entries[ARRAY_SIZE(ns_entries) - 1]; 131 while (entry <= last) { 132 const struct proc_ns_operations *ops = *entry; 133 if (!proc_fill_cache(file, ctx, ops->name, strlen(ops->name), 134 proc_ns_instantiate, task, ops)) 135 break; 136 ctx->pos++; 137 entry++; 138 } 139out: 140 put_task_struct(task); 141 return 0; 142} 143 144const struct file_operations proc_ns_dir_operations = { 145 .read = generic_read_dir, 146 .iterate_shared = proc_ns_dir_readdir, 147 .llseek = generic_file_llseek, 148}; 149 150static struct dentry *proc_ns_dir_lookup(struct inode *dir, 151 struct dentry *dentry, unsigned int flags) 152{ 153 struct task_struct *task = get_proc_task(dir); 154 const struct proc_ns_operations *const *entry, *const *last; 155 unsigned int len = dentry->d_name.len; 156 struct dentry *res = ERR_PTR(-ENOENT); 157 158 if (!task) 159 goto out_no_task; 160 161 last = &ns_entries[ARRAY_SIZE(ns_entries)]; 162 for (entry = ns_entries; entry < last; entry++) { 163 if (strlen((*entry)->name) != len) 164 continue; 165 if (!memcmp(dentry->d_name.name, (*entry)->name, len)) 166 break; 167 } 168 if (entry == last) 169 goto out; 170 171 res = proc_ns_instantiate(dentry, task, *entry); 172out: 173 put_task_struct(task); 174out_no_task: 175 return res; 176} 177 178const struct inode_operations proc_ns_dir_inode_operations = { 179 .lookup = proc_ns_dir_lookup, 180 .getattr = pid_getattr, 181 .setattr = proc_setattr, 182};