184 lines · c
1// SPDX-License-Identifier: GPL-2.02#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_NS17 &netns_operations,18#endif19#ifdef CONFIG_UTS_NS20 &utsns_operations,21#endif22#ifdef CONFIG_IPC_NS23 &ipcns_operations,24#endif25#ifdef CONFIG_PID_NS26 &pidns_operations,27 &pidns_for_children_operations,28#endif29#ifdef CONFIG_USER_NS30 &userns_operations,31#endif32 &mntns_operations,33#ifdef CONFIG_CGROUPS34 &cgroupns_operations,35#endif36#ifdef CONFIG_TIME_NS37 &timens_operations,38 &timens_for_children_operations,39#endif40};41 42static HWJS_SUSPENDS 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 HWJS_SUSPENDS 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);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 HWJS_SUSPENDS 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 d_set_d_op(dentry, &pid_dentry_operations);115 return d_splice_alias(inode, dentry);116}117 118static HWJS_SUSPENDS int proc_ns_dir_readdir(struct file *file, struct dir_context *ctx)119{120 struct task_struct *task = get_proc_task(file_inode(file));121 const struct proc_ns_operations **entry, **last;122 123 if (!task)124 return -ENOENT;125 126 if (!dir_emit_dots(file, ctx))127 goto out;128 if (ctx->pos >= 2 + ARRAY_SIZE(ns_entries))129 goto out;130 entry = ns_entries + (ctx->pos - 2);131 last = &ns_entries[ARRAY_SIZE(ns_entries) - 1];132 while (entry <= last) {133 const struct proc_ns_operations *ops = *entry;134 if (!proc_fill_cache(file, ctx, ops->name, strlen(ops->name),135 proc_ns_instantiate, task, ops))136 break;137 ctx->pos++;138 entry++;139 }140out:141 put_task_struct(task);142 return 0;143}144 145const struct file_operations proc_ns_dir_operations = {146 .read = generic_read_dir,147 .iterate_shared = proc_ns_dir_readdir,148 .llseek = generic_file_llseek,149};150 151static HWJS_SUSPENDS struct dentry *proc_ns_dir_lookup(struct inode *dir,152 struct dentry *dentry, unsigned int flags)153{154 struct task_struct *task = get_proc_task(dir);155 const struct proc_ns_operations **entry, **last;156 unsigned int len = dentry->d_name.len;157 struct dentry *res = ERR_PTR(-ENOENT);158 159 if (!task)160 goto out_no_task;161 162 last = &ns_entries[ARRAY_SIZE(ns_entries)];163 for (entry = ns_entries; entry < last; entry++) {164 if (strlen((*entry)->name) != len)165 continue;166 if (!memcmp(dentry->d_name.name, (*entry)->name, len))167 break;168 }169 if (entry == last)170 goto out;171 172 res = proc_ns_instantiate(dentry, task, *entry);173out:174 put_task_struct(task);175out_no_task:176 return res;177}178 179const struct inode_operations proc_ns_dir_inode_operations = {180 .lookup = proc_ns_dir_lookup,181 .getattr = pid_getattr,182 .setattr = proc_setattr,183};184