162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/sched/signal.h> 362306a36Sopenharmony_ci#include <linux/errno.h> 462306a36Sopenharmony_ci#include <linux/dcache.h> 562306a36Sopenharmony_ci#include <linux/path.h> 662306a36Sopenharmony_ci#include <linux/fdtable.h> 762306a36Sopenharmony_ci#include <linux/namei.h> 862306a36Sopenharmony_ci#include <linux/pid.h> 962306a36Sopenharmony_ci#include <linux/ptrace.h> 1062306a36Sopenharmony_ci#include <linux/bitmap.h> 1162306a36Sopenharmony_ci#include <linux/security.h> 1262306a36Sopenharmony_ci#include <linux/file.h> 1362306a36Sopenharmony_ci#include <linux/seq_file.h> 1462306a36Sopenharmony_ci#include <linux/fs.h> 1562306a36Sopenharmony_ci#include <linux/filelock.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/proc_fs.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "../mount.h" 2062306a36Sopenharmony_ci#include "internal.h" 2162306a36Sopenharmony_ci#include "fd.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic int seq_show(struct seq_file *m, void *v) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct files_struct *files = NULL; 2662306a36Sopenharmony_ci int f_flags = 0, ret = -ENOENT; 2762306a36Sopenharmony_ci struct file *file = NULL; 2862306a36Sopenharmony_ci struct task_struct *task; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci task = get_proc_task(m->private); 3162306a36Sopenharmony_ci if (!task) 3262306a36Sopenharmony_ci return -ENOENT; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci task_lock(task); 3562306a36Sopenharmony_ci files = task->files; 3662306a36Sopenharmony_ci if (files) { 3762306a36Sopenharmony_ci unsigned int fd = proc_fd(m->private); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci spin_lock(&files->file_lock); 4062306a36Sopenharmony_ci file = files_lookup_fd_locked(files, fd); 4162306a36Sopenharmony_ci if (file) { 4262306a36Sopenharmony_ci struct fdtable *fdt = files_fdtable(files); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci f_flags = file->f_flags; 4562306a36Sopenharmony_ci if (close_on_exec(fd, fdt)) 4662306a36Sopenharmony_ci f_flags |= O_CLOEXEC; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci get_file(file); 4962306a36Sopenharmony_ci ret = 0; 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci spin_unlock(&files->file_lock); 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci task_unlock(task); 5462306a36Sopenharmony_ci put_task_struct(task); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci if (ret) 5762306a36Sopenharmony_ci return ret; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci seq_printf(m, "pos:\t%lli\nflags:\t0%o\nmnt_id:\t%i\nino:\t%lu\n", 6062306a36Sopenharmony_ci (long long)file->f_pos, f_flags, 6162306a36Sopenharmony_ci real_mount(file->f_path.mnt)->mnt_id, 6262306a36Sopenharmony_ci file_inode(file)->i_ino); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci /* show_fd_locks() never deferences files so a stale value is safe */ 6562306a36Sopenharmony_ci show_fd_locks(m, file, files); 6662306a36Sopenharmony_ci if (seq_has_overflowed(m)) 6762306a36Sopenharmony_ci goto out; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (file->f_op->show_fdinfo) 7062306a36Sopenharmony_ci file->f_op->show_fdinfo(m, file); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ciout: 7362306a36Sopenharmony_ci fput(file); 7462306a36Sopenharmony_ci return 0; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic int proc_fdinfo_access_allowed(struct inode *inode) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci bool allowed = false; 8062306a36Sopenharmony_ci struct task_struct *task = get_proc_task(inode); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (!task) 8362306a36Sopenharmony_ci return -ESRCH; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci allowed = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS); 8662306a36Sopenharmony_ci put_task_struct(task); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (!allowed) 8962306a36Sopenharmony_ci return -EACCES; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci return 0; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic int seq_fdinfo_open(struct inode *inode, struct file *file) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci int ret = proc_fdinfo_access_allowed(inode); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (ret) 9962306a36Sopenharmony_ci return ret; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci return single_open(file, seq_show, inode); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic const struct file_operations proc_fdinfo_file_operations = { 10562306a36Sopenharmony_ci .open = seq_fdinfo_open, 10662306a36Sopenharmony_ci .read = seq_read, 10762306a36Sopenharmony_ci .llseek = seq_lseek, 10862306a36Sopenharmony_ci .release = single_release, 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic bool tid_fd_mode(struct task_struct *task, unsigned fd, fmode_t *mode) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci struct file *file; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci rcu_read_lock(); 11662306a36Sopenharmony_ci file = task_lookup_fd_rcu(task, fd); 11762306a36Sopenharmony_ci if (file) 11862306a36Sopenharmony_ci *mode = file->f_mode; 11962306a36Sopenharmony_ci rcu_read_unlock(); 12062306a36Sopenharmony_ci return !!file; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic void tid_fd_update_inode(struct task_struct *task, struct inode *inode, 12462306a36Sopenharmony_ci fmode_t f_mode) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (S_ISLNK(inode->i_mode)) { 12962306a36Sopenharmony_ci unsigned i_mode = S_IFLNK; 13062306a36Sopenharmony_ci if (f_mode & FMODE_READ) 13162306a36Sopenharmony_ci i_mode |= S_IRUSR | S_IXUSR; 13262306a36Sopenharmony_ci if (f_mode & FMODE_WRITE) 13362306a36Sopenharmony_ci i_mode |= S_IWUSR | S_IXUSR; 13462306a36Sopenharmony_ci inode->i_mode = i_mode; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci security_task_to_inode(task, inode); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic int tid_fd_revalidate(struct dentry *dentry, unsigned int flags) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci struct task_struct *task; 14262306a36Sopenharmony_ci struct inode *inode; 14362306a36Sopenharmony_ci unsigned int fd; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (flags & LOOKUP_RCU) 14662306a36Sopenharmony_ci return -ECHILD; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci inode = d_inode(dentry); 14962306a36Sopenharmony_ci task = get_proc_task(inode); 15062306a36Sopenharmony_ci fd = proc_fd(inode); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if (task) { 15362306a36Sopenharmony_ci fmode_t f_mode; 15462306a36Sopenharmony_ci if (tid_fd_mode(task, fd, &f_mode)) { 15562306a36Sopenharmony_ci tid_fd_update_inode(task, inode, f_mode); 15662306a36Sopenharmony_ci put_task_struct(task); 15762306a36Sopenharmony_ci return 1; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci put_task_struct(task); 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci return 0; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic const struct dentry_operations tid_fd_dentry_operations = { 16562306a36Sopenharmony_ci .d_revalidate = tid_fd_revalidate, 16662306a36Sopenharmony_ci .d_delete = pid_delete_dentry, 16762306a36Sopenharmony_ci}; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic int proc_fd_link(struct dentry *dentry, struct path *path) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct task_struct *task; 17262306a36Sopenharmony_ci int ret = -ENOENT; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci task = get_proc_task(d_inode(dentry)); 17562306a36Sopenharmony_ci if (task) { 17662306a36Sopenharmony_ci unsigned int fd = proc_fd(d_inode(dentry)); 17762306a36Sopenharmony_ci struct file *fd_file; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci fd_file = fget_task(task, fd); 18062306a36Sopenharmony_ci if (fd_file) { 18162306a36Sopenharmony_ci *path = fd_file->f_path; 18262306a36Sopenharmony_ci path_get(&fd_file->f_path); 18362306a36Sopenharmony_ci ret = 0; 18462306a36Sopenharmony_ci fput(fd_file); 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci put_task_struct(task); 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci return ret; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistruct fd_data { 19362306a36Sopenharmony_ci fmode_t mode; 19462306a36Sopenharmony_ci unsigned fd; 19562306a36Sopenharmony_ci}; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic struct dentry *proc_fd_instantiate(struct dentry *dentry, 19862306a36Sopenharmony_ci struct task_struct *task, const void *ptr) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci const struct fd_data *data = ptr; 20162306a36Sopenharmony_ci struct proc_inode *ei; 20262306a36Sopenharmony_ci struct inode *inode; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci inode = proc_pid_make_inode(dentry->d_sb, task, S_IFLNK); 20562306a36Sopenharmony_ci if (!inode) 20662306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci ei = PROC_I(inode); 20962306a36Sopenharmony_ci ei->fd = data->fd; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci inode->i_op = &proc_pid_link_inode_operations; 21262306a36Sopenharmony_ci inode->i_size = 64; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci ei->op.proc_get_link = proc_fd_link; 21562306a36Sopenharmony_ci tid_fd_update_inode(task, inode, data->mode); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci d_set_d_op(dentry, &tid_fd_dentry_operations); 21862306a36Sopenharmony_ci return d_splice_alias(inode, dentry); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic struct dentry *proc_lookupfd_common(struct inode *dir, 22262306a36Sopenharmony_ci struct dentry *dentry, 22362306a36Sopenharmony_ci instantiate_t instantiate) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct task_struct *task = get_proc_task(dir); 22662306a36Sopenharmony_ci struct fd_data data = {.fd = name_to_int(&dentry->d_name)}; 22762306a36Sopenharmony_ci struct dentry *result = ERR_PTR(-ENOENT); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if (!task) 23062306a36Sopenharmony_ci goto out_no_task; 23162306a36Sopenharmony_ci if (data.fd == ~0U) 23262306a36Sopenharmony_ci goto out; 23362306a36Sopenharmony_ci if (!tid_fd_mode(task, data.fd, &data.mode)) 23462306a36Sopenharmony_ci goto out; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci result = instantiate(dentry, task, &data); 23762306a36Sopenharmony_ciout: 23862306a36Sopenharmony_ci put_task_struct(task); 23962306a36Sopenharmony_ciout_no_task: 24062306a36Sopenharmony_ci return result; 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic int proc_readfd_common(struct file *file, struct dir_context *ctx, 24462306a36Sopenharmony_ci instantiate_t instantiate) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct task_struct *p = get_proc_task(file_inode(file)); 24762306a36Sopenharmony_ci unsigned int fd; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (!p) 25062306a36Sopenharmony_ci return -ENOENT; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci if (!dir_emit_dots(file, ctx)) 25362306a36Sopenharmony_ci goto out; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci rcu_read_lock(); 25662306a36Sopenharmony_ci for (fd = ctx->pos - 2;; fd++) { 25762306a36Sopenharmony_ci struct file *f; 25862306a36Sopenharmony_ci struct fd_data data; 25962306a36Sopenharmony_ci char name[10 + 1]; 26062306a36Sopenharmony_ci unsigned int len; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci f = task_lookup_next_fd_rcu(p, &fd); 26362306a36Sopenharmony_ci ctx->pos = fd + 2LL; 26462306a36Sopenharmony_ci if (!f) 26562306a36Sopenharmony_ci break; 26662306a36Sopenharmony_ci data.mode = f->f_mode; 26762306a36Sopenharmony_ci rcu_read_unlock(); 26862306a36Sopenharmony_ci data.fd = fd; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci len = snprintf(name, sizeof(name), "%u", fd); 27162306a36Sopenharmony_ci if (!proc_fill_cache(file, ctx, 27262306a36Sopenharmony_ci name, len, instantiate, p, 27362306a36Sopenharmony_ci &data)) 27462306a36Sopenharmony_ci goto out; 27562306a36Sopenharmony_ci cond_resched(); 27662306a36Sopenharmony_ci rcu_read_lock(); 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci rcu_read_unlock(); 27962306a36Sopenharmony_ciout: 28062306a36Sopenharmony_ci put_task_struct(p); 28162306a36Sopenharmony_ci return 0; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic int proc_readfd_count(struct inode *inode, loff_t *count) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci struct task_struct *p = get_proc_task(inode); 28762306a36Sopenharmony_ci struct fdtable *fdt; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (!p) 29062306a36Sopenharmony_ci return -ENOENT; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci task_lock(p); 29362306a36Sopenharmony_ci if (p->files) { 29462306a36Sopenharmony_ci rcu_read_lock(); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci fdt = files_fdtable(p->files); 29762306a36Sopenharmony_ci *count = bitmap_weight(fdt->open_fds, fdt->max_fds); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci rcu_read_unlock(); 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci task_unlock(p); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci put_task_struct(p); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci return 0; 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic int proc_readfd(struct file *file, struct dir_context *ctx) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci return proc_readfd_common(file, ctx, proc_fd_instantiate); 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ciconst struct file_operations proc_fd_operations = { 31462306a36Sopenharmony_ci .read = generic_read_dir, 31562306a36Sopenharmony_ci .iterate_shared = proc_readfd, 31662306a36Sopenharmony_ci .llseek = generic_file_llseek, 31762306a36Sopenharmony_ci}; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry, 32062306a36Sopenharmony_ci unsigned int flags) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci return proc_lookupfd_common(dir, dentry, proc_fd_instantiate); 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci/* 32662306a36Sopenharmony_ci * /proc/pid/fd needs a special permission handler so that a process can still 32762306a36Sopenharmony_ci * access /proc/self/fd after it has executed a setuid(). 32862306a36Sopenharmony_ci */ 32962306a36Sopenharmony_ciint proc_fd_permission(struct mnt_idmap *idmap, 33062306a36Sopenharmony_ci struct inode *inode, int mask) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci struct task_struct *p; 33362306a36Sopenharmony_ci int rv; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci rv = generic_permission(&nop_mnt_idmap, inode, mask); 33662306a36Sopenharmony_ci if (rv == 0) 33762306a36Sopenharmony_ci return rv; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci rcu_read_lock(); 34062306a36Sopenharmony_ci p = pid_task(proc_pid(inode), PIDTYPE_PID); 34162306a36Sopenharmony_ci if (p && same_thread_group(p, current)) 34262306a36Sopenharmony_ci rv = 0; 34362306a36Sopenharmony_ci rcu_read_unlock(); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci return rv; 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic int proc_fd_getattr(struct mnt_idmap *idmap, 34962306a36Sopenharmony_ci const struct path *path, struct kstat *stat, 35062306a36Sopenharmony_ci u32 request_mask, unsigned int query_flags) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci struct inode *inode = d_inode(path->dentry); 35362306a36Sopenharmony_ci int rv = 0; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* If it's a directory, put the number of open fds there */ 35862306a36Sopenharmony_ci if (S_ISDIR(inode->i_mode)) { 35962306a36Sopenharmony_ci rv = proc_readfd_count(inode, &stat->size); 36062306a36Sopenharmony_ci if (rv < 0) 36162306a36Sopenharmony_ci return rv; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci return rv; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ciconst struct inode_operations proc_fd_inode_operations = { 36862306a36Sopenharmony_ci .lookup = proc_lookupfd, 36962306a36Sopenharmony_ci .permission = proc_fd_permission, 37062306a36Sopenharmony_ci .getattr = proc_fd_getattr, 37162306a36Sopenharmony_ci .setattr = proc_setattr, 37262306a36Sopenharmony_ci}; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic struct dentry *proc_fdinfo_instantiate(struct dentry *dentry, 37562306a36Sopenharmony_ci struct task_struct *task, const void *ptr) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci const struct fd_data *data = ptr; 37862306a36Sopenharmony_ci struct proc_inode *ei; 37962306a36Sopenharmony_ci struct inode *inode; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci inode = proc_pid_make_inode(dentry->d_sb, task, S_IFREG | S_IRUGO); 38262306a36Sopenharmony_ci if (!inode) 38362306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci ei = PROC_I(inode); 38662306a36Sopenharmony_ci ei->fd = data->fd; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci inode->i_fop = &proc_fdinfo_file_operations; 38962306a36Sopenharmony_ci tid_fd_update_inode(task, inode, 0); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci d_set_d_op(dentry, &tid_fd_dentry_operations); 39262306a36Sopenharmony_ci return d_splice_alias(inode, dentry); 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic struct dentry * 39662306a36Sopenharmony_ciproc_lookupfdinfo(struct inode *dir, struct dentry *dentry, unsigned int flags) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci return proc_lookupfd_common(dir, dentry, proc_fdinfo_instantiate); 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic int proc_readfdinfo(struct file *file, struct dir_context *ctx) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci return proc_readfd_common(file, ctx, 40462306a36Sopenharmony_ci proc_fdinfo_instantiate); 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic int proc_open_fdinfo(struct inode *inode, struct file *file) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci int ret = proc_fdinfo_access_allowed(inode); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (ret) 41262306a36Sopenharmony_ci return ret; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci return 0; 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ciconst struct inode_operations proc_fdinfo_inode_operations = { 41862306a36Sopenharmony_ci .lookup = proc_lookupfdinfo, 41962306a36Sopenharmony_ci .setattr = proc_setattr, 42062306a36Sopenharmony_ci}; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ciconst struct file_operations proc_fdinfo_operations = { 42362306a36Sopenharmony_ci .open = proc_open_fdinfo, 42462306a36Sopenharmony_ci .read = generic_read_dir, 42562306a36Sopenharmony_ci .iterate_shared = proc_readfdinfo, 42662306a36Sopenharmony_ci .llseek = generic_file_llseek, 42762306a36Sopenharmony_ci}; 428