Commit 8ebd8aa7 authored by Linus Torvalds's avatar Linus Torvalds Committed by Yi Yang
Browse files

tty: add the option to have a tty reject a new ldisc

stable inclusion
from stable-v6.6.36
commit 287b569a5b914903ba7c438a3c0dbc3410ebb409
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IACT4T
CVE: CVE-2024-40966

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=287b569a5b914903ba7c438a3c0dbc3410ebb409



--------------------------------

[ Upstream commit 6bd23e0c2bb6c65d4f5754d1456bc9a4427fc59b ]

... 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: default avatarTetsuo 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: default avatarsyzbot <syzbot+dbac96d8e73b61aa559c@syzkaller.appspotmail.com>
Closes: https://syzkaller.appspot.com/bug?extid=dbac96d8e73b61aa559c


Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Link: https://lore.kernel.org/r/20240423163339.59780-1-torvalds@linux-foundation.org


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Signed-off-by: default avatarYi Yang <yiyang13@huawei.com>
parent 130fc493
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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. */
+10 −0
Original line number Diff line number Diff line
@@ -3390,6 +3390,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)
@@ -3509,6 +3518,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;
+8 −0
Original line number Diff line number Diff line
@@ -156,6 +156,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
@@ -374,6 +381,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);