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> 10*f1f1f256SIvan Babrou #include <linux/bitmap.h> 11faf60af1SCyrill Gorcunov #include <linux/security.h> 12ddd3e077SCyrill Gorcunov #include <linux/file.h> 13ddd3e077SCyrill Gorcunov #include <linux/seq_file.h> 146c8c9031SAndrey Vagin #include <linux/fs.h> 15faf60af1SCyrill Gorcunov 16faf60af1SCyrill Gorcunov #include <linux/proc_fs.h> 17faf60af1SCyrill Gorcunov 1849d063cbSAndrey Vagin #include "../mount.h" 19faf60af1SCyrill Gorcunov #include "internal.h" 20faf60af1SCyrill Gorcunov #include "fd.h" 21faf60af1SCyrill Gorcunov 22ddd3e077SCyrill Gorcunov static int seq_show(struct seq_file *m, void *v) 23faf60af1SCyrill Gorcunov { 24faf60af1SCyrill Gorcunov struct files_struct *files = NULL; 25ddd3e077SCyrill Gorcunov int f_flags = 0, ret = -ENOENT; 26ddd3e077SCyrill Gorcunov struct file *file = NULL; 27ddd3e077SCyrill Gorcunov struct task_struct *task; 28faf60af1SCyrill Gorcunov 29ddd3e077SCyrill Gorcunov task = get_proc_task(m->private); 30ddd3e077SCyrill Gorcunov if (!task) 31ddd3e077SCyrill Gorcunov return -ENOENT; 32ddd3e077SCyrill Gorcunov 33775e0656SEric W. Biederman task_lock(task); 34775e0656SEric W. Biederman files = task->files; 35faf60af1SCyrill Gorcunov if (files) { 36771187d6SAlexey Dobriyan unsigned int fd = proc_fd(m->private); 37ddd3e077SCyrill Gorcunov 38faf60af1SCyrill Gorcunov spin_lock(&files->file_lock); 39120ce2b0SEric W. Biederman file = files_lookup_fd_locked(files, fd); 40faf60af1SCyrill Gorcunov if (file) { 41ddd3e077SCyrill Gorcunov struct fdtable *fdt = files_fdtable(files); 42faf60af1SCyrill Gorcunov 43c6f3d811SAl Viro f_flags = file->f_flags; 44faf60af1SCyrill Gorcunov if (close_on_exec(fd, fdt)) 45faf60af1SCyrill Gorcunov f_flags |= O_CLOEXEC; 46faf60af1SCyrill Gorcunov 47ddd3e077SCyrill Gorcunov get_file(file); 48ddd3e077SCyrill Gorcunov ret = 0; 49faf60af1SCyrill Gorcunov } 50faf60af1SCyrill Gorcunov spin_unlock(&files->file_lock); 51faf60af1SCyrill Gorcunov } 52775e0656SEric W. Biederman task_unlock(task); 53775e0656SEric W. Biederman put_task_struct(task); 54ddd3e077SCyrill Gorcunov 556c8c9031SAndrey Vagin if (ret) 566c8c9031SAndrey Vagin return ret; 576c8c9031SAndrey Vagin 583845f256SKalesh Singh seq_printf(m, "pos:\t%lli\nflags:\t0%o\nmnt_id:\t%i\nino:\t%lu\n", 5949d063cbSAndrey Vagin (long long)file->f_pos, f_flags, 603845f256SKalesh Singh real_mount(file->f_path.mnt)->mnt_id, 613845f256SKalesh Singh file_inode(file)->i_ino); 626c8c9031SAndrey Vagin 63775e0656SEric W. Biederman /* show_fd_locks() never deferences files so a stale value is safe */ 646c8c9031SAndrey Vagin show_fd_locks(m, file, files); 656c8c9031SAndrey Vagin if (seq_has_overflowed(m)) 666c8c9031SAndrey Vagin goto out; 676c8c9031SAndrey Vagin 6855985dd7SCyrill Gorcunov if (file->f_op->show_fdinfo) 69a3816ab0SJoe Perches file->f_op->show_fdinfo(m, file); 70faf60af1SCyrill Gorcunov 716c8c9031SAndrey Vagin out: 726c8c9031SAndrey Vagin fput(file); 736c8c9031SAndrey Vagin return 0; 74ddd3e077SCyrill Gorcunov } 75ddd3e077SCyrill Gorcunov 761927e498SKalesh Singh static int proc_fdinfo_access_allowed(struct inode *inode) 77ddd3e077SCyrill Gorcunov { 787bc3fa01SKalesh Singh bool allowed = false; 797bc3fa01SKalesh Singh struct task_struct *task = get_proc_task(inode); 807bc3fa01SKalesh Singh 817bc3fa01SKalesh Singh if (!task) 827bc3fa01SKalesh Singh return -ESRCH; 837bc3fa01SKalesh Singh 847bc3fa01SKalesh Singh allowed = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS); 857bc3fa01SKalesh Singh put_task_struct(task); 867bc3fa01SKalesh Singh 877bc3fa01SKalesh Singh if (!allowed) 887bc3fa01SKalesh Singh return -EACCES; 897bc3fa01SKalesh Singh 901927e498SKalesh Singh return 0; 911927e498SKalesh Singh } 921927e498SKalesh Singh 931927e498SKalesh Singh static int seq_fdinfo_open(struct inode *inode, struct file *file) 941927e498SKalesh Singh { 951927e498SKalesh Singh int ret = proc_fdinfo_access_allowed(inode); 961927e498SKalesh Singh 971927e498SKalesh Singh if (ret) 981927e498SKalesh Singh return ret; 991927e498SKalesh Singh 100ddd3e077SCyrill Gorcunov return single_open(file, seq_show, inode); 101ddd3e077SCyrill Gorcunov } 102ddd3e077SCyrill Gorcunov 103ddd3e077SCyrill Gorcunov static const struct file_operations proc_fdinfo_file_operations = { 104ddd3e077SCyrill Gorcunov .open = seq_fdinfo_open, 105ddd3e077SCyrill Gorcunov .read = seq_read, 106ddd3e077SCyrill Gorcunov .llseek = seq_lseek, 107ddd3e077SCyrill Gorcunov .release = single_release, 108ddd3e077SCyrill Gorcunov }; 109ddd3e077SCyrill Gorcunov 1101ae9bd8bSAl Viro static bool tid_fd_mode(struct task_struct *task, unsigned fd, fmode_t *mode) 1111ae9bd8bSAl Viro { 1121ae9bd8bSAl Viro struct file *file; 1131ae9bd8bSAl Viro 1141ae9bd8bSAl Viro rcu_read_lock(); 11564eb661fSEric W. Biederman file = task_lookup_fd_rcu(task, fd); 1161ae9bd8bSAl Viro if (file) 1171ae9bd8bSAl Viro *mode = file->f_mode; 1181ae9bd8bSAl Viro rcu_read_unlock(); 1191ae9bd8bSAl Viro return !!file; 1201ae9bd8bSAl Viro } 1211ae9bd8bSAl Viro 12298836386SAl Viro static void tid_fd_update_inode(struct task_struct *task, struct inode *inode, 12398836386SAl Viro fmode_t f_mode) 124faf60af1SCyrill Gorcunov { 12568eb94f1SEric W. Biederman task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid); 126faf60af1SCyrill Gorcunov 127faf60af1SCyrill Gorcunov if (S_ISLNK(inode->i_mode)) { 128faf60af1SCyrill Gorcunov unsigned i_mode = S_IFLNK; 129faf60af1SCyrill Gorcunov if (f_mode & FMODE_READ) 130faf60af1SCyrill Gorcunov i_mode |= S_IRUSR | S_IXUSR; 131faf60af1SCyrill Gorcunov if (f_mode & FMODE_WRITE) 132faf60af1SCyrill Gorcunov i_mode |= S_IWUSR | S_IXUSR; 133faf60af1SCyrill Gorcunov inode->i_mode = i_mode; 134faf60af1SCyrill Gorcunov } 135faf60af1SCyrill Gorcunov security_task_to_inode(task, inode); 13698836386SAl Viro } 13798836386SAl Viro 13898836386SAl Viro static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags) 13998836386SAl Viro { 14098836386SAl Viro struct task_struct *task; 14198836386SAl Viro struct inode *inode; 14298836386SAl Viro unsigned int fd; 14398836386SAl Viro 14498836386SAl Viro if (flags & LOOKUP_RCU) 14598836386SAl Viro return -ECHILD; 14698836386SAl Viro 14798836386SAl Viro inode = d_inode(dentry); 14898836386SAl Viro task = get_proc_task(inode); 14998836386SAl Viro fd = proc_fd(inode); 15098836386SAl Viro 15198836386SAl Viro if (task) { 15298836386SAl Viro fmode_t f_mode; 15398836386SAl Viro if (tid_fd_mode(task, fd, &f_mode)) { 15498836386SAl Viro tid_fd_update_inode(task, inode, f_mode); 155faf60af1SCyrill Gorcunov put_task_struct(task); 156faf60af1SCyrill Gorcunov return 1; 157faf60af1SCyrill Gorcunov } 158faf60af1SCyrill Gorcunov put_task_struct(task); 159faf60af1SCyrill Gorcunov } 160faf60af1SCyrill Gorcunov return 0; 161faf60af1SCyrill Gorcunov } 162faf60af1SCyrill Gorcunov 163faf60af1SCyrill Gorcunov static const struct dentry_operations tid_fd_dentry_operations = { 164faf60af1SCyrill Gorcunov .d_revalidate = tid_fd_revalidate, 165faf60af1SCyrill Gorcunov .d_delete = pid_delete_dentry, 166faf60af1SCyrill Gorcunov }; 167faf60af1SCyrill Gorcunov 168faf60af1SCyrill Gorcunov static int proc_fd_link(struct dentry *dentry, struct path *path) 169faf60af1SCyrill Gorcunov { 170ddd3e077SCyrill Gorcunov struct task_struct *task; 171ddd3e077SCyrill Gorcunov int ret = -ENOENT; 172ddd3e077SCyrill Gorcunov 1732b0143b5SDavid Howells task = get_proc_task(d_inode(dentry)); 174ddd3e077SCyrill Gorcunov if (task) { 175771187d6SAlexey Dobriyan unsigned int fd = proc_fd(d_inode(dentry)); 176ddd3e077SCyrill Gorcunov struct file *fd_file; 177ddd3e077SCyrill Gorcunov 178439be326SEric W. Biederman fd_file = fget_task(task, fd); 179ddd3e077SCyrill Gorcunov if (fd_file) { 180ddd3e077SCyrill Gorcunov *path = fd_file->f_path; 181ddd3e077SCyrill Gorcunov path_get(&fd_file->f_path); 182ddd3e077SCyrill Gorcunov ret = 0; 183439be326SEric W. Biederman fput(fd_file); 184ddd3e077SCyrill Gorcunov } 185439be326SEric W. Biederman put_task_struct(task); 186ddd3e077SCyrill Gorcunov } 187ddd3e077SCyrill Gorcunov 188ddd3e077SCyrill Gorcunov return ret; 189faf60af1SCyrill Gorcunov } 190faf60af1SCyrill Gorcunov 19198836386SAl Viro struct fd_data { 19298836386SAl Viro fmode_t mode; 19398836386SAl Viro unsigned fd; 19498836386SAl Viro }; 19598836386SAl Viro 1960168b9e3SAl Viro static struct dentry *proc_fd_instantiate(struct dentry *dentry, 197faf60af1SCyrill Gorcunov struct task_struct *task, const void *ptr) 198faf60af1SCyrill Gorcunov { 19998836386SAl Viro const struct fd_data *data = ptr; 200faf60af1SCyrill Gorcunov struct proc_inode *ei; 201faf60af1SCyrill Gorcunov struct inode *inode; 202faf60af1SCyrill Gorcunov 2030168b9e3SAl Viro inode = proc_pid_make_inode(dentry->d_sb, task, S_IFLNK); 204faf60af1SCyrill Gorcunov if (!inode) 2050168b9e3SAl Viro return ERR_PTR(-ENOENT); 206faf60af1SCyrill Gorcunov 207faf60af1SCyrill Gorcunov ei = PROC_I(inode); 20898836386SAl Viro ei->fd = data->fd; 209faf60af1SCyrill Gorcunov 210faf60af1SCyrill Gorcunov inode->i_op = &proc_pid_link_inode_operations; 211faf60af1SCyrill Gorcunov inode->i_size = 64; 212faf60af1SCyrill Gorcunov 213faf60af1SCyrill Gorcunov ei->op.proc_get_link = proc_fd_link; 21498836386SAl Viro tid_fd_update_inode(task, inode, data->mode); 215faf60af1SCyrill Gorcunov 216faf60af1SCyrill Gorcunov d_set_d_op(dentry, &tid_fd_dentry_operations); 2170168b9e3SAl Viro return d_splice_alias(inode, dentry); 218faf60af1SCyrill Gorcunov } 219faf60af1SCyrill Gorcunov 220faf60af1SCyrill Gorcunov static struct dentry *proc_lookupfd_common(struct inode *dir, 221faf60af1SCyrill Gorcunov struct dentry *dentry, 222faf60af1SCyrill Gorcunov instantiate_t instantiate) 223faf60af1SCyrill Gorcunov { 224faf60af1SCyrill Gorcunov struct task_struct *task = get_proc_task(dir); 22598836386SAl Viro struct fd_data data = {.fd = name_to_int(&dentry->d_name)}; 2260168b9e3SAl Viro struct dentry *result = ERR_PTR(-ENOENT); 227faf60af1SCyrill Gorcunov 228faf60af1SCyrill Gorcunov if (!task) 229faf60af1SCyrill Gorcunov goto out_no_task; 23098836386SAl Viro if (data.fd == ~0U) 231faf60af1SCyrill Gorcunov goto out; 23298836386SAl Viro if (!tid_fd_mode(task, data.fd, &data.mode)) 2331ae9bd8bSAl Viro goto out; 234faf60af1SCyrill Gorcunov 2350168b9e3SAl Viro result = instantiate(dentry, task, &data); 236faf60af1SCyrill Gorcunov out: 237faf60af1SCyrill Gorcunov put_task_struct(task); 238faf60af1SCyrill Gorcunov out_no_task: 2390168b9e3SAl Viro return result; 240faf60af1SCyrill Gorcunov } 241faf60af1SCyrill Gorcunov 242f0c3b509SAl Viro static int proc_readfd_common(struct file *file, struct dir_context *ctx, 243f0c3b509SAl Viro instantiate_t instantiate) 244faf60af1SCyrill Gorcunov { 245f0c3b509SAl Viro struct task_struct *p = get_proc_task(file_inode(file)); 246f0c3b509SAl Viro unsigned int fd; 247faf60af1SCyrill Gorcunov 248faf60af1SCyrill Gorcunov if (!p) 249f0c3b509SAl Viro return -ENOENT; 250faf60af1SCyrill Gorcunov 251f0c3b509SAl Viro if (!dir_emit_dots(file, ctx)) 252faf60af1SCyrill Gorcunov goto out; 253f0c3b509SAl Viro 254faf60af1SCyrill Gorcunov rcu_read_lock(); 2555b17b618SEric W. Biederman for (fd = ctx->pos - 2;; fd++) { 25698836386SAl Viro struct file *f; 25798836386SAl Viro struct fd_data data; 258e3912ac3SAlexey Dobriyan char name[10 + 1]; 259a4ef3895SAlexey Dobriyan unsigned int len; 260faf60af1SCyrill Gorcunov 2615b17b618SEric W. Biederman f = task_lookup_next_fd_rcu(p, &fd); 2625b17b618SEric W. Biederman ctx->pos = fd + 2LL; 26398836386SAl Viro if (!f) 2645b17b618SEric W. Biederman break; 26598836386SAl Viro data.mode = f->f_mode; 266faf60af1SCyrill Gorcunov rcu_read_unlock(); 26798836386SAl Viro data.fd = fd; 268faf60af1SCyrill Gorcunov 269771187d6SAlexey Dobriyan len = snprintf(name, sizeof(name), "%u", fd); 270f0c3b509SAl Viro if (!proc_fill_cache(file, ctx, 271faf60af1SCyrill Gorcunov name, len, instantiate, p, 27298836386SAl Viro &data)) 2735b17b618SEric W. Biederman goto out; 2743cc4a84eSEric Dumazet cond_resched(); 275faf60af1SCyrill Gorcunov rcu_read_lock(); 276faf60af1SCyrill Gorcunov } 277faf60af1SCyrill Gorcunov rcu_read_unlock(); 278faf60af1SCyrill Gorcunov out: 279faf60af1SCyrill Gorcunov put_task_struct(p); 280f0c3b509SAl Viro return 0; 281faf60af1SCyrill Gorcunov } 282faf60af1SCyrill Gorcunov 283*f1f1f256SIvan Babrou static int proc_readfd_count(struct inode *inode, loff_t *count) 284*f1f1f256SIvan Babrou { 285*f1f1f256SIvan Babrou struct task_struct *p = get_proc_task(inode); 286*f1f1f256SIvan Babrou struct fdtable *fdt; 287*f1f1f256SIvan Babrou 288*f1f1f256SIvan Babrou if (!p) 289*f1f1f256SIvan Babrou return -ENOENT; 290*f1f1f256SIvan Babrou 291*f1f1f256SIvan Babrou task_lock(p); 292*f1f1f256SIvan Babrou if (p->files) { 293*f1f1f256SIvan Babrou rcu_read_lock(); 294*f1f1f256SIvan Babrou 295*f1f1f256SIvan Babrou fdt = files_fdtable(p->files); 296*f1f1f256SIvan Babrou *count = bitmap_weight(fdt->open_fds, fdt->max_fds); 297*f1f1f256SIvan Babrou 298*f1f1f256SIvan Babrou rcu_read_unlock(); 299*f1f1f256SIvan Babrou } 300*f1f1f256SIvan Babrou task_unlock(p); 301*f1f1f256SIvan Babrou 302*f1f1f256SIvan Babrou put_task_struct(p); 303*f1f1f256SIvan Babrou 304*f1f1f256SIvan Babrou return 0; 305*f1f1f256SIvan Babrou } 306*f1f1f256SIvan Babrou 307f0c3b509SAl Viro static int proc_readfd(struct file *file, struct dir_context *ctx) 308faf60af1SCyrill Gorcunov { 309f0c3b509SAl Viro return proc_readfd_common(file, ctx, proc_fd_instantiate); 310faf60af1SCyrill Gorcunov } 311faf60af1SCyrill Gorcunov 312faf60af1SCyrill Gorcunov const struct file_operations proc_fd_operations = { 313faf60af1SCyrill Gorcunov .read = generic_read_dir, 314f50752eaSAl Viro .iterate_shared = proc_readfd, 315f50752eaSAl Viro .llseek = generic_file_llseek, 316faf60af1SCyrill Gorcunov }; 317faf60af1SCyrill Gorcunov 318faf60af1SCyrill Gorcunov static struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry, 319faf60af1SCyrill Gorcunov unsigned int flags) 320faf60af1SCyrill Gorcunov { 321faf60af1SCyrill Gorcunov return proc_lookupfd_common(dir, dentry, proc_fd_instantiate); 322faf60af1SCyrill Gorcunov } 323faf60af1SCyrill Gorcunov 324faf60af1SCyrill Gorcunov /* 325faf60af1SCyrill Gorcunov * /proc/pid/fd needs a special permission handler so that a process can still 326faf60af1SCyrill Gorcunov * access /proc/self/fd after it has executed a setuid(). 327faf60af1SCyrill Gorcunov */ 328549c7297SChristian Brauner int proc_fd_permission(struct user_namespace *mnt_userns, 329549c7297SChristian Brauner struct inode *inode, int mask) 330faf60af1SCyrill Gorcunov { 33154708d28SOleg Nesterov struct task_struct *p; 33254708d28SOleg Nesterov int rv; 33354708d28SOleg Nesterov 33447291baaSChristian Brauner rv = generic_permission(&init_user_ns, inode, mask); 335faf60af1SCyrill Gorcunov if (rv == 0) 33654708d28SOleg Nesterov return rv; 33754708d28SOleg Nesterov 33854708d28SOleg Nesterov rcu_read_lock(); 33954708d28SOleg Nesterov p = pid_task(proc_pid(inode), PIDTYPE_PID); 34054708d28SOleg Nesterov if (p && same_thread_group(p, current)) 341faf60af1SCyrill Gorcunov rv = 0; 34254708d28SOleg Nesterov rcu_read_unlock(); 34354708d28SOleg Nesterov 344faf60af1SCyrill Gorcunov return rv; 345faf60af1SCyrill Gorcunov } 346faf60af1SCyrill Gorcunov 347*f1f1f256SIvan Babrou static int proc_fd_getattr(struct user_namespace *mnt_userns, 348*f1f1f256SIvan Babrou const struct path *path, struct kstat *stat, 349*f1f1f256SIvan Babrou u32 request_mask, unsigned int query_flags) 350*f1f1f256SIvan Babrou { 351*f1f1f256SIvan Babrou struct inode *inode = d_inode(path->dentry); 352*f1f1f256SIvan Babrou int rv = 0; 353*f1f1f256SIvan Babrou 354*f1f1f256SIvan Babrou generic_fillattr(&init_user_ns, inode, stat); 355*f1f1f256SIvan Babrou 356*f1f1f256SIvan Babrou /* If it's a directory, put the number of open fds there */ 357*f1f1f256SIvan Babrou if (S_ISDIR(inode->i_mode)) { 358*f1f1f256SIvan Babrou rv = proc_readfd_count(inode, &stat->size); 359*f1f1f256SIvan Babrou if (rv < 0) 360*f1f1f256SIvan Babrou return rv; 361*f1f1f256SIvan Babrou } 362*f1f1f256SIvan Babrou 363*f1f1f256SIvan Babrou return rv; 364*f1f1f256SIvan Babrou } 365*f1f1f256SIvan Babrou 366faf60af1SCyrill Gorcunov const struct inode_operations proc_fd_inode_operations = { 367faf60af1SCyrill Gorcunov .lookup = proc_lookupfd, 368faf60af1SCyrill Gorcunov .permission = proc_fd_permission, 369*f1f1f256SIvan Babrou .getattr = proc_fd_getattr, 370faf60af1SCyrill Gorcunov .setattr = proc_setattr, 371faf60af1SCyrill Gorcunov }; 372faf60af1SCyrill Gorcunov 3730168b9e3SAl Viro static struct dentry *proc_fdinfo_instantiate(struct dentry *dentry, 374faf60af1SCyrill Gorcunov struct task_struct *task, const void *ptr) 375faf60af1SCyrill Gorcunov { 37698836386SAl Viro const struct fd_data *data = ptr; 377faf60af1SCyrill Gorcunov struct proc_inode *ei; 378faf60af1SCyrill Gorcunov struct inode *inode; 379faf60af1SCyrill Gorcunov 3807bc3fa01SKalesh Singh inode = proc_pid_make_inode(dentry->d_sb, task, S_IFREG | S_IRUGO); 381faf60af1SCyrill Gorcunov if (!inode) 3820168b9e3SAl Viro return ERR_PTR(-ENOENT); 383faf60af1SCyrill Gorcunov 384faf60af1SCyrill Gorcunov ei = PROC_I(inode); 38598836386SAl Viro ei->fd = data->fd; 386faf60af1SCyrill Gorcunov 387faf60af1SCyrill Gorcunov inode->i_fop = &proc_fdinfo_file_operations; 38898836386SAl Viro tid_fd_update_inode(task, inode, 0); 389faf60af1SCyrill Gorcunov 390faf60af1SCyrill Gorcunov d_set_d_op(dentry, &tid_fd_dentry_operations); 3910168b9e3SAl Viro return d_splice_alias(inode, dentry); 392faf60af1SCyrill Gorcunov } 393faf60af1SCyrill Gorcunov 394faf60af1SCyrill Gorcunov static struct dentry * 395faf60af1SCyrill Gorcunov proc_lookupfdinfo(struct inode *dir, struct dentry *dentry, unsigned int flags) 396faf60af1SCyrill Gorcunov { 397faf60af1SCyrill Gorcunov return proc_lookupfd_common(dir, dentry, proc_fdinfo_instantiate); 398faf60af1SCyrill Gorcunov } 399faf60af1SCyrill Gorcunov 400f0c3b509SAl Viro static int proc_readfdinfo(struct file *file, struct dir_context *ctx) 401faf60af1SCyrill Gorcunov { 402f0c3b509SAl Viro return proc_readfd_common(file, ctx, 403faf60af1SCyrill Gorcunov proc_fdinfo_instantiate); 404faf60af1SCyrill Gorcunov } 405faf60af1SCyrill Gorcunov 4061927e498SKalesh Singh static int proc_open_fdinfo(struct inode *inode, struct file *file) 4071927e498SKalesh Singh { 4081927e498SKalesh Singh int ret = proc_fdinfo_access_allowed(inode); 4091927e498SKalesh Singh 4101927e498SKalesh Singh if (ret) 4111927e498SKalesh Singh return ret; 4121927e498SKalesh Singh 4131927e498SKalesh Singh return 0; 4141927e498SKalesh Singh } 4151927e498SKalesh Singh 416faf60af1SCyrill Gorcunov const struct inode_operations proc_fdinfo_inode_operations = { 417faf60af1SCyrill Gorcunov .lookup = proc_lookupfdinfo, 418faf60af1SCyrill Gorcunov .setattr = proc_setattr, 419faf60af1SCyrill Gorcunov }; 420faf60af1SCyrill Gorcunov 421faf60af1SCyrill Gorcunov const struct file_operations proc_fdinfo_operations = { 4221927e498SKalesh Singh .open = proc_open_fdinfo, 423faf60af1SCyrill Gorcunov .read = generic_read_dir, 424f50752eaSAl Viro .iterate_shared = proc_readfdinfo, 425f50752eaSAl Viro .llseek = generic_file_llseek, 426faf60af1SCyrill Gorcunov }; 427