]>
Commit | Line | Data |
---|---|---|
6b4e306a EB |
1 | #include <linux/proc_fs.h> |
2 | #include <linux/nsproxy.h> | |
6b4e306a | 3 | #include <linux/ptrace.h> |
6b4e306a EB |
4 | #include <linux/namei.h> |
5 | #include <linux/file.h> | |
6 | #include <linux/utsname.h> | |
7 | #include <net/net_namespace.h> | |
6b4e306a EB |
8 | #include <linux/ipc_namespace.h> |
9 | #include <linux/pid_namespace.h> | |
cde1975b | 10 | #include <linux/user_namespace.h> |
6b4e306a EB |
11 | #include "internal.h" |
12 | ||
13 | ||
14 | static const struct proc_ns_operations *ns_entries[] = { | |
13b6f576 EB |
15 | #ifdef CONFIG_NET_NS |
16 | &netns_operations, | |
17 | #endif | |
34482e89 EB |
18 | #ifdef CONFIG_UTS_NS |
19 | &utsns_operations, | |
20 | #endif | |
a00eaf11 EB |
21 | #ifdef CONFIG_IPC_NS |
22 | &ipcns_operations, | |
23 | #endif | |
57e8391d EB |
24 | #ifdef CONFIG_PID_NS |
25 | &pidns_operations, | |
cde1975b EB |
26 | #endif |
27 | #ifdef CONFIG_USER_NS | |
28 | &userns_operations, | |
57e8391d | 29 | #endif |
8823c079 | 30 | &mntns_operations, |
6b4e306a EB |
31 | }; |
32 | ||
bf056bfa EB |
33 | static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd) |
34 | { | |
2b0143b5 | 35 | struct inode *inode = d_inode(dentry); |
3d3d35b1 | 36 | const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops; |
bf056bfa | 37 | struct task_struct *task; |
db04dc67 | 38 | struct path ns_path; |
bf056bfa EB |
39 | void *error = ERR_PTR(-EACCES); |
40 | ||
41 | task = get_proc_task(inode); | |
42 | if (!task) | |
e149ed2b | 43 | return error; |
bf056bfa | 44 | |
e149ed2b AV |
45 | if (ptrace_may_access(task, PTRACE_MODE_READ)) { |
46 | error = ns_get_path(&ns_path, task, ns_ops); | |
47 | if (!error) | |
48 | nd_jump_link(nd, &ns_path); | |
bf056bfa | 49 | } |
bf056bfa | 50 | put_task_struct(task); |
bf056bfa EB |
51 | return error; |
52 | } | |
53 | ||
54 | static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int buflen) | |
55 | { | |
2b0143b5 | 56 | struct inode *inode = d_inode(dentry); |
3d3d35b1 | 57 | const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops; |
bf056bfa | 58 | struct task_struct *task; |
bf056bfa | 59 | char name[50]; |
5d826c84 | 60 | int res = -EACCES; |
bf056bfa EB |
61 | |
62 | task = get_proc_task(inode); | |
63 | if (!task) | |
e149ed2b | 64 | return res; |
bf056bfa | 65 | |
e149ed2b AV |
66 | if (ptrace_may_access(task, PTRACE_MODE_READ)) { |
67 | res = ns_get_name(name, sizeof(name), task, ns_ops); | |
68 | if (res >= 0) | |
69 | res = readlink_copy(buffer, buflen, name); | |
70 | } | |
bf056bfa | 71 | put_task_struct(task); |
5d826c84 | 72 | return res; |
bf056bfa EB |
73 | } |
74 | ||
75 | static const struct inode_operations proc_ns_link_inode_operations = { | |
76 | .readlink = proc_ns_readlink, | |
77 | .follow_link = proc_ns_follow_link, | |
78 | .setattr = proc_setattr, | |
79 | }; | |
80 | ||
c52a47ac | 81 | static int proc_ns_instantiate(struct inode *dir, |
6b4e306a EB |
82 | struct dentry *dentry, struct task_struct *task, const void *ptr) |
83 | { | |
84 | const struct proc_ns_operations *ns_ops = ptr; | |
85 | struct inode *inode; | |
86 | struct proc_inode *ei; | |
6b4e306a EB |
87 | |
88 | inode = proc_pid_make_inode(dir->i_sb, task); | |
89 | if (!inode) | |
90 | goto out; | |
91 | ||
92 | ei = PROC_I(inode); | |
bf056bfa EB |
93 | inode->i_mode = S_IFLNK|S_IRWXUGO; |
94 | inode->i_op = &proc_ns_link_inode_operations; | |
3d3d35b1 | 95 | ei->ns_ops = ns_ops; |
6b4e306a | 96 | |
1b26c9b3 | 97 | d_set_d_op(dentry, &pid_dentry_operations); |
6b4e306a EB |
98 | d_add(dentry, inode); |
99 | /* Close the race of the process dying before we return the dentry */ | |
0b728e19 | 100 | if (pid_revalidate(dentry, 0)) |
c52a47ac | 101 | return 0; |
6b4e306a | 102 | out: |
c52a47ac | 103 | return -ENOENT; |
6b4e306a EB |
104 | } |
105 | ||
f0c3b509 | 106 | static int proc_ns_dir_readdir(struct file *file, struct dir_context *ctx) |
6b4e306a | 107 | { |
f0c3b509 | 108 | struct task_struct *task = get_proc_task(file_inode(file)); |
6b4e306a | 109 | const struct proc_ns_operations **entry, **last; |
6b4e306a | 110 | |
6b4e306a | 111 | if (!task) |
f0c3b509 | 112 | return -ENOENT; |
6b4e306a | 113 | |
f0c3b509 AV |
114 | if (!dir_emit_dots(file, ctx)) |
115 | goto out; | |
116 | if (ctx->pos >= 2 + ARRAY_SIZE(ns_entries)) | |
117 | goto out; | |
118 | entry = ns_entries + (ctx->pos - 2); | |
119 | last = &ns_entries[ARRAY_SIZE(ns_entries) - 1]; | |
120 | while (entry <= last) { | |
121 | const struct proc_ns_operations *ops = *entry; | |
122 | if (!proc_fill_cache(file, ctx, ops->name, strlen(ops->name), | |
123 | proc_ns_instantiate, task, ops)) | |
124 | break; | |
125 | ctx->pos++; | |
126 | entry++; | |
127 | } | |
6b4e306a EB |
128 | out: |
129 | put_task_struct(task); | |
f0c3b509 | 130 | return 0; |
6b4e306a EB |
131 | } |
132 | ||
133 | const struct file_operations proc_ns_dir_operations = { | |
134 | .read = generic_read_dir, | |
f0c3b509 | 135 | .iterate = proc_ns_dir_readdir, |
6b4e306a EB |
136 | }; |
137 | ||
138 | static struct dentry *proc_ns_dir_lookup(struct inode *dir, | |
00cd8dd3 | 139 | struct dentry *dentry, unsigned int flags) |
6b4e306a | 140 | { |
c52a47ac | 141 | int error; |
6b4e306a EB |
142 | struct task_struct *task = get_proc_task(dir); |
143 | const struct proc_ns_operations **entry, **last; | |
144 | unsigned int len = dentry->d_name.len; | |
145 | ||
c52a47ac | 146 | error = -ENOENT; |
6b4e306a EB |
147 | |
148 | if (!task) | |
149 | goto out_no_task; | |
150 | ||
4c619aa0 AM |
151 | last = &ns_entries[ARRAY_SIZE(ns_entries)]; |
152 | for (entry = ns_entries; entry < last; entry++) { | |
6b4e306a EB |
153 | if (strlen((*entry)->name) != len) |
154 | continue; | |
155 | if (!memcmp(dentry->d_name.name, (*entry)->name, len)) | |
156 | break; | |
157 | } | |
4c619aa0 | 158 | if (entry == last) |
6b4e306a EB |
159 | goto out; |
160 | ||
161 | error = proc_ns_instantiate(dir, dentry, task, *entry); | |
162 | out: | |
163 | put_task_struct(task); | |
164 | out_no_task: | |
c52a47ac | 165 | return ERR_PTR(error); |
6b4e306a EB |
166 | } |
167 | ||
168 | const struct inode_operations proc_ns_dir_inode_operations = { | |
169 | .lookup = proc_ns_dir_lookup, | |
170 | .getattr = pid_getattr, | |
171 | .setattr = proc_setattr, | |
172 | }; |