From 1ae9bd8b7e4912b238a14adc7c559a7ecbb9c062 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 2 May 2018 22:42:22 -0400 Subject: proc_lookupfd_common(): don't bother with instantiate unless the file is open ... and take the "check if file is open, pick ->f_mode" into a helper; tid_fd_revalidate() can use it. The next patch will get rid of tid_fd_revalidate() calls in instantiate callbacks. Signed-off-by: Al Viro --- fs/proc/fd.c | 63 ++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 34 insertions(+), 29 deletions(-) (limited to 'fs/proc') diff --git a/fs/proc/fd.c b/fs/proc/fd.c index 6b80cd1e419a..d38845ecc408 100644 --- a/fs/proc/fd.c +++ b/fs/proc/fd.c @@ -81,12 +81,29 @@ static const struct file_operations proc_fdinfo_file_operations = { .release = single_release, }; +static bool tid_fd_mode(struct task_struct *task, unsigned fd, fmode_t *mode) +{ + struct files_struct *files = get_files_struct(task); + struct file *file; + + if (!files) + return false; + + rcu_read_lock(); + file = fcheck_files(files, fd); + if (file) + *mode = file->f_mode; + rcu_read_unlock(); + put_files_struct(files); + return !!file; +} + static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags) { - struct files_struct *files; struct task_struct *task; struct inode *inode; unsigned int fd; + fmode_t f_mode; if (flags & LOOKUP_RCU) return -ECHILD; @@ -96,35 +113,20 @@ static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags) fd = proc_fd(inode); if (task) { - files = get_files_struct(task); - if (files) { - struct file *file; - - rcu_read_lock(); - file = fcheck_files(files, fd); - if (file) { - unsigned f_mode = file->f_mode; - - rcu_read_unlock(); - put_files_struct(files); - - task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid); - - if (S_ISLNK(inode->i_mode)) { - unsigned i_mode = S_IFLNK; - if (f_mode & FMODE_READ) - i_mode |= S_IRUSR | S_IXUSR; - if (f_mode & FMODE_WRITE) - i_mode |= S_IWUSR | S_IXUSR; - inode->i_mode = i_mode; - } - - security_task_to_inode(task, inode); - put_task_struct(task); - return 1; + if (tid_fd_mode(task, fd, &f_mode)) { + task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid); + + if (S_ISLNK(inode->i_mode)) { + unsigned i_mode = S_IFLNK; + if (f_mode & FMODE_READ) + i_mode |= S_IRUSR | S_IXUSR; + if (f_mode & FMODE_WRITE) + i_mode |= S_IWUSR | S_IXUSR; + inode->i_mode = i_mode; } - rcu_read_unlock(); - put_files_struct(files); + security_task_to_inode(task, inode); + put_task_struct(task); + return 1; } put_task_struct(task); } @@ -203,11 +205,14 @@ static struct dentry *proc_lookupfd_common(struct inode *dir, struct task_struct *task = get_proc_task(dir); int result = -ENOENT; unsigned fd = name_to_int(&dentry->d_name); + fmode_t f_mode; if (!task) goto out_no_task; if (fd == ~0U) goto out; + if (!tid_fd_mode(task, fd, &f_mode)) + goto out; result = instantiate(dir, dentry, task, (void *)(unsigned long)fd); out: -- cgit v1.2.3