blob: 030250c27d70c4c182016c19399e45f929b7b53c [file] [log] [blame]
Eric W. Biederman6b4e3062010-03-07 16:41:34 -08001#include <linux/proc_fs.h>
2#include <linux/nsproxy.h>
3#include <linux/sched.h>
4#include <linux/ptrace.h>
5#include <linux/fs_struct.h>
6#include <linux/mount.h>
7#include <linux/path.h>
8#include <linux/namei.h>
9#include <linux/file.h>
10#include <linux/utsname.h>
11#include <net/net_namespace.h>
Eric W. Biederman6b4e3062010-03-07 16:41:34 -080012#include <linux/ipc_namespace.h>
13#include <linux/pid_namespace.h>
Eric W. Biedermancde19752012-07-26 06:24:06 -070014#include <linux/user_namespace.h>
Eric W. Biederman6b4e3062010-03-07 16:41:34 -080015#include "internal.h"
16
17
18static const struct proc_ns_operations *ns_entries[] = {
Eric W. Biederman13b6f572010-03-07 18:14:23 -080019#ifdef CONFIG_NET_NS
20 &netns_operations,
21#endif
Eric W. Biederman34482e82010-03-07 18:43:27 -080022#ifdef CONFIG_UTS_NS
23 &utsns_operations,
24#endif
Eric W. Biedermana00eaf12010-03-07 18:48:39 -080025#ifdef CONFIG_IPC_NS
26 &ipcns_operations,
27#endif
Eric W. Biederman57e83912010-03-07 18:17:03 -080028#ifdef CONFIG_PID_NS
29 &pidns_operations,
30#endif
Eric W. Biedermancde19752012-07-26 06:24:06 -070031#ifdef CONFIG_USER_NS
32 &userns_operations,
33#endif
Eric W. Biederman8823c072010-03-07 18:49:36 -080034 &mntns_operations,
Eric W. Biederman6b4e3062010-03-07 16:41:34 -080035};
36
37static const struct file_operations ns_file_operations = {
38 .llseek = no_llseek,
39};
40
41static struct dentry *proc_ns_instantiate(struct inode *dir,
42 struct dentry *dentry, struct task_struct *task, const void *ptr)
43{
44 const struct proc_ns_operations *ns_ops = ptr;
45 struct inode *inode;
46 struct proc_inode *ei;
47 struct dentry *error = ERR_PTR(-ENOENT);
Eric W. Biederman79392532011-06-15 12:47:04 -070048 void *ns;
Eric W. Biederman6b4e3062010-03-07 16:41:34 -080049
50 inode = proc_pid_make_inode(dir->i_sb, task);
51 if (!inode)
52 goto out;
53
Eric W. Biederman79392532011-06-15 12:47:04 -070054 ns = ns_ops->get(task);
55 if (!ns)
56 goto out_iput;
57
Eric W. Biederman6b4e3062010-03-07 16:41:34 -080058 ei = PROC_I(inode);
59 inode->i_mode = S_IFREG|S_IRUSR;
60 inode->i_fop = &ns_file_operations;
61 ei->ns_ops = ns_ops;
Eric W. Biederman79392532011-06-15 12:47:04 -070062 ei->ns = ns;
Eric W. Biederman6b4e3062010-03-07 16:41:34 -080063
Pravin B Shelar1b26c9b2012-03-23 15:02:55 -070064 d_set_d_op(dentry, &pid_dentry_operations);
Eric W. Biederman6b4e3062010-03-07 16:41:34 -080065 d_add(dentry, inode);
66 /* Close the race of the process dying before we return the dentry */
Al Viro0b728e12012-06-10 16:03:43 -040067 if (pid_revalidate(dentry, 0))
Eric W. Biederman6b4e3062010-03-07 16:41:34 -080068 error = NULL;
69out:
70 return error;
71out_iput:
72 iput(inode);
73 goto out;
74}
75
76static int proc_ns_fill_cache(struct file *filp, void *dirent,
77 filldir_t filldir, struct task_struct *task,
78 const struct proc_ns_operations *ops)
79{
80 return proc_fill_cache(filp, dirent, filldir,
81 ops->name, strlen(ops->name),
82 proc_ns_instantiate, task, ops);
83}
84
85static int proc_ns_dir_readdir(struct file *filp, void *dirent,
86 filldir_t filldir)
87{
88 int i;
89 struct dentry *dentry = filp->f_path.dentry;
90 struct inode *inode = dentry->d_inode;
91 struct task_struct *task = get_proc_task(inode);
92 const struct proc_ns_operations **entry, **last;
93 ino_t ino;
94 int ret;
95
96 ret = -ENOENT;
97 if (!task)
98 goto out_no_task;
99
100 ret = -EPERM;
101 if (!ptrace_may_access(task, PTRACE_MODE_READ))
102 goto out;
103
104 ret = 0;
105 i = filp->f_pos;
106 switch (i) {
107 case 0:
108 ino = inode->i_ino;
109 if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
110 goto out;
111 i++;
112 filp->f_pos++;
113 /* fall through */
114 case 1:
115 ino = parent_ino(dentry);
116 if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
117 goto out;
118 i++;
119 filp->f_pos++;
120 /* fall through */
121 default:
122 i -= 2;
123 if (i >= ARRAY_SIZE(ns_entries)) {
124 ret = 1;
125 goto out;
126 }
127 entry = ns_entries + i;
128 last = &ns_entries[ARRAY_SIZE(ns_entries) - 1];
129 while (entry <= last) {
130 if (proc_ns_fill_cache(filp, dirent, filldir,
131 task, *entry) < 0)
132 goto out;
133 filp->f_pos++;
134 entry++;
135 }
136 }
137
138 ret = 1;
139out:
140 put_task_struct(task);
141out_no_task:
142 return ret;
143}
144
145const struct file_operations proc_ns_dir_operations = {
146 .read = generic_read_dir,
147 .readdir = proc_ns_dir_readdir,
148};
149
150static struct dentry *proc_ns_dir_lookup(struct inode *dir,
Al Viro00cd8dd2012-06-10 17:13:09 -0400151 struct dentry *dentry, unsigned int flags)
Eric W. Biederman6b4e3062010-03-07 16:41:34 -0800152{
153 struct dentry *error;
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
158 error = ERR_PTR(-ENOENT);
159
160 if (!task)
161 goto out_no_task;
162
163 error = ERR_PTR(-EPERM);
164 if (!ptrace_may_access(task, PTRACE_MODE_READ))
165 goto out;
166
Andrew Morton4c619aa2012-03-28 14:42:52 -0700167 last = &ns_entries[ARRAY_SIZE(ns_entries)];
168 for (entry = ns_entries; entry < last; entry++) {
Eric W. Biederman6b4e3062010-03-07 16:41:34 -0800169 if (strlen((*entry)->name) != len)
170 continue;
171 if (!memcmp(dentry->d_name.name, (*entry)->name, len))
172 break;
173 }
Eric W. Biederman62ca24b2011-05-11 15:42:08 -0700174 error = ERR_PTR(-ENOENT);
Andrew Morton4c619aa2012-03-28 14:42:52 -0700175 if (entry == last)
Eric W. Biederman6b4e3062010-03-07 16:41:34 -0800176 goto out;
177
178 error = proc_ns_instantiate(dir, dentry, task, *entry);
179out:
180 put_task_struct(task);
181out_no_task:
182 return error;
183}
184
185const struct inode_operations proc_ns_dir_inode_operations = {
186 .lookup = proc_ns_dir_lookup,
187 .getattr = pid_getattr,
188 .setattr = proc_setattr,
189};
190
191struct file *proc_ns_fget(int fd)
192{
193 struct file *file;
194
195 file = fget(fd);
196 if (!file)
197 return ERR_PTR(-EBADF);
198
199 if (file->f_op != &ns_file_operations)
200 goto out_invalid;
201
202 return file;
203
204out_invalid:
205 fput(file);
206 return ERR_PTR(-EINVAL);
207}
208
Eric W. Biederman8823c072010-03-07 18:49:36 -0800209bool proc_ns_inode(struct inode *inode)
210{
211 return inode->i_fop == &ns_file_operations;
212}