Skip to content

Commit

Permalink
pty: fix the cached path of the pty slave file descriptor in the master
Browse files Browse the repository at this point in the history
Christian Brauner reported that if you use the TIOCGPTPEER ioctl() to
get a slave pty file descriptor, the resulting file descriptor doesn't
look right in /proc/<pid>/fd/<fd>.  In particular, he wanted to use
readlink() on /proc/self/fd/<fd> to get the pathname of the slave pty
(basically implementing "ptsname{_r}()").

The reason for that was that we had generated the wrong 'struct path'
when we create the pty in ptmx_open().

In particular, the dentry was correct, but the vfsmount pointed to the
mount of the ptmx node. That _can_ be correct - in case you use
"/dev/pts/ptmx" to open the master - but usually is not.  The normal
case is to use /dev/ptmx, which then looks up the pts/ directory, and
then the vfsmount of the ptmx node is obviously the /dev directory, not
the /dev/pts/ directory.

We actually did have the right vfsmount available, but in the wrong
place (it gets looked up in 'devpts_acquire()' when we get a reference
to the pts filesystem), and so ptmx_open() used the wrong mnt pointer.

The end result of this confusion was that the pty worked fine, but when
if you did TIOCGPTPEER to get the slave side of the pty, end end result
would also work, but have that dodgy 'struct path'.

And then when doing "d_path()" on to get the pathname, the vfsmount
would not match the root of the pts directory, and d_path() would return
an empty pathname thinking that the entry had escaped a bind mount into
another mount.

This fixes the problem by making devpts_acquire() return the vfsmount
for the pts filesystem, allowing ptmx_open() to trivially just use the
right mount for the pts dentry, and create the proper 'struct path'.

Reported-by: Christian Brauner <[email protected]>
Cc: Al Viro <[email protected]>
Acked-by: Eric Biederman <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
torvalds committed Aug 17, 2017
1 parent ac9a409 commit c8c03f1
Show file tree
Hide file tree
Showing 3 changed files with 9 additions and 4 deletions.
7 changes: 5 additions & 2 deletions drivers/tty/pty.c
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
struct tty_struct *tty;
struct path *pts_path;
struct dentry *dentry;
struct vfsmount *mnt;
int retval;
int index;

Expand All @@ -805,7 +806,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
if (retval)
return retval;

fsi = devpts_acquire(filp);
fsi = devpts_acquire(filp, &mnt);
if (IS_ERR(fsi)) {
retval = PTR_ERR(fsi);
goto out_free_file;
Expand Down Expand Up @@ -849,7 +850,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
pts_path = kmalloc(sizeof(struct path), GFP_KERNEL);
if (!pts_path)
goto err_release;
pts_path->mnt = filp->f_path.mnt;
pts_path->mnt = mnt;
pts_path->dentry = dentry;
path_get(pts_path);
tty->link->driver_data = pts_path;
Expand All @@ -866,6 +867,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
path_put(pts_path);
kfree(pts_path);
err_release:
mntput(mnt);
tty_unlock(tty);
// This will also put-ref the fsi
tty_release(inode, filp);
Expand All @@ -874,6 +876,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
devpts_kill_index(fsi, index);
out_put_fsi:
devpts_release(fsi);
mntput(mnt);
out_free_file:
tty_free_file(filp);
return retval;
Expand Down
4 changes: 3 additions & 1 deletion fs/devpts/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ static inline struct pts_fs_info *DEVPTS_SB(struct super_block *sb)
return sb->s_fs_info;
}

struct pts_fs_info *devpts_acquire(struct file *filp)
struct pts_fs_info *devpts_acquire(struct file *filp, struct vfsmount **ptsmnt)
{
struct pts_fs_info *result;
struct path path;
Expand All @@ -142,6 +142,7 @@ struct pts_fs_info *devpts_acquire(struct file *filp)

path = filp->f_path;
path_get(&path);
*ptsmnt = NULL;

/* Has the devpts filesystem already been found? */
sb = path.mnt->mnt_sb;
Expand All @@ -165,6 +166,7 @@ struct pts_fs_info *devpts_acquire(struct file *filp)
* pty code needs to hold extra references in case of last /dev/tty close
*/
atomic_inc(&sb->s_active);
*ptsmnt = mntget(path.mnt);
result = DEVPTS_SB(sb);

out:
Expand Down
2 changes: 1 addition & 1 deletion include/linux/devpts_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

struct pts_fs_info;

struct pts_fs_info *devpts_acquire(struct file *);
struct pts_fs_info *devpts_acquire(struct file *, struct vfsmount **ptsmnt);
void devpts_release(struct pts_fs_info *);

int devpts_new_index(struct pts_fs_info *);
Expand Down

0 comments on commit c8c03f1

Please sign in to comment.