1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 23f07c014SIngo Molnar #include <linux/sched/signal.h> 3faf60af1SCyrill Gorcunov #include <linux/errno.h> 4faf60af1SCyrill Gorcunov #include <linux/dcache.h> 5faf60af1SCyrill Gorcunov #include <linux/path.h> 6faf60af1SCyrill Gorcunov #include <linux/fdtable.h> 7faf60af1SCyrill Gorcunov #include <linux/namei.h> 8faf60af1SCyrill Gorcunov #include <linux/pid.h> 97bc3fa01SKalesh Singh #include <linux/ptrace.h> 10faf60af1SCyrill Gorcunov #include <linux/security.h> 11ddd3e077SCyrill Gorcunov #include <linux/file.h> 12ddd3e077SCyrill Gorcunov #include <linux/seq_file.h> 136c8c9031SAndrey Vagin #include <linux/fs.h> 14faf60af1SCyrill Gorcunov 15faf60af1SCyrill Gorcunov #include <linux/proc_fs.h> 16faf60af1SCyrill Gorcunov 1749d063cbSAndrey Vagin #include "../mount.h" 18faf60af1SCyrill Gorcunov #include "internal.h" 19faf60af1SCyrill Gorcunov #include "fd.h" 20faf60af1SCyrill Gorcunov 21ddd3e077SCyrill Gorcunov static int seq_show(struct seq_file *m, void *v) 22faf60af1SCyrill Gorcunov { 23faf60af1SCyrill Gorcunov struct files_struct *files = NULL; 24ddd3e077SCyrill Gorcunov int f_flags = 0, ret = -ENOENT; 25ddd3e077SCyrill Gorcunov struct file *file = NULL; 26ddd3e077SCyrill Gorcunov struct task_struct *task; 27faf60af1SCyrill Gorcunov 28ddd3e077SCyrill Gorcunov task = get_proc_task(m->private); 29ddd3e077SCyrill Gorcunov if (!task) 30ddd3e077SCyrill Gorcunov return -ENOENT; 31ddd3e077SCyrill Gorcunov 32775e0656SEric W. Biederman task_lock(task); 33775e0656SEric W. Biederman files = task->files; 34faf60af1SCyrill Gorcunov if (files) { 35771187d6SAlexey Dobriyan unsigned int fd = proc_fd(m->private); 36ddd3e077SCyrill Gorcunov 37faf60af1SCyrill Gorcunov spin_lock(&files->file_lock); 38120ce2b0SEric W. Biederman file = files_lookup_fd_locked(files, fd); 39faf60af1SCyrill Gorcunov if (file) { 40ddd3e077SCyrill Gorcunov struct fdtable *fdt = files_fdtable(files); 41faf60af1SCyrill Gorcunov 42c6f3d811SAl Viro f_flags = file->f_flags; 43faf60af1SCyrill Gorcunov if (close_on_exec(fd, fdt)) 44faf60af1SCyrill Gorcunov f_flags |= O_CLOEXEC; 45faf60af1SCyrill Gorcunov 46ddd3e077SCyrill Gorcunov get_file(file); 47ddd3e077SCyrill Gorcunov ret = 0; 48faf60af1SCyrill Gorcunov } 49faf60af1SCyrill Gorcunov spin_unlock(&files->file_lock); 50faf60af1SCyrill Gorcunov } 51775e0656SEric W. Biederman task_unlock(task); 52775e0656SEric W. Biederman put_task_struct(task); 53ddd3e077SCyrill Gorcunov 546c8c9031SAndrey Vagin if (ret) 556c8c9031SAndrey Vagin return ret; 566c8c9031SAndrey Vagin 57*3845f256SKalesh Singh seq_printf(m, "pos:\t%lli\nflags:\t0%o\nmnt_id:\t%i\nino:\t%lu\n", 5849d063cbSAndrey Vagin (long long)file->f_pos, f_flags, 59*3845f256SKalesh Singh real_mount(file->f_path.mnt)->mnt_id, 60*3845f256SKalesh Singh file_inode(file)->i_ino); 616c8c9031SAndrey Vagin 62775e0656SEric W. Biederman /* show_fd_locks() never deferences files so a stale value is safe */ 636c8c9031SAndrey Vagin show_fd_locks(m, file, files); 646c8c9031SAndrey Vagin if (seq_has_overflowed(m)) 656c8c9031SAndrey Vagin goto out; 666c8c9031SAndrey Vagin 6755985dd7SCyrill Gorcunov if (file->f_op->show_fdinfo) 68a3816ab0SJoe Perches file->f_op->show_fdinfo(m, file); 69faf60af1SCyrill Gorcunov 706c8c9031SAndrey Vagin out: 716c8c9031SAndrey Vagin fput(file); 726c8c9031SAndrey Vagin return 0; 73ddd3e077SCyrill Gorcunov } 74ddd3e077SCyrill Gorcunov 75ddd3e077SCyrill Gorcunov static int seq_fdinfo_open(struct inode *inode, struct file *file) 76ddd3e077SCyrill Gorcunov { 777bc3fa01SKalesh Singh bool allowed = false; 787bc3fa01SKalesh Singh struct task_struct *task = get_proc_task(inode); 797bc3fa01SKalesh Singh 807bc3fa01SKalesh Singh if (!task) 817bc3fa01SKalesh Singh return -ESRCH; 827bc3fa01SKalesh Singh 837bc3fa01SKalesh Singh allowed = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS); 847bc3fa01SKalesh Singh put_task_struct(task); 857bc3fa01SKalesh Singh 867bc3fa01SKalesh Singh if (!allowed) 877bc3fa01SKalesh Singh return -EACCES; 887bc3fa01SKalesh Singh 89ddd3e077SCyrill Gorcunov return single_open(file, seq_show, inode); 90ddd3e077SCyrill Gorcunov } 91ddd3e077SCyrill Gorcunov 92ddd3e077SCyrill Gorcunov static const struct file_operations proc_fdinfo_file_operations = { 93ddd3e077SCyrill Gorcunov .open = seq_fdinfo_open, 94ddd3e077SCyrill Gorcunov .read = seq_read, 95ddd3e077SCyrill Gorcunov .llseek = seq_lseek, 96ddd3e077SCyrill Gorcunov .release = single_release, 97ddd3e077SCyrill Gorcunov }; 98ddd3e077SCyrill Gorcunov 991ae9bd8bSAl Viro static bool tid_fd_mode(struct task_struct *task, unsigned fd, fmode_t *mode) 1001ae9bd8bSAl Viro { 1011ae9bd8bSAl Viro struct file *file; 1021ae9bd8bSAl Viro 1031ae9bd8bSAl Viro rcu_read_lock(); 10464eb661fSEric W. Biederman file = task_lookup_fd_rcu(task, fd); 1051ae9bd8bSAl Viro if (file) 1061ae9bd8bSAl Viro *mode = file->f_mode; 1071ae9bd8bSAl Viro rcu_read_unlock(); 1081ae9bd8bSAl Viro return !!file; 1091ae9bd8bSAl Viro } 1101ae9bd8bSAl Viro 11198836386SAl Viro static void tid_fd_update_inode(struct task_struct *task, struct inode *inode, 11298836386SAl Viro fmode_t f_mode) 113faf60af1SCyrill Gorcunov { 11468eb94f1SEric W. Biederman task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid); 115faf60af1SCyrill Gorcunov 116faf60af1SCyrill Gorcunov if (S_ISLNK(inode->i_mode)) { 117faf60af1SCyrill Gorcunov unsigned i_mode = S_IFLNK; 118faf60af1SCyrill Gorcunov if (f_mode & FMODE_READ) 119faf60af1SCyrill Gorcunov i_mode |= S_IRUSR | S_IXUSR; 120faf60af1SCyrill Gorcunov if (f_mode & FMODE_WRITE) 121faf60af1SCyrill Gorcunov i_mode |= S_IWUSR | S_IXUSR; 122faf60af1SCyrill Gorcunov inode->i_mode = i_mode; 123faf60af1SCyrill Gorcunov } 124faf60af1SCyrill Gorcunov security_task_to_inode(task, inode); 12598836386SAl Viro } 12698836386SAl Viro 12798836386SAl Viro static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags) 12898836386SAl Viro { 12998836386SAl Viro struct task_struct *task; 13098836386SAl Viro struct inode *inode; 13198836386SAl Viro unsigned int fd; 13298836386SAl Viro 13398836386SAl Viro if (flags & LOOKUP_RCU) 13498836386SAl Viro return -ECHILD; 13598836386SAl Viro 13698836386SAl Viro inode = d_inode(dentry); 13798836386SAl Viro task = get_proc_task(inode); 13898836386SAl Viro fd = proc_fd(inode); 13998836386SAl Viro 14098836386SAl Viro if (task) { 14198836386SAl Viro fmode_t f_mode; 14298836386SAl Viro if (tid_fd_mode(task, fd, &f_mode)) { 14398836386SAl Viro tid_fd_update_inode(task, inode, f_mode); 144faf60af1SCyrill Gorcunov put_task_struct(task); 145faf60af1SCyrill Gorcunov return 1; 146faf60af1SCyrill Gorcunov } 147faf60af1SCyrill Gorcunov put_task_struct(task); 148faf60af1SCyrill Gorcunov } 149faf60af1SCyrill Gorcunov return 0; 150faf60af1SCyrill Gorcunov } 151faf60af1SCyrill Gorcunov 152faf60af1SCyrill Gorcunov static const struct dentry_operations tid_fd_dentry_operations = { 153faf60af1SCyrill Gorcunov .d_revalidate = tid_fd_revalidate, 154faf60af1SCyrill Gorcunov .d_delete = pid_delete_dentry, 155faf60af1SCyrill Gorcunov }; 156faf60af1SCyrill Gorcunov 157faf60af1SCyrill Gorcunov static int proc_fd_link(struct dentry *dentry, struct path *path) 158faf60af1SCyrill Gorcunov { 159ddd3e077SCyrill Gorcunov struct task_struct *task; 160ddd3e077SCyrill Gorcunov int ret = -ENOENT; 161ddd3e077SCyrill Gorcunov 1622b0143b5SDavid Howells task = get_proc_task(d_inode(dentry)); 163ddd3e077SCyrill Gorcunov if (task) { 164771187d6SAlexey Dobriyan unsigned int fd = proc_fd(d_inode(dentry)); 165ddd3e077SCyrill Gorcunov struct file *fd_file; 166ddd3e077SCyrill Gorcunov 167439be326SEric W. Biederman fd_file = fget_task(task, fd); 168ddd3e077SCyrill Gorcunov if (fd_file) { 169ddd3e077SCyrill Gorcunov *path = fd_file->f_path; 170ddd3e077SCyrill Gorcunov path_get(&fd_file->f_path); 171ddd3e077SCyrill Gorcunov ret = 0; 172439be326SEric W. Biederman fput(fd_file); 173ddd3e077SCyrill Gorcunov } 174439be326SEric W. Biederman put_task_struct(task); 175ddd3e077SCyrill Gorcunov } 176ddd3e077SCyrill Gorcunov 177ddd3e077SCyrill Gorcunov return ret; 178faf60af1SCyrill Gorcunov } 179faf60af1SCyrill Gorcunov 18098836386SAl Viro struct fd_data { 18198836386SAl Viro fmode_t mode; 18298836386SAl Viro unsigned fd; 18398836386SAl Viro }; 18498836386SAl Viro 1850168b9e3SAl Viro static struct dentry *proc_fd_instantiate(struct dentry *dentry, 186faf60af1SCyrill Gorcunov struct task_struct *task, const void *ptr) 187faf60af1SCyrill Gorcunov { 18898836386SAl Viro const struct fd_data *data = ptr; 189faf60af1SCyrill Gorcunov struct proc_inode *ei; 190faf60af1SCyrill Gorcunov struct inode *inode; 191faf60af1SCyrill Gorcunov 1920168b9e3SAl Viro inode = proc_pid_make_inode(dentry->d_sb, task, S_IFLNK); 193faf60af1SCyrill Gorcunov if (!inode) 1940168b9e3SAl Viro return ERR_PTR(-ENOENT); 195faf60af1SCyrill Gorcunov 196faf60af1SCyrill Gorcunov ei = PROC_I(inode); 19798836386SAl Viro ei->fd = data->fd; 198faf60af1SCyrill Gorcunov 199faf60af1SCyrill Gorcunov inode->i_op = &proc_pid_link_inode_operations; 200faf60af1SCyrill Gorcunov inode->i_size = 64; 201faf60af1SCyrill Gorcunov 202faf60af1SCyrill Gorcunov ei->op.proc_get_link = proc_fd_link; 20398836386SAl Viro tid_fd_update_inode(task, inode, data->mode); 204faf60af1SCyrill Gorcunov 205faf60af1SCyrill Gorcunov d_set_d_op(dentry, &tid_fd_dentry_operations); 2060168b9e3SAl Viro return d_splice_alias(inode, dentry); 207faf60af1SCyrill Gorcunov } 208faf60af1SCyrill Gorcunov 209faf60af1SCyrill Gorcunov static struct dentry *proc_lookupfd_common(struct inode *dir, 210faf60af1SCyrill Gorcunov struct dentry *dentry, 211faf60af1SCyrill Gorcunov instantiate_t instantiate) 212faf60af1SCyrill Gorcunov { 213faf60af1SCyrill Gorcunov struct task_struct *task = get_proc_task(dir); 21498836386SAl Viro struct fd_data data = {.fd = name_to_int(&dentry->d_name)}; 2150168b9e3SAl Viro struct dentry *result = ERR_PTR(-ENOENT); 216faf60af1SCyrill Gorcunov 217faf60af1SCyrill Gorcunov if (!task) 218faf60af1SCyrill Gorcunov goto out_no_task; 21998836386SAl Viro if (data.fd == ~0U) 220faf60af1SCyrill Gorcunov goto out; 22198836386SAl Viro if (!tid_fd_mode(task, data.fd, &data.mode)) 2221ae9bd8bSAl Viro goto out; 223faf60af1SCyrill Gorcunov 2240168b9e3SAl Viro result = instantiate(dentry, task, &data); 225faf60af1SCyrill Gorcunov out: 226faf60af1SCyrill Gorcunov put_task_struct(task); 227faf60af1SCyrill Gorcunov out_no_task: 2280168b9e3SAl Viro return result; 229faf60af1SCyrill Gorcunov } 230faf60af1SCyrill Gorcunov 231f0c3b509SAl Viro static int proc_readfd_common(struct file *file, struct dir_context *ctx, 232f0c3b509SAl Viro instantiate_t instantiate) 233faf60af1SCyrill Gorcunov { 234f0c3b509SAl Viro struct task_struct *p = get_proc_task(file_inode(file)); 235f0c3b509SAl Viro unsigned int fd; 236faf60af1SCyrill Gorcunov 237faf60af1SCyrill Gorcunov if (!p) 238f0c3b509SAl Viro return -ENOENT; 239faf60af1SCyrill Gorcunov 240f0c3b509SAl Viro if (!dir_emit_dots(file, ctx)) 241faf60af1SCyrill Gorcunov goto out; 242f0c3b509SAl Viro 243faf60af1SCyrill Gorcunov rcu_read_lock(); 2445b17b618SEric W. Biederman for (fd = ctx->pos - 2;; fd++) { 24598836386SAl Viro struct file *f; 24698836386SAl Viro struct fd_data data; 247e3912ac3SAlexey Dobriyan char name[10 + 1]; 248a4ef3895SAlexey Dobriyan unsigned int len; 249faf60af1SCyrill Gorcunov 2505b17b618SEric W. Biederman f = task_lookup_next_fd_rcu(p, &fd); 2515b17b618SEric W. Biederman ctx->pos = fd + 2LL; 25298836386SAl Viro if (!f) 2535b17b618SEric W. Biederman break; 25498836386SAl Viro data.mode = f->f_mode; 255faf60af1SCyrill Gorcunov rcu_read_unlock(); 25698836386SAl Viro data.fd = fd; 257faf60af1SCyrill Gorcunov 258771187d6SAlexey Dobriyan len = snprintf(name, sizeof(name), "%u", fd); 259f0c3b509SAl Viro if (!proc_fill_cache(file, ctx, 260faf60af1SCyrill Gorcunov name, len, instantiate, p, 26198836386SAl Viro &data)) 2625b17b618SEric W. Biederman goto out; 2633cc4a84eSEric Dumazet cond_resched(); 264faf60af1SCyrill Gorcunov rcu_read_lock(); 265faf60af1SCyrill Gorcunov } 266faf60af1SCyrill Gorcunov rcu_read_unlock(); 267faf60af1SCyrill Gorcunov out: 268faf60af1SCyrill Gorcunov put_task_struct(p); 269f0c3b509SAl Viro return 0; 270faf60af1SCyrill Gorcunov } 271faf60af1SCyrill Gorcunov 272f0c3b509SAl Viro static int proc_readfd(struct file *file, struct dir_context *ctx) 273faf60af1SCyrill Gorcunov { 274f0c3b509SAl Viro return proc_readfd_common(file, ctx, proc_fd_instantiate); 275faf60af1SCyrill Gorcunov } 276faf60af1SCyrill Gorcunov 277faf60af1SCyrill Gorcunov const struct file_operations proc_fd_operations = { 278faf60af1SCyrill Gorcunov .read = generic_read_dir, 279f50752eaSAl Viro .iterate_shared = proc_readfd, 280f50752eaSAl Viro .llseek = generic_file_llseek, 281faf60af1SCyrill Gorcunov }; 282faf60af1SCyrill Gorcunov 283faf60af1SCyrill Gorcunov static struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry, 284faf60af1SCyrill Gorcunov unsigned int flags) 285faf60af1SCyrill Gorcunov { 286faf60af1SCyrill Gorcunov return proc_lookupfd_common(dir, dentry, proc_fd_instantiate); 287faf60af1SCyrill Gorcunov } 288faf60af1SCyrill Gorcunov 289faf60af1SCyrill Gorcunov /* 290faf60af1SCyrill Gorcunov * /proc/pid/fd needs a special permission handler so that a process can still 291faf60af1SCyrill Gorcunov * access /proc/self/fd after it has executed a setuid(). 292faf60af1SCyrill Gorcunov */ 293549c7297SChristian Brauner int proc_fd_permission(struct user_namespace *mnt_userns, 294549c7297SChristian Brauner struct inode *inode, int mask) 295faf60af1SCyrill Gorcunov { 29654708d28SOleg Nesterov struct task_struct *p; 29754708d28SOleg Nesterov int rv; 29854708d28SOleg Nesterov 29947291baaSChristian Brauner rv = generic_permission(&init_user_ns, inode, mask); 300faf60af1SCyrill Gorcunov if (rv == 0) 30154708d28SOleg Nesterov return rv; 30254708d28SOleg Nesterov 30354708d28SOleg Nesterov rcu_read_lock(); 30454708d28SOleg Nesterov p = pid_task(proc_pid(inode), PIDTYPE_PID); 30554708d28SOleg Nesterov if (p && same_thread_group(p, current)) 306faf60af1SCyrill Gorcunov rv = 0; 30754708d28SOleg Nesterov rcu_read_unlock(); 30854708d28SOleg Nesterov 309faf60af1SCyrill Gorcunov return rv; 310faf60af1SCyrill Gorcunov } 311faf60af1SCyrill Gorcunov 312faf60af1SCyrill Gorcunov const struct inode_operations proc_fd_inode_operations = { 313faf60af1SCyrill Gorcunov .lookup = proc_lookupfd, 314faf60af1SCyrill Gorcunov .permission = proc_fd_permission, 315faf60af1SCyrill Gorcunov .setattr = proc_setattr, 316faf60af1SCyrill Gorcunov }; 317faf60af1SCyrill Gorcunov 3180168b9e3SAl Viro static struct dentry *proc_fdinfo_instantiate(struct dentry *dentry, 319faf60af1SCyrill Gorcunov struct task_struct *task, const void *ptr) 320faf60af1SCyrill Gorcunov { 32198836386SAl Viro const struct fd_data *data = ptr; 322faf60af1SCyrill Gorcunov struct proc_inode *ei; 323faf60af1SCyrill Gorcunov struct inode *inode; 324faf60af1SCyrill Gorcunov 3257bc3fa01SKalesh Singh inode = proc_pid_make_inode(dentry->d_sb, task, S_IFREG | S_IRUGO); 326faf60af1SCyrill Gorcunov if (!inode) 3270168b9e3SAl Viro return ERR_PTR(-ENOENT); 328faf60af1SCyrill Gorcunov 329faf60af1SCyrill Gorcunov ei = PROC_I(inode); 33098836386SAl Viro ei->fd = data->fd; 331faf60af1SCyrill Gorcunov 332faf60af1SCyrill Gorcunov inode->i_fop = &proc_fdinfo_file_operations; 33398836386SAl Viro tid_fd_update_inode(task, inode, 0); 334faf60af1SCyrill Gorcunov 335faf60af1SCyrill Gorcunov d_set_d_op(dentry, &tid_fd_dentry_operations); 3360168b9e3SAl Viro return d_splice_alias(inode, dentry); 337faf60af1SCyrill Gorcunov } 338faf60af1SCyrill Gorcunov 339faf60af1SCyrill Gorcunov static struct dentry * 340faf60af1SCyrill Gorcunov proc_lookupfdinfo(struct inode *dir, struct dentry *dentry, unsigned int flags) 341faf60af1SCyrill Gorcunov { 342faf60af1SCyrill Gorcunov return proc_lookupfd_common(dir, dentry, proc_fdinfo_instantiate); 343faf60af1SCyrill Gorcunov } 344faf60af1SCyrill Gorcunov 345f0c3b509SAl Viro static int proc_readfdinfo(struct file *file, struct dir_context *ctx) 346faf60af1SCyrill Gorcunov { 347f0c3b509SAl Viro return proc_readfd_common(file, ctx, 348faf60af1SCyrill Gorcunov proc_fdinfo_instantiate); 349faf60af1SCyrill Gorcunov } 350faf60af1SCyrill Gorcunov 351faf60af1SCyrill Gorcunov const struct inode_operations proc_fdinfo_inode_operations = { 352faf60af1SCyrill Gorcunov .lookup = proc_lookupfdinfo, 353faf60af1SCyrill Gorcunov .setattr = proc_setattr, 354faf60af1SCyrill Gorcunov }; 355faf60af1SCyrill Gorcunov 356faf60af1SCyrill Gorcunov const struct file_operations proc_fdinfo_operations = { 357faf60af1SCyrill Gorcunov .read = generic_read_dir, 358f50752eaSAl Viro .iterate_shared = proc_readfdinfo, 359f50752eaSAl Viro .llseek = generic_file_llseek, 360faf60af1SCyrill Gorcunov }; 361