Skip to content

Commit 0640113

Browse files
committed
vfs: Fix /proc/<tid>/fdinfo/<fd> file handling
Cyrill Gorcunov reports that I broke the fdinfo files with commit 30a08bf ("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 commit 30a08bf 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>
1 parent 5041caa commit 0640113

File tree

1 file changed

+10
-7
lines changed

1 file changed

+10
-7
lines changed

fs/proc/base.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1803,7 +1803,7 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
18031803
rcu_read_lock();
18041804
file = fcheck_files(files, fd);
18051805
if (file) {
1806-
unsigned i_mode, f_mode = file->f_mode;
1806+
unsigned f_mode = file->f_mode;
18071807

18081808
rcu_read_unlock();
18091809
put_files_struct(files);
@@ -1819,12 +1819,14 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
18191819
inode->i_gid = GLOBAL_ROOT_GID;
18201820
}
18211821

1822-
i_mode = S_IFLNK;
1823-
if (f_mode & FMODE_READ)
1824-
i_mode |= S_IRUSR | S_IXUSR;
1825-
if (f_mode & FMODE_WRITE)
1826-
i_mode |= S_IWUSR | S_IXUSR;
1827-
inode->i_mode = i_mode;
1822+
if (S_ISLNK(inode->i_mode)) {
1823+
unsigned i_mode = S_IFLNK;
1824+
if (f_mode & FMODE_READ)
1825+
i_mode |= S_IRUSR | S_IXUSR;
1826+
if (f_mode & FMODE_WRITE)
1827+
i_mode |= S_IWUSR | S_IXUSR;
1828+
inode->i_mode = i_mode;
1829+
}
18281830

18291831
security_task_to_inode(task, inode);
18301832
put_task_struct(task);
@@ -1859,6 +1861,7 @@ static struct dentry *proc_fd_instantiate(struct inode *dir,
18591861
ei = PROC_I(inode);
18601862
ei->fd = fd;
18611863

1864+
inode->i_mode = S_IFLNK;
18621865
inode->i_op = &proc_pid_link_inode_operations;
18631866
inode->i_size = 64;
18641867
ei->op.proc_get_link = proc_fd_link;

0 commit comments

Comments
 (0)