Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0
2 : #include <linux/sched/signal.h>
3 : #include <linux/errno.h>
4 : #include <linux/dcache.h>
5 : #include <linux/path.h>
6 : #include <linux/fdtable.h>
7 : #include <linux/namei.h>
8 : #include <linux/pid.h>
9 : #include <linux/ptrace.h>
10 : #include <linux/security.h>
11 : #include <linux/file.h>
12 : #include <linux/seq_file.h>
13 : #include <linux/fs.h>
14 :
15 : #include <linux/proc_fs.h>
16 :
17 : #include "../mount.h"
18 : #include "internal.h"
19 : #include "fd.h"
20 :
21 0 : static int seq_show(struct seq_file *m, void *v)
22 : {
23 0 : struct files_struct *files = NULL;
24 0 : int f_flags = 0, ret = -ENOENT;
25 0 : struct file *file = NULL;
26 : struct task_struct *task;
27 :
28 0 : task = get_proc_task(m->private);
29 0 : if (!task)
30 : return -ENOENT;
31 :
32 : task_lock(task);
33 0 : files = task->files;
34 0 : if (files) {
35 0 : unsigned int fd = proc_fd(m->private);
36 :
37 0 : spin_lock(&files->file_lock);
38 0 : file = files_lookup_fd_locked(files, fd);
39 0 : if (file) {
40 0 : struct fdtable *fdt = files_fdtable(files);
41 :
42 0 : f_flags = file->f_flags;
43 0 : if (close_on_exec(fd, fdt))
44 0 : f_flags |= O_CLOEXEC;
45 :
46 0 : get_file(file);
47 0 : ret = 0;
48 : }
49 0 : spin_unlock(&files->file_lock);
50 : }
51 : task_unlock(task);
52 0 : put_task_struct(task);
53 :
54 0 : if (ret)
55 : return ret;
56 :
57 0 : seq_printf(m, "pos:\t%lli\nflags:\t0%o\nmnt_id:\t%i\nino:\t%lu\n",
58 0 : (long long)file->f_pos, f_flags,
59 0 : real_mount(file->f_path.mnt)->mnt_id,
60 0 : file_inode(file)->i_ino);
61 :
62 : /* show_fd_locks() never deferences files so a stale value is safe */
63 0 : show_fd_locks(m, file, files);
64 0 : if (seq_has_overflowed(m))
65 : goto out;
66 :
67 0 : if (file->f_op->show_fdinfo)
68 0 : file->f_op->show_fdinfo(m, file);
69 :
70 : out:
71 0 : fput(file);
72 0 : return 0;
73 : }
74 :
75 0 : static int proc_fdinfo_access_allowed(struct inode *inode)
76 : {
77 0 : bool allowed = false;
78 0 : struct task_struct *task = get_proc_task(inode);
79 :
80 0 : if (!task)
81 : return -ESRCH;
82 :
83 0 : allowed = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);
84 0 : put_task_struct(task);
85 :
86 0 : if (!allowed)
87 : return -EACCES;
88 :
89 0 : return 0;
90 : }
91 :
92 0 : static int seq_fdinfo_open(struct inode *inode, struct file *file)
93 : {
94 0 : int ret = proc_fdinfo_access_allowed(inode);
95 :
96 0 : if (ret)
97 : return ret;
98 :
99 0 : return single_open(file, seq_show, inode);
100 : }
101 :
102 : static const struct file_operations proc_fdinfo_file_operations = {
103 : .open = seq_fdinfo_open,
104 : .read = seq_read,
105 : .llseek = seq_lseek,
106 : .release = single_release,
107 : };
108 :
109 : static bool tid_fd_mode(struct task_struct *task, unsigned fd, fmode_t *mode)
110 : {
111 : struct file *file;
112 :
113 : rcu_read_lock();
114 0 : file = task_lookup_fd_rcu(task, fd);
115 0 : if (file)
116 0 : *mode = file->f_mode;
117 : rcu_read_unlock();
118 : return !!file;
119 : }
120 :
121 0 : static void tid_fd_update_inode(struct task_struct *task, struct inode *inode,
122 : fmode_t f_mode)
123 : {
124 0 : task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid);
125 :
126 0 : if (S_ISLNK(inode->i_mode)) {
127 0 : unsigned i_mode = S_IFLNK;
128 0 : if (f_mode & FMODE_READ)
129 0 : i_mode |= S_IRUSR | S_IXUSR;
130 0 : if (f_mode & FMODE_WRITE)
131 0 : i_mode |= S_IWUSR | S_IXUSR;
132 0 : inode->i_mode = i_mode;
133 : }
134 0 : security_task_to_inode(task, inode);
135 0 : }
136 :
137 0 : static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags)
138 : {
139 : struct task_struct *task;
140 : struct inode *inode;
141 : unsigned int fd;
142 :
143 0 : if (flags & LOOKUP_RCU)
144 : return -ECHILD;
145 :
146 0 : inode = d_inode(dentry);
147 0 : task = get_proc_task(inode);
148 0 : fd = proc_fd(inode);
149 :
150 0 : if (task) {
151 : fmode_t f_mode;
152 0 : if (tid_fd_mode(task, fd, &f_mode)) {
153 0 : tid_fd_update_inode(task, inode, f_mode);
154 0 : put_task_struct(task);
155 0 : return 1;
156 : }
157 0 : put_task_struct(task);
158 : }
159 : return 0;
160 : }
161 :
162 : static const struct dentry_operations tid_fd_dentry_operations = {
163 : .d_revalidate = tid_fd_revalidate,
164 : .d_delete = pid_delete_dentry,
165 : };
166 :
167 0 : static int proc_fd_link(struct dentry *dentry, struct path *path)
168 : {
169 : struct task_struct *task;
170 0 : int ret = -ENOENT;
171 :
172 0 : task = get_proc_task(d_inode(dentry));
173 0 : if (task) {
174 0 : unsigned int fd = proc_fd(d_inode(dentry));
175 : struct file *fd_file;
176 :
177 0 : fd_file = fget_task(task, fd);
178 0 : if (fd_file) {
179 0 : *path = fd_file->f_path;
180 0 : path_get(&fd_file->f_path);
181 0 : ret = 0;
182 0 : fput(fd_file);
183 : }
184 0 : put_task_struct(task);
185 : }
186 :
187 0 : return ret;
188 : }
189 :
190 : struct fd_data {
191 : fmode_t mode;
192 : unsigned fd;
193 : };
194 :
195 0 : static struct dentry *proc_fd_instantiate(struct dentry *dentry,
196 : struct task_struct *task, const void *ptr)
197 : {
198 0 : const struct fd_data *data = ptr;
199 : struct proc_inode *ei;
200 : struct inode *inode;
201 :
202 0 : inode = proc_pid_make_inode(dentry->d_sb, task, S_IFLNK);
203 0 : if (!inode)
204 : return ERR_PTR(-ENOENT);
205 :
206 0 : ei = PROC_I(inode);
207 0 : ei->fd = data->fd;
208 :
209 0 : inode->i_op = &proc_pid_link_inode_operations;
210 0 : inode->i_size = 64;
211 :
212 0 : ei->op.proc_get_link = proc_fd_link;
213 0 : tid_fd_update_inode(task, inode, data->mode);
214 :
215 0 : d_set_d_op(dentry, &tid_fd_dentry_operations);
216 0 : return d_splice_alias(inode, dentry);
217 : }
218 :
219 0 : static struct dentry *proc_lookupfd_common(struct inode *dir,
220 : struct dentry *dentry,
221 : instantiate_t instantiate)
222 : {
223 0 : struct task_struct *task = get_proc_task(dir);
224 0 : struct fd_data data = {.fd = name_to_int(&dentry->d_name)};
225 0 : struct dentry *result = ERR_PTR(-ENOENT);
226 :
227 0 : if (!task)
228 : goto out_no_task;
229 0 : if (data.fd == ~0U)
230 : goto out;
231 0 : if (!tid_fd_mode(task, data.fd, &data.mode))
232 : goto out;
233 :
234 0 : result = instantiate(dentry, task, &data);
235 : out:
236 0 : put_task_struct(task);
237 : out_no_task:
238 0 : return result;
239 : }
240 :
241 0 : static int proc_readfd_common(struct file *file, struct dir_context *ctx,
242 : instantiate_t instantiate)
243 : {
244 0 : struct task_struct *p = get_proc_task(file_inode(file));
245 : unsigned int fd;
246 :
247 0 : if (!p)
248 : return -ENOENT;
249 :
250 0 : if (!dir_emit_dots(file, ctx))
251 : goto out;
252 :
253 : rcu_read_lock();
254 0 : for (fd = ctx->pos - 2;; fd++) {
255 : struct file *f;
256 : struct fd_data data;
257 : char name[10 + 1];
258 : unsigned int len;
259 :
260 0 : f = task_lookup_next_fd_rcu(p, &fd);
261 0 : ctx->pos = fd + 2LL;
262 0 : if (!f)
263 : break;
264 0 : data.mode = f->f_mode;
265 : rcu_read_unlock();
266 0 : data.fd = fd;
267 :
268 0 : len = snprintf(name, sizeof(name), "%u", fd);
269 0 : if (!proc_fill_cache(file, ctx,
270 : name, len, instantiate, p,
271 : &data))
272 : goto out;
273 0 : cond_resched();
274 : rcu_read_lock();
275 : }
276 : rcu_read_unlock();
277 : out:
278 0 : put_task_struct(p);
279 0 : return 0;
280 : }
281 :
282 0 : static int proc_readfd(struct file *file, struct dir_context *ctx)
283 : {
284 0 : return proc_readfd_common(file, ctx, proc_fd_instantiate);
285 : }
286 :
287 : const struct file_operations proc_fd_operations = {
288 : .read = generic_read_dir,
289 : .iterate_shared = proc_readfd,
290 : .llseek = generic_file_llseek,
291 : };
292 :
293 0 : static struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry,
294 : unsigned int flags)
295 : {
296 0 : return proc_lookupfd_common(dir, dentry, proc_fd_instantiate);
297 : }
298 :
299 : /*
300 : * /proc/pid/fd needs a special permission handler so that a process can still
301 : * access /proc/self/fd after it has executed a setuid().
302 : */
303 0 : int proc_fd_permission(struct user_namespace *mnt_userns,
304 : struct inode *inode, int mask)
305 : {
306 : struct task_struct *p;
307 : int rv;
308 :
309 0 : rv = generic_permission(&init_user_ns, inode, mask);
310 0 : if (rv == 0)
311 : return rv;
312 :
313 : rcu_read_lock();
314 0 : p = pid_task(proc_pid(inode), PIDTYPE_PID);
315 0 : if (p && same_thread_group(p, current))
316 0 : rv = 0;
317 : rcu_read_unlock();
318 :
319 0 : return rv;
320 : }
321 :
322 : const struct inode_operations proc_fd_inode_operations = {
323 : .lookup = proc_lookupfd,
324 : .permission = proc_fd_permission,
325 : .setattr = proc_setattr,
326 : };
327 :
328 0 : static struct dentry *proc_fdinfo_instantiate(struct dentry *dentry,
329 : struct task_struct *task, const void *ptr)
330 : {
331 0 : const struct fd_data *data = ptr;
332 : struct proc_inode *ei;
333 : struct inode *inode;
334 :
335 0 : inode = proc_pid_make_inode(dentry->d_sb, task, S_IFREG | S_IRUGO);
336 0 : if (!inode)
337 : return ERR_PTR(-ENOENT);
338 :
339 0 : ei = PROC_I(inode);
340 0 : ei->fd = data->fd;
341 :
342 0 : inode->i_fop = &proc_fdinfo_file_operations;
343 0 : tid_fd_update_inode(task, inode, 0);
344 :
345 0 : d_set_d_op(dentry, &tid_fd_dentry_operations);
346 0 : return d_splice_alias(inode, dentry);
347 : }
348 :
349 : static struct dentry *
350 0 : proc_lookupfdinfo(struct inode *dir, struct dentry *dentry, unsigned int flags)
351 : {
352 0 : return proc_lookupfd_common(dir, dentry, proc_fdinfo_instantiate);
353 : }
354 :
355 0 : static int proc_readfdinfo(struct file *file, struct dir_context *ctx)
356 : {
357 0 : return proc_readfd_common(file, ctx,
358 : proc_fdinfo_instantiate);
359 : }
360 :
361 0 : static int proc_open_fdinfo(struct inode *inode, struct file *file)
362 : {
363 0 : int ret = proc_fdinfo_access_allowed(inode);
364 :
365 0 : if (ret)
366 : return ret;
367 :
368 0 : return 0;
369 : }
370 :
371 : const struct inode_operations proc_fdinfo_inode_operations = {
372 : .lookup = proc_lookupfdinfo,
373 : .setattr = proc_setattr,
374 : };
375 :
376 : const struct file_operations proc_fdinfo_operations = {
377 : .open = proc_open_fdinfo,
378 : .read = generic_read_dir,
379 : .iterate_shared = proc_readfdinfo,
380 : .llseek = generic_file_llseek,
381 : };
|