xref: /OK3568_Linux_fs/kernel/fs/proc/namespaces.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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