Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 6bd23e0

Browse files
torvaldsgregkh
authored andcommitted
tty: add the option to have a tty reject a new ldisc
... 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>
1 parent a47cf07 commit 6bd23e0

File tree

3 files changed

+24
-0
lines changed

3 files changed

+24
-0
lines changed

drivers/tty/tty_ldisc.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,12 @@ int tty_set_ldisc(struct tty_struct *tty, int disc)
545545
goto out;
546546
}
547547

548+
if (tty->ops->ldisc_ok) {
549+
retval = tty->ops->ldisc_ok(tty, disc);
550+
if (retval)
551+
goto out;
552+
}
553+
548554
old_ldisc = tty->ldisc;
549555

550556
/* Shutdown the old discipline. */

drivers/tty/vt/vt.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3576,6 +3576,15 @@ static void con_cleanup(struct tty_struct *tty)
35763576
tty_port_put(&vc->port);
35773577
}
35783578

3579+
/*
3580+
* We can't deal with anything but the N_TTY ldisc,
3581+
* because we can sleep in our write() routine.
3582+
*/
3583+
static int con_ldisc_ok(struct tty_struct *tty, int ldisc)
3584+
{
3585+
return ldisc == N_TTY ? 0 : -EINVAL;
3586+
}
3587+
35793588
static int default_color = 7; /* white */
35803589
static int default_italic_color = 2; // green (ASCII)
35813590
static int default_underline_color = 3; // cyan (ASCII)
@@ -3695,6 +3704,7 @@ static const struct tty_operations con_ops = {
36953704
.resize = vt_resize,
36963705
.shutdown = con_shutdown,
36973706
.cleanup = con_cleanup,
3707+
.ldisc_ok = con_ldisc_ok,
36983708
};
36993709

37003710
static struct cdev vc0_cdev;

include/linux/tty_driver.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,13 @@ struct serial_struct;
154154
*
155155
* Optional. Called under the @tty->termios_rwsem. May sleep.
156156
*
157+
* @ldisc_ok: ``int ()(struct tty_struct *tty, int ldisc)``
158+
*
159+
* This routine allows the @tty driver to decide if it can deal
160+
* with a particular @ldisc.
161+
*
162+
* Optional. Called under the @tty->ldisc_sem and @tty->termios_rwsem.
163+
*
157164
* @set_ldisc: ``void ()(struct tty_struct *tty)``
158165
*
159166
* This routine allows the @tty driver to be notified when the device's
@@ -372,6 +379,7 @@ struct tty_operations {
372379
void (*hangup)(struct tty_struct *tty);
373380
int (*break_ctl)(struct tty_struct *tty, int state);
374381
void (*flush_buffer)(struct tty_struct *tty);
382+
int (*ldisc_ok)(struct tty_struct *tty, int ldisc);
375383
void (*set_ldisc)(struct tty_struct *tty);
376384
void (*wait_until_sent)(struct tty_struct *tty, int timeout);
377385
void (*send_xchar)(struct tty_struct *tty, u8 ch);

0 commit comments

Comments
 (0)