History

pty: fix the cached path of the pty slave file descriptor in the master

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'.

Linus Torvalds committed 9 years ago

Commit c8c03f11 parent ac9a4093 files · +9 −4Browse files

Unified · Split

3 files
  1. drivers/tty/pty.c +5 −2
  2. fs/devpts/inode.c +3 −1
  3. include/linux/devpts_fs.h +1 −1
drivers/tty/pty.c+5−2
@@ -793,6 +793,7 @@ static int ptmx_open(struct inode *inode, struct file *filp) · 792 unmodified lines
793793 struct tty_struct *tty;
794794 struct path *pts_path;
795795 struct dentry *dentry;
796+ struct vfsmount *mnt;
796797 int retval;
797798 int index;
798799
@@ -805,7 +806,7 @@ static int ptmx_open(struct inode *inode, struct file *filp) · 6 unmodified lines
805806 if (retval)
806807 return retval;
807808
808− fsi = devpts_acquire(filp);
809+ fsi = devpts_acquire(filp, &mnt);
809810 if (IS_ERR(fsi)) {
810811 retval = PTR_ERR(fsi);
811812 goto out_free_file;
@@ -849,7 +850,7 @@ static int ptmx_open(struct inode *inode, struct file *filp) · 37 unmodified lines
849850 pts_path = kmalloc(sizeof(struct path), GFP_KERNEL);
850851 if (!pts_path)
851852 goto err_release;
852− pts_path->mnt = filp->f_path.mnt;
853+ pts_path->mnt = mnt;
853854 pts_path->dentry = dentry;
854855 path_get(pts_path);
855856 tty->link->driver_data = pts_path;
@@ -866,6 +867,7 @@ err_path_put: · 10 unmodified lines
866867 path_put(pts_path);
867868 kfree(pts_path);
868869 err_release:
870+ mntput(mnt);
869871 tty_unlock(tty);
870872 // This will also put-ref the fsi
871873 tty_release(inode, filp);
@@ -874,6 +876,7 @@ out: · 2 unmodified lines
874876 devpts_kill_index(fsi, index);
875877 out_put_fsi:
876878 devpts_release(fsi);
879+ mntput(mnt);
877880 out_free_file:
878881 tty_free_file(filp);
879882 return retval;
fs/devpts/inode.c+3−1
@@ -133,7 +133,7 @@ static inline struct pts_fs_info *DEVPTS_SB(struct super_block *sb) · 132 unmodified lines
133133 return sb->s_fs_info;
134134 }
135135
136−struct pts_fs_info *devpts_acquire(struct file *filp)
136+struct pts_fs_info *devpts_acquire(struct file *filp, struct vfsmount **ptsmnt)
137137 {
138138 struct pts_fs_info *result;
139139 struct path path;
@@ -142,6 +142,7 @@ struct pts_fs_info *devpts_acquire(struct file *filp) · 2 unmodified lines
142142
143143 path = filp->f_path;
144144 path_get(&path);
145+ *ptsmnt = NULL;
145146
146147 /* Has the devpts filesystem already been found? */
147148 sb = path.mnt->mnt_sb;
@@ -165,6 +166,7 @@ struct pts_fs_info *devpts_acquire(struct file *filp) · 17 unmodified lines
165166 * pty code needs to hold extra references in case of last /dev/tty close
166167 */
167168 atomic_inc(&sb->s_active);
169+ *ptsmnt = mntget(path.mnt);
168170 result = DEVPTS_SB(sb);
169171
170172 out:
include/linux/devpts_fs.h+1−1
@@ -19,7 +19,7 @@ · 18 unmodified lines
1919
2020 struct pts_fs_info;
2121
22−struct pts_fs_info *devpts_acquire(struct file *);
22+struct pts_fs_info *devpts_acquire(struct file *, struct vfsmount **ptsmnt);
2323 void devpts_release(struct pts_fs_info *);
2424
2525 int devpts_new_index(struct pts_fs_info *);