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