Syzkaller reports a sleeping function called from invalid context in do_con_write() in the 5.10 and 5.15 stable releases.
The issue has been fixed by the following upstream patch that was adapted to 5.10 and 5.15. All of the changes made to the patch in order to adapt it are described at the end of the commit message.
This patch has already been backported to the following stable branches: v6.9 - https://lore.kernel.org/all/20240625085551.368621044@linuxfoundation.org/ v6.6 - https://lore.kernel.org/all/20240625085539.398852153@linuxfoundation.org/ v6.1 - https://lore.kernel.org/all/20240625085527.625846117@linuxfoundation.org/
Found by InfoTeCS on behalf of Linux Verification Center (linuxtesting.org) with Syzkaller.
Linus Torvalds (1): tty: add the option to have a tty reject a new ldisc
drivers/tty/tty_ldisc.c | 6 ++++++ drivers/tty/vt/vt.c | 10 ++++++++++ include/linux/tty_driver.h | 8 ++++++++ 3 files changed, 24 insertions(+)
From: Linus Torvalds torvalds@linux-foundation.org
commit 6bd23e0c2bb6c65d4f5754d1456bc9a4427fc59b upstream.
... 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.o... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org [Ilia: In order to adapt this patch to branches 5.10 and 5.15, the ldisc_ok() function description has been corrected in the old style.] Signed-off-by: Gavrilov Ilia Ilia.Gavrilov@infotecs.ru --- 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 c23938b8628d..dc5267ac9923 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -579,6 +579,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 a070f2e7d960..d16b7bdbd442 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -3448,6 +3448,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) @@ -3576,6 +3585,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 2f719b471d52..315e475e6a09 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -123,6 +123,13 @@ * Optional: Called under the termios lock * * + * int (*ldisc_ok)(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. + * * void (*set_ldisc)(struct tty_struct *tty); * * This routine allows the tty driver to be notified when the @@ -270,6 +277,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, char ch);
linux-stable-mirror@lists.linaro.org