diff options
Diffstat (limited to 'drivers/tty/pty.c')
-rw-r--r-- | drivers/tty/pty.c | 85 |
1 files changed, 83 insertions, 2 deletions
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 65799575c666..64338442050e 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 1991, 1992 Linus Torvalds * @@ -24,6 +25,9 @@ #include <linux/slab.h> #include <linux/mutex.h> #include <linux/poll.h> +#include <linux/mount.h> +#include <linux/file.h> +#include <linux/ioctl.h> #undef TTY_DEBUG_HANGUP #ifdef TTY_DEBUG_HANGUP @@ -481,6 +485,16 @@ static int pty_bsd_ioctl(struct tty_struct *tty, return -ENOIOCTLCMD; } +static long pty_bsd_compat_ioctl(struct tty_struct *tty, + unsigned int cmd, unsigned long arg) +{ + /* + * PTY ioctls don't require any special translation between 32-bit and + * 64-bit userspace, they are already compatible. + */ + return pty_bsd_ioctl(tty, cmd, arg); +} + static int legacy_count = CONFIG_LEGACY_PTY_COUNT; /* * not really modular, but the easiest way to keep compat with existing @@ -502,6 +516,7 @@ static const struct tty_operations master_pty_ops_bsd = { .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, .ioctl = pty_bsd_ioctl, + .compat_ioctl = pty_bsd_compat_ioctl, .cleanup = pty_cleanup, .resize = pty_resize, .remove = pty_remove @@ -585,9 +600,58 @@ static inline void legacy_pty_init(void) { } /* Unix98 devices */ #ifdef CONFIG_UNIX98_PTYS - static struct cdev ptmx_cdev; +/** + * ptm_open_peer - open the peer of a pty + * @master: the open struct file of the ptmx device node + * @tty: the master of the pty being opened + * @flags: the flags for open + * + * Provide a race free way for userspace to open the slave end of a pty + * (where they have the master fd and cannot access or trust the mount + * namespace /dev/pts was mounted inside). + */ +int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags) +{ + int fd = -1; + struct file *filp; + int retval = -EINVAL; + struct path path; + + if (tty->driver != ptm_driver) + return -EIO; + + fd = get_unused_fd_flags(0); + if (fd < 0) { + retval = fd; + goto err; + } + + /* Compute the slave's path */ + path.mnt = devpts_mntget(master, tty->driver_data); + if (IS_ERR(path.mnt)) { + retval = PTR_ERR(path.mnt); + goto err_put; + } + path.dentry = tty->link->driver_data; + + filp = dentry_open(&path, flags, current_cred()); + mntput(path.mnt); + if (IS_ERR(filp)) { + retval = PTR_ERR(filp); + goto err_put; + } + + fd_install(fd, filp); + return fd; + +err_put: + put_unused_fd(fd); +err: + return retval; +} + static int pty_unix98_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { @@ -609,6 +673,16 @@ static int pty_unix98_ioctl(struct tty_struct *tty, return -ENOIOCTLCMD; } +static long pty_unix98_compat_ioctl(struct tty_struct *tty, + unsigned int cmd, unsigned long arg) +{ + /* + * PTY ioctls don't require any special translation between 32-bit and + * 64-bit userspace, they are already compatible. + */ + return pty_unix98_ioctl(tty, cmd, arg); +} + /** * ptm_unix98_lookup - find a pty master * @driver: ptm driver @@ -669,6 +743,11 @@ static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) } } +static void pty_show_fdinfo(struct tty_struct *tty, struct seq_file *m) +{ + seq_printf(m, "tty-index:\t%d\n", tty->index); +} + static const struct tty_operations ptm_unix98_ops = { .lookup = ptm_unix98_lookup, .install = pty_unix98_install, @@ -681,8 +760,10 @@ static const struct tty_operations ptm_unix98_ops = { .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, .ioctl = pty_unix98_ioctl, + .compat_ioctl = pty_unix98_compat_ioctl, .resize = pty_resize, - .cleanup = pty_cleanup + .cleanup = pty_cleanup, + .show_fdinfo = pty_show_fdinfo, }; static const struct tty_operations pty_unix98_ops = { |