summaryrefslogtreecommitdiff
path: root/drivers/tty/pty.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/pty.c')
-rw-r--r--drivers/tty/pty.c85
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 = {