vfs: Fix /proc/<tid>/fdinfo/<fd> file handling
Cyrill Gorcunov reports that I broke the fdinfo files with commit30a08bf2d3
("proc: move fd symlink i_mode calculations into tid_fd_revalidate()"), and he's quite right. The tid_fd_revalidate() function is not just used for the <tid>/fd symlinks, it's also used for the <tid>/fdinfo/<fd> files, and the permission model for those are different. So do the dynamic symlink permission handling just for symlinks, making the fdinfo files once more appear as the proper regular files they are. Of course, Al Viro argued (probably correctly) that we shouldn't do the symlink permission games at all, and make the symlinks always just be the normal 'lrwxrwxrwx'. That would have avoided this issue too, but since somebody noticed that the permissions had changed (which was the reason for that original commit30a08bf2d3
in the first place), people do apparently use this feature. [ Basically, you can use the symlink permission data as a cheap "fdinfo" replacement, since you see whether the file is open for reading and/or writing by just looking at st_mode of the symlink. So the feature does make sense, even if the pain it has caused means we probably shouldn't have done it to begin with. ] Reported-and-tested-by: Cyrill Gorcunov <gorcunov@openvz.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
5041caa4d5
commit
0640113be2
1 changed files with 10 additions and 7 deletions
|
@ -1803,7 +1803,7 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
|
|||
rcu_read_lock();
|
||||
file = fcheck_files(files, fd);
|
||||
if (file) {
|
||||
unsigned i_mode, f_mode = file->f_mode;
|
||||
unsigned f_mode = file->f_mode;
|
||||
|
||||
rcu_read_unlock();
|
||||
put_files_struct(files);
|
||||
|
@ -1819,12 +1819,14 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
|
|||
inode->i_gid = GLOBAL_ROOT_GID;
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
|
@ -1859,6 +1861,7 @@ static struct dentry *proc_fd_instantiate(struct inode *dir,
|
|||
ei = PROC_I(inode);
|
||||
ei->fd = fd;
|
||||
|
||||
inode->i_mode = S_IFLNK;
|
||||
inode->i_op = &proc_pid_link_inode_operations;
|
||||
inode->i_size = 64;
|
||||
ei->op.proc_get_link = proc_fd_link;
|
||||
|
|
Loading…
Reference in a new issue