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