Skip to content

Commit

Permalink
tty: add the option to have a tty reject a new ldisc
Browse files Browse the repository at this point in the history
BugLink: https://bugs.launchpad.net/bugs/2075154

[ Upstream commit 6bd23e0 ]

... and use it to limit the virtual terminals to just N_TTY.  They are
kind of special, and in particular, the "con_write()" routine violates
the "writes cannot sleep" rule that some ldiscs rely on.

This avoids the

   BUG: sleeping function called from invalid context at kernel/printk/printk.c:2659

when N_GSM has been attached to a virtual console, and gsmld_write()
calls con_write() while holding a spinlock, and con_write() then tries
to get the console lock.

Tested-by: Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp>
Cc: Jiri Slaby <jirislaby@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Daniel Starke <daniel.starke@siemens.com>
Reported-by: syzbot <syzbot+dbac96d8e73b61aa559c@syzkaller.appspotmail.com>
Closes: https://syzkaller.appspot.com/bug?extid=dbac96d8e73b61aa559c
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Link: https://lore.kernel.org/r/20240423163339.59780-1-torvalds@linux-foundation.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Manuel Diewald <manuel.diewald@canonical.com>
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
Signed-off-by: Roxana Nicolescu <roxana.nicolescu@canonical.com>
  • Loading branch information
torvalds authored and roxanan1996 committed Aug 13, 2024
1 parent fcd272f commit 6f25087
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 0 deletions.
6 changes: 6 additions & 0 deletions drivers/tty/tty_ldisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
10 changes: 10 additions & 0 deletions drivers/tty/vt/vt.c
Original file line number Diff line number Diff line change
Expand Up @@ -3396,6 +3396,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)
Expand Down Expand Up @@ -3515,6 +3524,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;
Expand Down
8 changes: 8 additions & 0 deletions include/linux/tty_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 6f25087

Please sign in to comment.