Re: [PATCH v2] tty: n_gsm: restrict tty devices to attach

From: Linus Torvalds
Date: Sun Apr 21 2024 - 13:19:01 EST


On Sun, 21 Apr 2024 at 09:04, Linus Torvalds
<torvalds@xxxxxxxxxxxxxxxxxxxx> wrote:
>
> The only option is to *mark* the ones that are atomic. Which was my suggestion.

Actually, another option would be to just return an error at 'set_ldisc()' time.

Sadly, the actual "tty->ops->set_ldisc()" function not only returns
'void' (easy enough to change - there aren't that many of them), but
it's called too late after the old ldisc has already been dropped.
It's basically a "inform tty about new ldisc" and is not useful for a
"is this ok"?

But we could trivially add a "ldisc_ok()" function, and have the vt
driver say "I only accept N_TTY".

Something like this ENTIRELY UNTESTED patch.

Again - this is untested, and maybe there are other tty drivers that
have issues with the stranger line disciplines, but this at least
seems simple and fairly easy to explain why we do what we do..

And if pty's really need the same thing, that would be easy to add.
But I actually think that at least pty slaves should *not* limit
ldiscs, because the whole point of a pty slave is to look like another
tty. If you want to emulate a serial device over a network, the way to
do it would be with a pty.

Hmm?

Linus
drivers/tty/tty_ldisc.c | 6 ++++++
drivers/tty/vt/vt.c | 10 ++++++++++
include/linux/tty_driver.h | 8 ++++++++
3 files changed, 24 insertions(+)

diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 3f68e213df1f..d80e9d4c974b 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -545,6 +545,12 @@ int tty_set_ldisc(struct tty_struct *tty, int disc)
goto out;
}

+ if (tty->ops->ldisc_ok) {
+ retval = tty->ops->ldisc_ok(tty, disc);
+ if (retval)
+ goto out;
+ }
+
old_ldisc = tty->ldisc;

/* Shutdown the old discipline. */
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 9b5b98dfc8b4..cd87e3d1291e 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -3576,6 +3576,15 @@ static void con_cleanup(struct tty_struct *tty)
tty_port_put(&vc->port);
}

+/*
+ * We can't deal with anything but the N_TTY ldisc,
+ * because we can sleep in our write() routine.
+ */
+static int con_ldisc_ok(struct tty_struct *tty, int ldisc)
+{
+ return ldisc == N_TTY ? 0 : -EINVAL;
+}
+
static int default_color = 7; /* white */
static int default_italic_color = 2; // green (ASCII)
static int default_underline_color = 3; // cyan (ASCII)
@@ -3695,6 +3704,7 @@ static const struct tty_operations con_ops = {
.resize = vt_resize,
.shutdown = con_shutdown,
.cleanup = con_cleanup,
+ .ldisc_ok = con_ldisc_ok,
};

static struct cdev vc0_cdev;
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 7372124fbf90..dd4b31ce6d5d 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -154,6 +154,13 @@ struct serial_struct;
*
* Optional. Called under the @tty->termios_rwsem. May sleep.
*
+ * @ldisc_ok: ``int ()(struct tty_struct *tty, int ldisc)``
+ *
+ * This routine allows the @tty driver to decide if it can deal
+ * with a particular @ldisc.
+ *
+ * Optional. Called under the @tty->ldisc_sem and @tty->termios_rwsem.
+ *
* @set_ldisc: ``void ()(struct tty_struct *tty)``
*
* This routine allows the @tty driver to be notified when the device's
@@ -372,6 +379,7 @@ struct tty_operations {
void (*hangup)(struct tty_struct *tty);
int (*break_ctl)(struct tty_struct *tty, int state);
void (*flush_buffer)(struct tty_struct *tty);
+ int (*ldisc_ok)(struct tty_struct *tty, int ldisc);
void (*set_ldisc)(struct tty_struct *tty);
void (*wait_until_sent)(struct tty_struct *tty, int timeout);
void (*send_xchar)(struct tty_struct *tty, u8 ch);