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> 9faf60af1SCyrill Gorcunov 10faf60af1SCyrill Gorcunov #include <linux/proc_fs.h> 11faf60af1SCyrill Gorcunov 12faf60af1SCyrill Gorcunov #include "internal.h" 13faf60af1SCyrill Gorcunov #include "fd.h" 14faf60af1SCyrill Gorcunov 15faf60af1SCyrill Gorcunov #define PROC_FDINFO_MAX 64 16faf60af1SCyrill Gorcunov 17faf60af1SCyrill Gorcunov static int proc_fd_info(struct inode *inode, struct path *path, char *info) 18faf60af1SCyrill Gorcunov { 19faf60af1SCyrill Gorcunov struct task_struct *task = get_proc_task(inode); 20faf60af1SCyrill Gorcunov struct files_struct *files = NULL; 21faf60af1SCyrill Gorcunov int fd = proc_fd(inode); 22faf60af1SCyrill Gorcunov struct file *file; 23faf60af1SCyrill Gorcunov 24faf60af1SCyrill Gorcunov if (task) { 25faf60af1SCyrill Gorcunov files = get_files_struct(task); 26faf60af1SCyrill Gorcunov put_task_struct(task); 27faf60af1SCyrill Gorcunov } 28faf60af1SCyrill Gorcunov if (files) { 29faf60af1SCyrill Gorcunov /* 30faf60af1SCyrill Gorcunov * We are not taking a ref to the file structure, so we must 31faf60af1SCyrill Gorcunov * hold ->file_lock. 32faf60af1SCyrill Gorcunov */ 33faf60af1SCyrill Gorcunov spin_lock(&files->file_lock); 34faf60af1SCyrill Gorcunov file = fcheck_files(files, fd); 35faf60af1SCyrill Gorcunov if (file) { 36faf60af1SCyrill Gorcunov unsigned int f_flags; 37faf60af1SCyrill Gorcunov struct fdtable *fdt; 38faf60af1SCyrill Gorcunov 39faf60af1SCyrill Gorcunov fdt = files_fdtable(files); 40faf60af1SCyrill Gorcunov f_flags = file->f_flags & ~O_CLOEXEC; 41faf60af1SCyrill Gorcunov if (close_on_exec(fd, fdt)) 42faf60af1SCyrill Gorcunov f_flags |= O_CLOEXEC; 43faf60af1SCyrill Gorcunov 44faf60af1SCyrill Gorcunov if (path) { 45faf60af1SCyrill Gorcunov *path = file->f_path; 46faf60af1SCyrill Gorcunov path_get(&file->f_path); 47faf60af1SCyrill Gorcunov } 48faf60af1SCyrill Gorcunov if (info) 49faf60af1SCyrill Gorcunov snprintf(info, PROC_FDINFO_MAX, 50faf60af1SCyrill Gorcunov "pos:\t%lli\n" 51faf60af1SCyrill Gorcunov "flags:\t0%o\n", 52faf60af1SCyrill Gorcunov (long long) file->f_pos, 53faf60af1SCyrill Gorcunov f_flags); 54faf60af1SCyrill Gorcunov spin_unlock(&files->file_lock); 55faf60af1SCyrill Gorcunov put_files_struct(files); 56faf60af1SCyrill Gorcunov return 0; 57faf60af1SCyrill Gorcunov } 58faf60af1SCyrill Gorcunov spin_unlock(&files->file_lock); 59faf60af1SCyrill Gorcunov put_files_struct(files); 60faf60af1SCyrill Gorcunov } 61faf60af1SCyrill Gorcunov return -ENOENT; 62faf60af1SCyrill Gorcunov } 63faf60af1SCyrill Gorcunov 64faf60af1SCyrill Gorcunov static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags) 65faf60af1SCyrill Gorcunov { 66faf60af1SCyrill Gorcunov struct files_struct *files; 67faf60af1SCyrill Gorcunov struct task_struct *task; 68faf60af1SCyrill Gorcunov const struct cred *cred; 69faf60af1SCyrill Gorcunov struct inode *inode; 70faf60af1SCyrill Gorcunov int fd; 71faf60af1SCyrill Gorcunov 72faf60af1SCyrill Gorcunov if (flags & LOOKUP_RCU) 73faf60af1SCyrill Gorcunov return -ECHILD; 74faf60af1SCyrill Gorcunov 75faf60af1SCyrill Gorcunov inode = dentry->d_inode; 76faf60af1SCyrill Gorcunov task = get_proc_task(inode); 77faf60af1SCyrill Gorcunov fd = proc_fd(inode); 78faf60af1SCyrill Gorcunov 79faf60af1SCyrill Gorcunov if (task) { 80faf60af1SCyrill Gorcunov files = get_files_struct(task); 81faf60af1SCyrill Gorcunov if (files) { 82faf60af1SCyrill Gorcunov struct file *file; 83faf60af1SCyrill Gorcunov 84faf60af1SCyrill Gorcunov rcu_read_lock(); 85faf60af1SCyrill Gorcunov file = fcheck_files(files, fd); 86faf60af1SCyrill Gorcunov if (file) { 87faf60af1SCyrill Gorcunov unsigned f_mode = file->f_mode; 88faf60af1SCyrill Gorcunov 89faf60af1SCyrill Gorcunov rcu_read_unlock(); 90faf60af1SCyrill Gorcunov put_files_struct(files); 91faf60af1SCyrill Gorcunov 92faf60af1SCyrill Gorcunov if (task_dumpable(task)) { 93faf60af1SCyrill Gorcunov rcu_read_lock(); 94faf60af1SCyrill Gorcunov cred = __task_cred(task); 95faf60af1SCyrill Gorcunov inode->i_uid = cred->euid; 96faf60af1SCyrill Gorcunov inode->i_gid = cred->egid; 97faf60af1SCyrill Gorcunov rcu_read_unlock(); 98faf60af1SCyrill Gorcunov } else { 99faf60af1SCyrill Gorcunov inode->i_uid = GLOBAL_ROOT_UID; 100faf60af1SCyrill Gorcunov inode->i_gid = GLOBAL_ROOT_GID; 101faf60af1SCyrill Gorcunov } 102faf60af1SCyrill Gorcunov 103faf60af1SCyrill Gorcunov if (S_ISLNK(inode->i_mode)) { 104faf60af1SCyrill Gorcunov unsigned i_mode = S_IFLNK; 105faf60af1SCyrill Gorcunov if (f_mode & FMODE_READ) 106faf60af1SCyrill Gorcunov i_mode |= S_IRUSR | S_IXUSR; 107faf60af1SCyrill Gorcunov if (f_mode & FMODE_WRITE) 108faf60af1SCyrill Gorcunov i_mode |= S_IWUSR | S_IXUSR; 109faf60af1SCyrill Gorcunov inode->i_mode = i_mode; 110faf60af1SCyrill Gorcunov } 111faf60af1SCyrill Gorcunov 112faf60af1SCyrill Gorcunov security_task_to_inode(task, inode); 113faf60af1SCyrill Gorcunov put_task_struct(task); 114faf60af1SCyrill Gorcunov return 1; 115faf60af1SCyrill Gorcunov } 116faf60af1SCyrill Gorcunov rcu_read_unlock(); 117faf60af1SCyrill Gorcunov put_files_struct(files); 118faf60af1SCyrill Gorcunov } 119faf60af1SCyrill Gorcunov put_task_struct(task); 120faf60af1SCyrill Gorcunov } 121faf60af1SCyrill Gorcunov 122faf60af1SCyrill Gorcunov d_drop(dentry); 123faf60af1SCyrill Gorcunov return 0; 124faf60af1SCyrill Gorcunov } 125faf60af1SCyrill Gorcunov 126faf60af1SCyrill Gorcunov static const struct dentry_operations tid_fd_dentry_operations = { 127faf60af1SCyrill Gorcunov .d_revalidate = tid_fd_revalidate, 128faf60af1SCyrill Gorcunov .d_delete = pid_delete_dentry, 129faf60af1SCyrill Gorcunov }; 130faf60af1SCyrill Gorcunov 131faf60af1SCyrill Gorcunov static int proc_fd_link(struct dentry *dentry, struct path *path) 132faf60af1SCyrill Gorcunov { 133faf60af1SCyrill Gorcunov return proc_fd_info(dentry->d_inode, path, NULL); 134faf60af1SCyrill Gorcunov } 135faf60af1SCyrill Gorcunov 136faf60af1SCyrill Gorcunov static struct dentry * 137faf60af1SCyrill Gorcunov proc_fd_instantiate(struct inode *dir, struct dentry *dentry, 138faf60af1SCyrill Gorcunov struct task_struct *task, const void *ptr) 139faf60af1SCyrill Gorcunov { 140faf60af1SCyrill Gorcunov struct dentry *error = ERR_PTR(-ENOENT); 141faf60af1SCyrill Gorcunov unsigned fd = (unsigned long)ptr; 142faf60af1SCyrill Gorcunov struct proc_inode *ei; 143faf60af1SCyrill Gorcunov struct inode *inode; 144faf60af1SCyrill Gorcunov 145faf60af1SCyrill Gorcunov inode = proc_pid_make_inode(dir->i_sb, task); 146faf60af1SCyrill Gorcunov if (!inode) 147faf60af1SCyrill Gorcunov goto out; 148faf60af1SCyrill Gorcunov 149faf60af1SCyrill Gorcunov ei = PROC_I(inode); 150faf60af1SCyrill Gorcunov ei->fd = fd; 151faf60af1SCyrill Gorcunov 152faf60af1SCyrill Gorcunov inode->i_mode = S_IFLNK; 153faf60af1SCyrill Gorcunov inode->i_op = &proc_pid_link_inode_operations; 154faf60af1SCyrill Gorcunov inode->i_size = 64; 155faf60af1SCyrill Gorcunov 156faf60af1SCyrill Gorcunov ei->op.proc_get_link = proc_fd_link; 157faf60af1SCyrill Gorcunov 158faf60af1SCyrill Gorcunov d_set_d_op(dentry, &tid_fd_dentry_operations); 159faf60af1SCyrill Gorcunov d_add(dentry, inode); 160faf60af1SCyrill Gorcunov 161faf60af1SCyrill Gorcunov /* Close the race of the process dying before we return the dentry */ 162faf60af1SCyrill Gorcunov if (tid_fd_revalidate(dentry, 0)) 163faf60af1SCyrill Gorcunov error = NULL; 164faf60af1SCyrill Gorcunov out: 165faf60af1SCyrill Gorcunov return error; 166faf60af1SCyrill Gorcunov } 167faf60af1SCyrill Gorcunov 168faf60af1SCyrill Gorcunov static struct dentry *proc_lookupfd_common(struct inode *dir, 169faf60af1SCyrill Gorcunov struct dentry *dentry, 170faf60af1SCyrill Gorcunov instantiate_t instantiate) 171faf60af1SCyrill Gorcunov { 172faf60af1SCyrill Gorcunov struct task_struct *task = get_proc_task(dir); 173faf60af1SCyrill Gorcunov struct dentry *result = ERR_PTR(-ENOENT); 174faf60af1SCyrill Gorcunov unsigned fd = name_to_int(dentry); 175faf60af1SCyrill Gorcunov 176faf60af1SCyrill Gorcunov if (!task) 177faf60af1SCyrill Gorcunov goto out_no_task; 178faf60af1SCyrill Gorcunov if (fd == ~0U) 179faf60af1SCyrill Gorcunov goto out; 180faf60af1SCyrill Gorcunov 181faf60af1SCyrill Gorcunov result = instantiate(dir, dentry, task, (void *)(unsigned long)fd); 182faf60af1SCyrill Gorcunov out: 183faf60af1SCyrill Gorcunov put_task_struct(task); 184faf60af1SCyrill Gorcunov out_no_task: 185faf60af1SCyrill Gorcunov return result; 186faf60af1SCyrill Gorcunov } 187faf60af1SCyrill Gorcunov 188faf60af1SCyrill Gorcunov static int proc_readfd_common(struct file * filp, void * dirent, 189faf60af1SCyrill Gorcunov filldir_t filldir, instantiate_t instantiate) 190faf60af1SCyrill Gorcunov { 191faf60af1SCyrill Gorcunov struct dentry *dentry = filp->f_path.dentry; 192faf60af1SCyrill Gorcunov struct inode *inode = dentry->d_inode; 193faf60af1SCyrill Gorcunov struct task_struct *p = get_proc_task(inode); 194faf60af1SCyrill Gorcunov struct files_struct *files; 195faf60af1SCyrill Gorcunov unsigned int fd, ino; 196faf60af1SCyrill Gorcunov int retval; 197faf60af1SCyrill Gorcunov 198faf60af1SCyrill Gorcunov retval = -ENOENT; 199faf60af1SCyrill Gorcunov if (!p) 200faf60af1SCyrill Gorcunov goto out_no_task; 201faf60af1SCyrill Gorcunov retval = 0; 202faf60af1SCyrill Gorcunov 203faf60af1SCyrill Gorcunov fd = filp->f_pos; 204faf60af1SCyrill Gorcunov switch (fd) { 205faf60af1SCyrill Gorcunov case 0: 206faf60af1SCyrill Gorcunov if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0) 207faf60af1SCyrill Gorcunov goto out; 208faf60af1SCyrill Gorcunov filp->f_pos++; 209faf60af1SCyrill Gorcunov case 1: 210faf60af1SCyrill Gorcunov ino = parent_ino(dentry); 211faf60af1SCyrill Gorcunov if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0) 212faf60af1SCyrill Gorcunov goto out; 213faf60af1SCyrill Gorcunov filp->f_pos++; 214faf60af1SCyrill Gorcunov default: 215faf60af1SCyrill Gorcunov files = get_files_struct(p); 216faf60af1SCyrill Gorcunov if (!files) 217faf60af1SCyrill Gorcunov goto out; 218faf60af1SCyrill Gorcunov rcu_read_lock(); 219faf60af1SCyrill Gorcunov for (fd = filp->f_pos - 2; 220faf60af1SCyrill Gorcunov fd < files_fdtable(files)->max_fds; 221faf60af1SCyrill Gorcunov fd++, filp->f_pos++) { 222faf60af1SCyrill Gorcunov char name[PROC_NUMBUF]; 223faf60af1SCyrill Gorcunov int len; 224faf60af1SCyrill Gorcunov int rv; 225faf60af1SCyrill Gorcunov 226faf60af1SCyrill Gorcunov if (!fcheck_files(files, fd)) 227faf60af1SCyrill Gorcunov continue; 228faf60af1SCyrill Gorcunov rcu_read_unlock(); 229faf60af1SCyrill Gorcunov 230faf60af1SCyrill Gorcunov len = snprintf(name, sizeof(name), "%d", fd); 231faf60af1SCyrill Gorcunov rv = proc_fill_cache(filp, dirent, filldir, 232faf60af1SCyrill Gorcunov name, len, instantiate, p, 233faf60af1SCyrill Gorcunov (void *)(unsigned long)fd); 234faf60af1SCyrill Gorcunov if (rv < 0) 235faf60af1SCyrill Gorcunov goto out_fd_loop; 236faf60af1SCyrill Gorcunov rcu_read_lock(); 237faf60af1SCyrill Gorcunov } 238faf60af1SCyrill Gorcunov rcu_read_unlock(); 239faf60af1SCyrill Gorcunov out_fd_loop: 240faf60af1SCyrill Gorcunov put_files_struct(files); 241faf60af1SCyrill Gorcunov } 242faf60af1SCyrill Gorcunov out: 243faf60af1SCyrill Gorcunov put_task_struct(p); 244faf60af1SCyrill Gorcunov out_no_task: 245faf60af1SCyrill Gorcunov return retval; 246faf60af1SCyrill Gorcunov } 247faf60af1SCyrill Gorcunov 248faf60af1SCyrill Gorcunov static ssize_t proc_fdinfo_read(struct file *file, char __user *buf, 249faf60af1SCyrill Gorcunov size_t len, loff_t *ppos) 250faf60af1SCyrill Gorcunov { 251faf60af1SCyrill Gorcunov char tmp[PROC_FDINFO_MAX]; 252faf60af1SCyrill Gorcunov int err = proc_fd_info(file->f_path.dentry->d_inode, NULL, tmp); 253faf60af1SCyrill Gorcunov if (!err) 254faf60af1SCyrill Gorcunov err = simple_read_from_buffer(buf, len, ppos, tmp, strlen(tmp)); 255faf60af1SCyrill Gorcunov return err; 256faf60af1SCyrill Gorcunov } 257faf60af1SCyrill Gorcunov 258faf60af1SCyrill Gorcunov static const struct file_operations proc_fdinfo_file_operations = { 259faf60af1SCyrill Gorcunov .open = nonseekable_open, 260faf60af1SCyrill Gorcunov .read = proc_fdinfo_read, 261faf60af1SCyrill Gorcunov .llseek = no_llseek, 262faf60af1SCyrill Gorcunov }; 263faf60af1SCyrill Gorcunov 264faf60af1SCyrill Gorcunov static int proc_readfd(struct file *filp, void *dirent, filldir_t filldir) 265faf60af1SCyrill Gorcunov { 266faf60af1SCyrill Gorcunov return proc_readfd_common(filp, dirent, filldir, proc_fd_instantiate); 267faf60af1SCyrill Gorcunov } 268faf60af1SCyrill Gorcunov 269faf60af1SCyrill Gorcunov const struct file_operations proc_fd_operations = { 270faf60af1SCyrill Gorcunov .read = generic_read_dir, 271faf60af1SCyrill Gorcunov .readdir = proc_readfd, 272faf60af1SCyrill Gorcunov .llseek = default_llseek, 273faf60af1SCyrill Gorcunov }; 274faf60af1SCyrill Gorcunov 275faf60af1SCyrill Gorcunov static struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry, 276faf60af1SCyrill Gorcunov unsigned int flags) 277faf60af1SCyrill Gorcunov { 278faf60af1SCyrill Gorcunov return proc_lookupfd_common(dir, dentry, proc_fd_instantiate); 279faf60af1SCyrill Gorcunov } 280faf60af1SCyrill Gorcunov 281faf60af1SCyrill Gorcunov /* 282faf60af1SCyrill Gorcunov * /proc/pid/fd needs a special permission handler so that a process can still 283faf60af1SCyrill Gorcunov * access /proc/self/fd after it has executed a setuid(). 284faf60af1SCyrill Gorcunov */ 285faf60af1SCyrill Gorcunov int proc_fd_permission(struct inode *inode, int mask) 286faf60af1SCyrill Gorcunov { 287faf60af1SCyrill Gorcunov int rv = generic_permission(inode, mask); 288faf60af1SCyrill Gorcunov if (rv == 0) 289faf60af1SCyrill Gorcunov return 0; 290faf60af1SCyrill Gorcunov if (task_pid(current) == proc_pid(inode)) 291faf60af1SCyrill Gorcunov rv = 0; 292faf60af1SCyrill Gorcunov return rv; 293faf60af1SCyrill Gorcunov } 294faf60af1SCyrill Gorcunov 295faf60af1SCyrill Gorcunov const struct inode_operations proc_fd_inode_operations = { 296faf60af1SCyrill Gorcunov .lookup = proc_lookupfd, 297faf60af1SCyrill Gorcunov .permission = proc_fd_permission, 298faf60af1SCyrill Gorcunov .setattr = proc_setattr, 299faf60af1SCyrill Gorcunov }; 300faf60af1SCyrill Gorcunov 301faf60af1SCyrill Gorcunov static struct dentry * 302faf60af1SCyrill Gorcunov proc_fdinfo_instantiate(struct inode *dir, struct dentry *dentry, 303faf60af1SCyrill Gorcunov struct task_struct *task, const void *ptr) 304faf60af1SCyrill Gorcunov { 305faf60af1SCyrill Gorcunov struct dentry *error = ERR_PTR(-ENOENT); 306faf60af1SCyrill Gorcunov unsigned fd = (unsigned long)ptr; 307faf60af1SCyrill Gorcunov struct proc_inode *ei; 308faf60af1SCyrill Gorcunov struct inode *inode; 309faf60af1SCyrill Gorcunov 310faf60af1SCyrill Gorcunov inode = proc_pid_make_inode(dir->i_sb, task); 311faf60af1SCyrill Gorcunov if (!inode) 312faf60af1SCyrill Gorcunov goto out; 313faf60af1SCyrill Gorcunov 314faf60af1SCyrill Gorcunov ei = PROC_I(inode); 315faf60af1SCyrill Gorcunov ei->fd = fd; 316faf60af1SCyrill Gorcunov 317faf60af1SCyrill Gorcunov inode->i_mode = S_IFREG | S_IRUSR; 318faf60af1SCyrill Gorcunov inode->i_fop = &proc_fdinfo_file_operations; 319faf60af1SCyrill Gorcunov 320faf60af1SCyrill Gorcunov d_set_d_op(dentry, &tid_fd_dentry_operations); 321faf60af1SCyrill Gorcunov d_add(dentry, inode); 322faf60af1SCyrill Gorcunov 323faf60af1SCyrill Gorcunov /* Close the race of the process dying before we return the dentry */ 324faf60af1SCyrill Gorcunov if (tid_fd_revalidate(dentry, 0)) 325faf60af1SCyrill Gorcunov error = NULL; 326faf60af1SCyrill Gorcunov out: 327faf60af1SCyrill Gorcunov return error; 328faf60af1SCyrill Gorcunov } 329faf60af1SCyrill Gorcunov 330faf60af1SCyrill Gorcunov static struct dentry * 331faf60af1SCyrill Gorcunov proc_lookupfdinfo(struct inode *dir, struct dentry *dentry, unsigned int flags) 332faf60af1SCyrill Gorcunov { 333faf60af1SCyrill Gorcunov return proc_lookupfd_common(dir, dentry, proc_fdinfo_instantiate); 334faf60af1SCyrill Gorcunov } 335faf60af1SCyrill Gorcunov 336faf60af1SCyrill Gorcunov static int proc_readfdinfo(struct file *filp, void *dirent, filldir_t filldir) 337faf60af1SCyrill Gorcunov { 338faf60af1SCyrill Gorcunov return proc_readfd_common(filp, dirent, filldir, 339faf60af1SCyrill Gorcunov proc_fdinfo_instantiate); 340faf60af1SCyrill Gorcunov } 341faf60af1SCyrill Gorcunov 342faf60af1SCyrill Gorcunov const struct inode_operations proc_fdinfo_inode_operations = { 343faf60af1SCyrill Gorcunov .lookup = proc_lookupfdinfo, 344faf60af1SCyrill Gorcunov .setattr = proc_setattr, 345faf60af1SCyrill Gorcunov }; 346faf60af1SCyrill Gorcunov 347faf60af1SCyrill Gorcunov const struct file_operations proc_fdinfo_operations = { 348faf60af1SCyrill Gorcunov .read = generic_read_dir, 349faf60af1SCyrill Gorcunov .readdir = proc_readfdinfo, 350faf60af1SCyrill Gorcunov .llseek = default_llseek, 351faf60af1SCyrill Gorcunov }; 352