aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2018-05-02 22:42:22 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2018-05-22 14:28:04 -0400
commit1ae9bd8b7e4912b238a14adc7c559a7ecbb9c062 (patch)
tree118b9f6c708060ea5286d46a879b5efd5c3a4ef7
parent1bbc55131e59bd099fdc568d3aa0b42634dbd188 (diff)
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 <viro@zeniv.linux.org.uk>
-rw-r--r--fs/proc/fd.c63
1 files changed, 34 insertions, 29 deletions
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 = {
81 .release = single_release, 81 .release = single_release,
82}; 82};
83 83
84static bool tid_fd_mode(struct task_struct *task, unsigned fd, fmode_t *mode)
85{
86 struct files_struct *files = get_files_struct(task);
87 struct file *file;
88
89 if (!files)
90 return false;
91
92 rcu_read_lock();
93 file = fcheck_files(files, fd);
94 if (file)
95 *mode = file->f_mode;
96 rcu_read_unlock();
97 put_files_struct(files);
98 return !!file;
99}
100
84static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags) 101static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags)
85{ 102{
86 struct files_struct *files;
87 struct task_struct *task; 103 struct task_struct *task;
88 struct inode *inode; 104 struct inode *inode;
89 unsigned int fd; 105 unsigned int fd;
106 fmode_t f_mode;
90 107
91 if (flags & LOOKUP_RCU) 108 if (flags & LOOKUP_RCU)
92 return -ECHILD; 109 return -ECHILD;
@@ -96,35 +113,20 @@ static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags)
96 fd = proc_fd(inode); 113 fd = proc_fd(inode);
97 114
98 if (task) { 115 if (task) {
99 files = get_files_struct(task); 116 if (tid_fd_mode(task, fd, &f_mode)) {
100 if (files) { 117 task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid);
101 struct file *file; 118
102 119 if (S_ISLNK(inode->i_mode)) {
103 rcu_read_lock(); 120 unsigned i_mode = S_IFLNK;
104 file = fcheck_files(files, fd); 121 if (f_mode & FMODE_READ)
105 if (file) { 122 i_mode |= S_IRUSR | S_IXUSR;
106 unsigned f_mode = file->f_mode; 123 if (f_mode & FMODE_WRITE)
107 124 i_mode |= S_IWUSR | S_IXUSR;
108 rcu_read_unlock(); 125 inode->i_mode = i_mode;
109 put_files_struct(files);
110
111 task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid);
112
113 if (S_ISLNK(inode->i_mode)) {
114 unsigned i_mode = S_IFLNK;
115 if (f_mode & FMODE_READ)
116 i_mode |= S_IRUSR | S_IXUSR;
117 if (f_mode & FMODE_WRITE)
118 i_mode |= S_IWUSR | S_IXUSR;
119 inode->i_mode = i_mode;
120 }
121
122 security_task_to_inode(task, inode);
123 put_task_struct(task);
124 return 1;
125 } 126 }
126 rcu_read_unlock(); 127 security_task_to_inode(task, inode);
127 put_files_struct(files); 128 put_task_struct(task);
129 return 1;
128 } 130 }
129 put_task_struct(task); 131 put_task_struct(task);
130 } 132 }
@@ -203,11 +205,14 @@ static struct dentry *proc_lookupfd_common(struct inode *dir,
203 struct task_struct *task = get_proc_task(dir); 205 struct task_struct *task = get_proc_task(dir);
204 int result = -ENOENT; 206 int result = -ENOENT;
205 unsigned fd = name_to_int(&dentry->d_name); 207 unsigned fd = name_to_int(&dentry->d_name);
208 fmode_t f_mode;
206 209
207 if (!task) 210 if (!task)
208 goto out_no_task; 211 goto out_no_task;
209 if (fd == ~0U) 212 if (fd == ~0U)
210 goto out; 213 goto out;
214 if (!tid_fd_mode(task, fd, &f_mode))
215 goto out;
211 216
212 result = instantiate(dir, dentry, task, (void *)(unsigned long)fd); 217 result = instantiate(dir, dentry, task, (void *)(unsigned long)fd);
213out: 218out: