Commit 5b0afd4b 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

mainline inclusion
from mainline-v6.10-rc1
commit 6bd23e0c2bb6c65d4f5754d1456bc9a4427fc59b
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/torvalds/linux.git/commit/?id=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>
Conflicts:
	include/linux/tty_driver.h
[Not merge commit 1fe18309 ("tty: add kernel-doc for tty_operations"),and context conflicts]
Signed-off-by: default avatarYi Yang <yiyang13@huawei.com>
parent b64d0f05
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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. */
+10 −0
Original line number Diff line number Diff line
@@ -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;
+1 −0
Original line number Diff line number Diff line
@@ -256,6 +256,7 @@ struct tty_operations {
		      const unsigned char *buf, int count);
	int  (*put_char)(struct tty_struct *tty, unsigned char ch);
	void (*flush_chars)(struct tty_struct *tty);
	int (*ldisc_ok)(struct tty_struct *tty, int ldisc);
	int  (*write_room)(struct tty_struct *tty);
	int  (*chars_in_buffer)(struct tty_struct *tty);
	int  (*ioctl)(struct tty_struct *tty,