1faf60af1SCyrill Gorcunov #include <linux/sched.h> 2faf60af1SCyrill Gorcunov #include <linux/errno.h> 3faf60af1SCyrill Gorcunov #include <linux/dcache.h> 4faf60af1SCyrill Gorcunov #include <linux/path.h> 5faf60af1SCyrill Gorcunov #include <linux/fdtable.h> 6faf60af1SCyrill Gorcunov #include <linux/namei.h> 7faf60af1SCyrill Gorcunov #include <linux/pid.h> 8faf60af1SCyrill Gorcunov #include <linux/security.h> 9ddd3e077SCyrill Gorcunov #include <linux/file.h> 10ddd3e077SCyrill Gorcunov #include <linux/seq_file.h> 116c8c9031SAndrey Vagin #include <linux/fs.h> 12faf60af1SCyrill Gorcunov 13faf60af1SCyrill Gorcunov #include <linux/proc_fs.h> 14faf60af1SCyrill Gorcunov 1549d063cbSAndrey Vagin #include "../mount.h" 16faf60af1SCyrill Gorcunov #include "internal.h" 17faf60af1SCyrill Gorcunov #include "fd.h" 18faf60af1SCyrill Gorcunov 19ddd3e077SCyrill Gorcunov static int seq_show(struct seq_file *m, void *v) 20faf60af1SCyrill Gorcunov { 21faf60af1SCyrill Gorcunov struct files_struct *files = NULL; 22ddd3e077SCyrill Gorcunov int f_flags = 0, ret = -ENOENT; 23ddd3e077SCyrill Gorcunov struct file *file = NULL; 24ddd3e077SCyrill Gorcunov struct task_struct *task; 25faf60af1SCyrill Gorcunov 26ddd3e077SCyrill Gorcunov task = get_proc_task(m->private); 27ddd3e077SCyrill Gorcunov if (!task) 28ddd3e077SCyrill Gorcunov return -ENOENT; 29ddd3e077SCyrill Gorcunov 30faf60af1SCyrill Gorcunov files = get_files_struct(task); 31faf60af1SCyrill Gorcunov put_task_struct(task); 32ddd3e077SCyrill Gorcunov 33faf60af1SCyrill Gorcunov if (files) { 34ddd3e077SCyrill Gorcunov int fd = proc_fd(m->private); 35ddd3e077SCyrill Gorcunov 36faf60af1SCyrill Gorcunov spin_lock(&files->file_lock); 37faf60af1SCyrill Gorcunov file = fcheck_files(files, fd); 38faf60af1SCyrill Gorcunov if (file) { 39ddd3e077SCyrill Gorcunov struct fdtable *fdt = files_fdtable(files); 40faf60af1SCyrill Gorcunov 41c6f3d811SAl Viro f_flags = file->f_flags; 42faf60af1SCyrill Gorcunov if (close_on_exec(fd, fdt)) 43faf60af1SCyrill Gorcunov f_flags |= O_CLOEXEC; 44faf60af1SCyrill Gorcunov 45ddd3e077SCyrill Gorcunov get_file(file); 46ddd3e077SCyrill Gorcunov ret = 0; 47faf60af1SCyrill Gorcunov } 48faf60af1SCyrill Gorcunov spin_unlock(&files->file_lock); 49faf60af1SCyrill Gorcunov put_files_struct(files); 50faf60af1SCyrill Gorcunov } 51ddd3e077SCyrill Gorcunov 526c8c9031SAndrey Vagin if (ret) 536c8c9031SAndrey Vagin return ret; 546c8c9031SAndrey Vagin 5549d063cbSAndrey Vagin seq_printf(m, "pos:\t%lli\nflags:\t0%o\nmnt_id:\t%i\n", 5649d063cbSAndrey Vagin (long long)file->f_pos, f_flags, 5749d063cbSAndrey Vagin real_mount(file->f_path.mnt)->mnt_id); 586c8c9031SAndrey Vagin 596c8c9031SAndrey Vagin show_fd_locks(m, file, files); 606c8c9031SAndrey Vagin if (seq_has_overflowed(m)) 616c8c9031SAndrey Vagin goto out; 626c8c9031SAndrey Vagin 6355985dd7SCyrill Gorcunov if (file->f_op->show_fdinfo) 64a3816ab0SJoe Perches file->f_op->show_fdinfo(m, file); 65faf60af1SCyrill Gorcunov 666c8c9031SAndrey Vagin out: 676c8c9031SAndrey Vagin fput(file); 686c8c9031SAndrey Vagin return 0; 69ddd3e077SCyrill Gorcunov } 70ddd3e077SCyrill Gorcunov 71ddd3e077SCyrill Gorcunov static int seq_fdinfo_open(struct inode *inode, struct file *file) 72ddd3e077SCyrill Gorcunov { 73ddd3e077SCyrill Gorcunov return single_open(file, seq_show, inode); 74ddd3e077SCyrill Gorcunov } 75ddd3e077SCyrill Gorcunov 76ddd3e077SCyrill Gorcunov static const struct file_operations proc_fdinfo_file_operations = { 77ddd3e077SCyrill Gorcunov .open = seq_fdinfo_open, 78ddd3e077SCyrill Gorcunov .read = seq_read, 79ddd3e077SCyrill Gorcunov .llseek = seq_lseek, 80ddd3e077SCyrill Gorcunov .release = single_release, 81ddd3e077SCyrill Gorcunov }; 82ddd3e077SCyrill Gorcunov 83faf60af1SCyrill Gorcunov static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags) 84faf60af1SCyrill Gorcunov { 85faf60af1SCyrill Gorcunov struct files_struct *files; 86faf60af1SCyrill Gorcunov struct task_struct *task; 87faf60af1SCyrill Gorcunov const struct cred *cred; 88faf60af1SCyrill Gorcunov struct inode *inode; 89faf60af1SCyrill Gorcunov int fd; 90faf60af1SCyrill Gorcunov 91faf60af1SCyrill Gorcunov if (flags & LOOKUP_RCU) 92faf60af1SCyrill Gorcunov return -ECHILD; 93faf60af1SCyrill Gorcunov 942b0143b5SDavid Howells inode = d_inode(dentry); 95faf60af1SCyrill Gorcunov task = get_proc_task(inode); 96faf60af1SCyrill Gorcunov fd = proc_fd(inode); 97faf60af1SCyrill Gorcunov 98faf60af1SCyrill Gorcunov if (task) { 99faf60af1SCyrill Gorcunov files = get_files_struct(task); 100faf60af1SCyrill Gorcunov if (files) { 101faf60af1SCyrill Gorcunov struct file *file; 102faf60af1SCyrill Gorcunov 103faf60af1SCyrill Gorcunov rcu_read_lock(); 104faf60af1SCyrill Gorcunov file = fcheck_files(files, fd); 105faf60af1SCyrill Gorcunov if (file) { 106faf60af1SCyrill Gorcunov unsigned f_mode = file->f_mode; 107faf60af1SCyrill Gorcunov 108faf60af1SCyrill Gorcunov rcu_read_unlock(); 109faf60af1SCyrill Gorcunov put_files_struct(files); 110faf60af1SCyrill Gorcunov 111faf60af1SCyrill Gorcunov if (task_dumpable(task)) { 112faf60af1SCyrill Gorcunov rcu_read_lock(); 113faf60af1SCyrill Gorcunov cred = __task_cred(task); 114faf60af1SCyrill Gorcunov inode->i_uid = cred->euid; 115faf60af1SCyrill Gorcunov inode->i_gid = cred->egid; 116faf60af1SCyrill Gorcunov rcu_read_unlock(); 117faf60af1SCyrill Gorcunov } else { 118faf60af1SCyrill Gorcunov inode->i_uid = GLOBAL_ROOT_UID; 119faf60af1SCyrill Gorcunov inode->i_gid = GLOBAL_ROOT_GID; 120faf60af1SCyrill Gorcunov } 121faf60af1SCyrill Gorcunov 122faf60af1SCyrill Gorcunov if (S_ISLNK(inode->i_mode)) { 123faf60af1SCyrill Gorcunov unsigned i_mode = S_IFLNK; 124faf60af1SCyrill Gorcunov if (f_mode & FMODE_READ) 125faf60af1SCyrill Gorcunov i_mode |= S_IRUSR | S_IXUSR; 126faf60af1SCyrill Gorcunov if (f_mode & FMODE_WRITE) 127faf60af1SCyrill Gorcunov i_mode |= S_IWUSR | S_IXUSR; 128faf60af1SCyrill Gorcunov inode->i_mode = i_mode; 129faf60af1SCyrill Gorcunov } 130faf60af1SCyrill Gorcunov 131faf60af1SCyrill Gorcunov security_task_to_inode(task, inode); 132faf60af1SCyrill Gorcunov put_task_struct(task); 133faf60af1SCyrill Gorcunov return 1; 134faf60af1SCyrill Gorcunov } 135faf60af1SCyrill Gorcunov rcu_read_unlock(); 136faf60af1SCyrill Gorcunov put_files_struct(files); 137faf60af1SCyrill Gorcunov } 138faf60af1SCyrill Gorcunov put_task_struct(task); 139faf60af1SCyrill Gorcunov } 140faf60af1SCyrill Gorcunov return 0; 141faf60af1SCyrill Gorcunov } 142faf60af1SCyrill Gorcunov 143faf60af1SCyrill Gorcunov static const struct dentry_operations tid_fd_dentry_operations = { 144faf60af1SCyrill Gorcunov .d_revalidate = tid_fd_revalidate, 145faf60af1SCyrill Gorcunov .d_delete = pid_delete_dentry, 146faf60af1SCyrill Gorcunov }; 147faf60af1SCyrill Gorcunov 148faf60af1SCyrill Gorcunov static int proc_fd_link(struct dentry *dentry, struct path *path) 149faf60af1SCyrill Gorcunov { 150ddd3e077SCyrill Gorcunov struct files_struct *files = NULL; 151ddd3e077SCyrill Gorcunov struct task_struct *task; 152ddd3e077SCyrill Gorcunov int ret = -ENOENT; 153ddd3e077SCyrill Gorcunov 1542b0143b5SDavid Howells task = get_proc_task(d_inode(dentry)); 155ddd3e077SCyrill Gorcunov if (task) { 156ddd3e077SCyrill Gorcunov files = get_files_struct(task); 157ddd3e077SCyrill Gorcunov put_task_struct(task); 158ddd3e077SCyrill Gorcunov } 159ddd3e077SCyrill Gorcunov 160ddd3e077SCyrill Gorcunov if (files) { 1612b0143b5SDavid Howells int fd = proc_fd(d_inode(dentry)); 162ddd3e077SCyrill Gorcunov struct file *fd_file; 163ddd3e077SCyrill Gorcunov 164ddd3e077SCyrill Gorcunov spin_lock(&files->file_lock); 165ddd3e077SCyrill Gorcunov fd_file = fcheck_files(files, fd); 166ddd3e077SCyrill Gorcunov if (fd_file) { 167ddd3e077SCyrill Gorcunov *path = fd_file->f_path; 168ddd3e077SCyrill Gorcunov path_get(&fd_file->f_path); 169ddd3e077SCyrill Gorcunov ret = 0; 170ddd3e077SCyrill Gorcunov } 171ddd3e077SCyrill Gorcunov spin_unlock(&files->file_lock); 172ddd3e077SCyrill Gorcunov put_files_struct(files); 173ddd3e077SCyrill Gorcunov } 174ddd3e077SCyrill Gorcunov 175ddd3e077SCyrill Gorcunov return ret; 176faf60af1SCyrill Gorcunov } 177faf60af1SCyrill Gorcunov 178c52a47acSAl Viro static int 179faf60af1SCyrill Gorcunov proc_fd_instantiate(struct inode *dir, struct dentry *dentry, 180faf60af1SCyrill Gorcunov struct task_struct *task, const void *ptr) 181faf60af1SCyrill Gorcunov { 182faf60af1SCyrill Gorcunov unsigned fd = (unsigned long)ptr; 183faf60af1SCyrill Gorcunov struct proc_inode *ei; 184faf60af1SCyrill Gorcunov struct inode *inode; 185faf60af1SCyrill Gorcunov 186faf60af1SCyrill Gorcunov inode = proc_pid_make_inode(dir->i_sb, task); 187faf60af1SCyrill Gorcunov if (!inode) 188faf60af1SCyrill Gorcunov goto out; 189faf60af1SCyrill Gorcunov 190faf60af1SCyrill Gorcunov ei = PROC_I(inode); 191faf60af1SCyrill Gorcunov ei->fd = fd; 192faf60af1SCyrill Gorcunov 193faf60af1SCyrill Gorcunov inode->i_mode = S_IFLNK; 194faf60af1SCyrill Gorcunov inode->i_op = &proc_pid_link_inode_operations; 195faf60af1SCyrill Gorcunov inode->i_size = 64; 196faf60af1SCyrill Gorcunov 197faf60af1SCyrill Gorcunov ei->op.proc_get_link = proc_fd_link; 198faf60af1SCyrill Gorcunov 199faf60af1SCyrill Gorcunov d_set_d_op(dentry, &tid_fd_dentry_operations); 200faf60af1SCyrill Gorcunov d_add(dentry, inode); 201faf60af1SCyrill Gorcunov 202faf60af1SCyrill Gorcunov /* Close the race of the process dying before we return the dentry */ 203faf60af1SCyrill Gorcunov if (tid_fd_revalidate(dentry, 0)) 204c52a47acSAl Viro return 0; 205faf60af1SCyrill Gorcunov out: 206c52a47acSAl Viro return -ENOENT; 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); 214c52a47acSAl Viro int result = -ENOENT; 215dbcdb504SAlexey Dobriyan unsigned fd = name_to_int(&dentry->d_name); 216faf60af1SCyrill Gorcunov 217faf60af1SCyrill Gorcunov if (!task) 218faf60af1SCyrill Gorcunov goto out_no_task; 219faf60af1SCyrill Gorcunov if (fd == ~0U) 220faf60af1SCyrill Gorcunov goto out; 221faf60af1SCyrill Gorcunov 222faf60af1SCyrill Gorcunov result = instantiate(dir, dentry, task, (void *)(unsigned long)fd); 223faf60af1SCyrill Gorcunov out: 224faf60af1SCyrill Gorcunov put_task_struct(task); 225faf60af1SCyrill Gorcunov out_no_task: 226c52a47acSAl Viro return ERR_PTR(result); 227faf60af1SCyrill Gorcunov } 228faf60af1SCyrill Gorcunov 229f0c3b509SAl Viro static int proc_readfd_common(struct file *file, struct dir_context *ctx, 230f0c3b509SAl Viro instantiate_t instantiate) 231faf60af1SCyrill Gorcunov { 232f0c3b509SAl Viro struct task_struct *p = get_proc_task(file_inode(file)); 233faf60af1SCyrill Gorcunov struct files_struct *files; 234f0c3b509SAl Viro unsigned int fd; 235faf60af1SCyrill Gorcunov 236faf60af1SCyrill Gorcunov if (!p) 237f0c3b509SAl Viro return -ENOENT; 238faf60af1SCyrill Gorcunov 239f0c3b509SAl Viro if (!dir_emit_dots(file, ctx)) 240faf60af1SCyrill Gorcunov goto out; 241faf60af1SCyrill Gorcunov files = get_files_struct(p); 242faf60af1SCyrill Gorcunov if (!files) 243faf60af1SCyrill Gorcunov goto out; 244f0c3b509SAl Viro 245faf60af1SCyrill Gorcunov rcu_read_lock(); 246f0c3b509SAl Viro for (fd = ctx->pos - 2; 247faf60af1SCyrill Gorcunov fd < files_fdtable(files)->max_fds; 248f0c3b509SAl Viro fd++, ctx->pos++) { 249faf60af1SCyrill Gorcunov char name[PROC_NUMBUF]; 250faf60af1SCyrill Gorcunov int len; 251faf60af1SCyrill Gorcunov 252faf60af1SCyrill Gorcunov if (!fcheck_files(files, fd)) 253faf60af1SCyrill Gorcunov continue; 254faf60af1SCyrill Gorcunov rcu_read_unlock(); 255faf60af1SCyrill Gorcunov 256faf60af1SCyrill Gorcunov len = snprintf(name, sizeof(name), "%d", fd); 257f0c3b509SAl Viro if (!proc_fill_cache(file, ctx, 258faf60af1SCyrill Gorcunov name, len, instantiate, p, 259f0c3b509SAl Viro (void *)(unsigned long)fd)) 260faf60af1SCyrill Gorcunov goto out_fd_loop; 261faf60af1SCyrill Gorcunov rcu_read_lock(); 262faf60af1SCyrill Gorcunov } 263faf60af1SCyrill Gorcunov rcu_read_unlock(); 264faf60af1SCyrill Gorcunov out_fd_loop: 265faf60af1SCyrill Gorcunov put_files_struct(files); 266faf60af1SCyrill Gorcunov out: 267faf60af1SCyrill Gorcunov put_task_struct(p); 268f0c3b509SAl Viro return 0; 269faf60af1SCyrill Gorcunov } 270faf60af1SCyrill Gorcunov 271f0c3b509SAl Viro static int proc_readfd(struct file *file, struct dir_context *ctx) 272faf60af1SCyrill Gorcunov { 273f0c3b509SAl Viro return proc_readfd_common(file, ctx, proc_fd_instantiate); 274faf60af1SCyrill Gorcunov } 275faf60af1SCyrill Gorcunov 276faf60af1SCyrill Gorcunov const struct file_operations proc_fd_operations = { 277faf60af1SCyrill Gorcunov .read = generic_read_dir, 278f0c3b509SAl Viro .iterate = proc_readfd, 279faf60af1SCyrill Gorcunov .llseek = default_llseek, 280faf60af1SCyrill Gorcunov }; 281faf60af1SCyrill Gorcunov 282faf60af1SCyrill Gorcunov static struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry, 283faf60af1SCyrill Gorcunov unsigned int flags) 284faf60af1SCyrill Gorcunov { 285faf60af1SCyrill Gorcunov return proc_lookupfd_common(dir, dentry, proc_fd_instantiate); 286faf60af1SCyrill Gorcunov } 287faf60af1SCyrill Gorcunov 288faf60af1SCyrill Gorcunov /* 289faf60af1SCyrill Gorcunov * /proc/pid/fd needs a special permission handler so that a process can still 290faf60af1SCyrill Gorcunov * access /proc/self/fd after it has executed a setuid(). 291faf60af1SCyrill Gorcunov */ 292faf60af1SCyrill Gorcunov int proc_fd_permission(struct inode *inode, int mask) 293faf60af1SCyrill Gorcunov { 294*54708d28SOleg Nesterov struct task_struct *p; 295*54708d28SOleg Nesterov int rv; 296*54708d28SOleg Nesterov 297*54708d28SOleg Nesterov rv = generic_permission(inode, mask); 298faf60af1SCyrill Gorcunov if (rv == 0) 299*54708d28SOleg Nesterov return rv; 300*54708d28SOleg Nesterov 301*54708d28SOleg Nesterov rcu_read_lock(); 302*54708d28SOleg Nesterov p = pid_task(proc_pid(inode), PIDTYPE_PID); 303*54708d28SOleg Nesterov if (p && same_thread_group(p, current)) 304faf60af1SCyrill Gorcunov rv = 0; 305*54708d28SOleg Nesterov rcu_read_unlock(); 306*54708d28SOleg Nesterov 307faf60af1SCyrill Gorcunov return rv; 308faf60af1SCyrill Gorcunov } 309faf60af1SCyrill Gorcunov 310faf60af1SCyrill Gorcunov const struct inode_operations proc_fd_inode_operations = { 311faf60af1SCyrill Gorcunov .lookup = proc_lookupfd, 312faf60af1SCyrill Gorcunov .permission = proc_fd_permission, 313faf60af1SCyrill Gorcunov .setattr = proc_setattr, 314faf60af1SCyrill Gorcunov }; 315faf60af1SCyrill Gorcunov 316c52a47acSAl Viro static int 317faf60af1SCyrill Gorcunov proc_fdinfo_instantiate(struct inode *dir, struct dentry *dentry, 318faf60af1SCyrill Gorcunov struct task_struct *task, const void *ptr) 319faf60af1SCyrill Gorcunov { 320faf60af1SCyrill Gorcunov unsigned fd = (unsigned long)ptr; 321faf60af1SCyrill Gorcunov struct proc_inode *ei; 322faf60af1SCyrill Gorcunov struct inode *inode; 323faf60af1SCyrill Gorcunov 324faf60af1SCyrill Gorcunov inode = proc_pid_make_inode(dir->i_sb, task); 325faf60af1SCyrill Gorcunov if (!inode) 326faf60af1SCyrill Gorcunov goto out; 327faf60af1SCyrill Gorcunov 328faf60af1SCyrill Gorcunov ei = PROC_I(inode); 329faf60af1SCyrill Gorcunov ei->fd = fd; 330faf60af1SCyrill Gorcunov 331faf60af1SCyrill Gorcunov inode->i_mode = S_IFREG | S_IRUSR; 332faf60af1SCyrill Gorcunov inode->i_fop = &proc_fdinfo_file_operations; 333faf60af1SCyrill Gorcunov 334faf60af1SCyrill Gorcunov d_set_d_op(dentry, &tid_fd_dentry_operations); 335faf60af1SCyrill Gorcunov d_add(dentry, inode); 336faf60af1SCyrill Gorcunov 337faf60af1SCyrill Gorcunov /* Close the race of the process dying before we return the dentry */ 338faf60af1SCyrill Gorcunov if (tid_fd_revalidate(dentry, 0)) 339c52a47acSAl Viro return 0; 340faf60af1SCyrill Gorcunov out: 341c52a47acSAl Viro return -ENOENT; 342faf60af1SCyrill Gorcunov } 343faf60af1SCyrill Gorcunov 344faf60af1SCyrill Gorcunov static struct dentry * 345faf60af1SCyrill Gorcunov proc_lookupfdinfo(struct inode *dir, struct dentry *dentry, unsigned int flags) 346faf60af1SCyrill Gorcunov { 347faf60af1SCyrill Gorcunov return proc_lookupfd_common(dir, dentry, proc_fdinfo_instantiate); 348faf60af1SCyrill Gorcunov } 349faf60af1SCyrill Gorcunov 350f0c3b509SAl Viro static int proc_readfdinfo(struct file *file, struct dir_context *ctx) 351faf60af1SCyrill Gorcunov { 352f0c3b509SAl Viro return proc_readfd_common(file, ctx, 353faf60af1SCyrill Gorcunov proc_fdinfo_instantiate); 354faf60af1SCyrill Gorcunov } 355faf60af1SCyrill Gorcunov 356faf60af1SCyrill Gorcunov const struct inode_operations proc_fdinfo_inode_operations = { 357faf60af1SCyrill Gorcunov .lookup = proc_lookupfdinfo, 358faf60af1SCyrill Gorcunov .setattr = proc_setattr, 359faf60af1SCyrill Gorcunov }; 360faf60af1SCyrill Gorcunov 361faf60af1SCyrill Gorcunov const struct file_operations proc_fdinfo_operations = { 362faf60af1SCyrill Gorcunov .read = generic_read_dir, 363f0c3b509SAl Viro .iterate = proc_readfdinfo, 364faf60af1SCyrill Gorcunov .llseek = default_llseek, 365faf60af1SCyrill Gorcunov }; 366