TTY/Serial fixes for 4.18-rc3
Here are 5 fixes for the tty core and some serial drivers. The tty core one fix some security and other issues reported by the syzbot that I have taken too long in responding to (sorry Tetsuo!). The 8350 serial driver fix resolves an issue of devices that used to work properly stopping working as they shouldn't have been added to a blacklist. All of these have been in linux-next for a few days with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCWziSHw8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ym5LACg0xI1fC7LAKrLSLKglU/H4Wsv6b0AoNIkfbWi wxAZZKscwFVKNpv6gN9n =YgAj -----END PGP SIGNATURE----- Merge tag 'tty-4.18-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull tty/serial fixes from Greg KH: "Here are five fixes for the tty core and some serial drivers. The tty core ones fix some security and other issues reported by the syzbot that I have taken too long in responding to (sorry Tetsuo!). The 8350 serial driver fix resolves an issue of devices that used to work properly stopping working as they shouldn't have been added to a blacklist. All of these have been in linux-next for a few days with no reported issues" * tag 'tty-4.18-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: vt: prevent leaking uninitialized data to userspace via /dev/vcs* serdev: fix memleak on module unload serial: 8250_pci: Remove stalled entries in blacklist n_tty: Access echo_* variables carefully. n_tty: Fix stall at n_tty_receive_char_special().
This commit is contained in:
Коммит
652788a90d
|
@ -124,6 +124,8 @@ struct n_tty_data {
|
|||
struct mutex output_lock;
|
||||
};
|
||||
|
||||
#define MASK(x) ((x) & (N_TTY_BUF_SIZE - 1))
|
||||
|
||||
static inline size_t read_cnt(struct n_tty_data *ldata)
|
||||
{
|
||||
return ldata->read_head - ldata->read_tail;
|
||||
|
@ -141,6 +143,7 @@ static inline unsigned char *read_buf_addr(struct n_tty_data *ldata, size_t i)
|
|||
|
||||
static inline unsigned char echo_buf(struct n_tty_data *ldata, size_t i)
|
||||
{
|
||||
smp_rmb(); /* Matches smp_wmb() in add_echo_byte(). */
|
||||
return ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)];
|
||||
}
|
||||
|
||||
|
@ -316,9 +319,7 @@ static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
|
|||
static void reset_buffer_flags(struct n_tty_data *ldata)
|
||||
{
|
||||
ldata->read_head = ldata->canon_head = ldata->read_tail = 0;
|
||||
ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0;
|
||||
ldata->commit_head = 0;
|
||||
ldata->echo_mark = 0;
|
||||
ldata->line_start = 0;
|
||||
|
||||
ldata->erasing = 0;
|
||||
|
@ -617,12 +618,19 @@ static size_t __process_echoes(struct tty_struct *tty)
|
|||
old_space = space = tty_write_room(tty);
|
||||
|
||||
tail = ldata->echo_tail;
|
||||
while (ldata->echo_commit != tail) {
|
||||
while (MASK(ldata->echo_commit) != MASK(tail)) {
|
||||
c = echo_buf(ldata, tail);
|
||||
if (c == ECHO_OP_START) {
|
||||
unsigned char op;
|
||||
int no_space_left = 0;
|
||||
|
||||
/*
|
||||
* Since add_echo_byte() is called without holding
|
||||
* output_lock, we might see only portion of multi-byte
|
||||
* operation.
|
||||
*/
|
||||
if (MASK(ldata->echo_commit) == MASK(tail + 1))
|
||||
goto not_yet_stored;
|
||||
/*
|
||||
* If the buffer byte is the start of a multi-byte
|
||||
* operation, get the next byte, which is either the
|
||||
|
@ -634,6 +642,8 @@ static size_t __process_echoes(struct tty_struct *tty)
|
|||
unsigned int num_chars, num_bs;
|
||||
|
||||
case ECHO_OP_ERASE_TAB:
|
||||
if (MASK(ldata->echo_commit) == MASK(tail + 2))
|
||||
goto not_yet_stored;
|
||||
num_chars = echo_buf(ldata, tail + 2);
|
||||
|
||||
/*
|
||||
|
@ -728,7 +738,8 @@ static size_t __process_echoes(struct tty_struct *tty)
|
|||
/* If the echo buffer is nearly full (so that the possibility exists
|
||||
* of echo overrun before the next commit), then discard enough
|
||||
* data at the tail to prevent a subsequent overrun */
|
||||
while (ldata->echo_commit - tail >= ECHO_DISCARD_WATERMARK) {
|
||||
while (ldata->echo_commit > tail &&
|
||||
ldata->echo_commit - tail >= ECHO_DISCARD_WATERMARK) {
|
||||
if (echo_buf(ldata, tail) == ECHO_OP_START) {
|
||||
if (echo_buf(ldata, tail + 1) == ECHO_OP_ERASE_TAB)
|
||||
tail += 3;
|
||||
|
@ -738,6 +749,7 @@ static size_t __process_echoes(struct tty_struct *tty)
|
|||
tail++;
|
||||
}
|
||||
|
||||
not_yet_stored:
|
||||
ldata->echo_tail = tail;
|
||||
return old_space - space;
|
||||
}
|
||||
|
@ -748,6 +760,7 @@ static void commit_echoes(struct tty_struct *tty)
|
|||
size_t nr, old, echoed;
|
||||
size_t head;
|
||||
|
||||
mutex_lock(&ldata->output_lock);
|
||||
head = ldata->echo_head;
|
||||
ldata->echo_mark = head;
|
||||
old = ldata->echo_commit - ldata->echo_tail;
|
||||
|
@ -756,10 +769,12 @@ static void commit_echoes(struct tty_struct *tty)
|
|||
* is over the threshold (and try again each time another
|
||||
* block is accumulated) */
|
||||
nr = head - ldata->echo_tail;
|
||||
if (nr < ECHO_COMMIT_WATERMARK || (nr % ECHO_BLOCK > old % ECHO_BLOCK))
|
||||
if (nr < ECHO_COMMIT_WATERMARK ||
|
||||
(nr % ECHO_BLOCK > old % ECHO_BLOCK)) {
|
||||
mutex_unlock(&ldata->output_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&ldata->output_lock);
|
||||
ldata->echo_commit = head;
|
||||
echoed = __process_echoes(tty);
|
||||
mutex_unlock(&ldata->output_lock);
|
||||
|
@ -810,7 +825,9 @@ static void flush_echoes(struct tty_struct *tty)
|
|||
|
||||
static inline void add_echo_byte(unsigned char c, struct n_tty_data *ldata)
|
||||
{
|
||||
*echo_buf_addr(ldata, ldata->echo_head++) = c;
|
||||
*echo_buf_addr(ldata, ldata->echo_head) = c;
|
||||
smp_wmb(); /* Matches smp_rmb() in echo_buf(). */
|
||||
ldata->echo_head++;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -978,14 +995,15 @@ static void eraser(unsigned char c, struct tty_struct *tty)
|
|||
}
|
||||
|
||||
seen_alnums = 0;
|
||||
while (ldata->read_head != ldata->canon_head) {
|
||||
while (MASK(ldata->read_head) != MASK(ldata->canon_head)) {
|
||||
head = ldata->read_head;
|
||||
|
||||
/* erase a single possibly multibyte character */
|
||||
do {
|
||||
head--;
|
||||
c = read_buf(ldata, head);
|
||||
} while (is_continuation(c, tty) && head != ldata->canon_head);
|
||||
} while (is_continuation(c, tty) &&
|
||||
MASK(head) != MASK(ldata->canon_head));
|
||||
|
||||
/* do not partially erase */
|
||||
if (is_continuation(c, tty))
|
||||
|
@ -1027,7 +1045,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
|
|||
* This info is used to go back the correct
|
||||
* number of columns.
|
||||
*/
|
||||
while (tail != ldata->canon_head) {
|
||||
while (MASK(tail) != MASK(ldata->canon_head)) {
|
||||
tail--;
|
||||
c = read_buf(ldata, tail);
|
||||
if (c == '\t') {
|
||||
|
@ -1302,7 +1320,7 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
|
|||
finish_erasing(ldata);
|
||||
echo_char(c, tty);
|
||||
echo_char_raw('\n', ldata);
|
||||
while (tail != ldata->read_head) {
|
||||
while (MASK(tail) != MASK(ldata->read_head)) {
|
||||
echo_char(read_buf(ldata, tail), tty);
|
||||
tail++;
|
||||
}
|
||||
|
@ -1878,30 +1896,21 @@ static int n_tty_open(struct tty_struct *tty)
|
|||
struct n_tty_data *ldata;
|
||||
|
||||
/* Currently a malloc failure here can panic */
|
||||
ldata = vmalloc(sizeof(*ldata));
|
||||
ldata = vzalloc(sizeof(*ldata));
|
||||
if (!ldata)
|
||||
goto err;
|
||||
return -ENOMEM;
|
||||
|
||||
ldata->overrun_time = jiffies;
|
||||
mutex_init(&ldata->atomic_read_lock);
|
||||
mutex_init(&ldata->output_lock);
|
||||
|
||||
tty->disc_data = ldata;
|
||||
reset_buffer_flags(tty->disc_data);
|
||||
ldata->column = 0;
|
||||
ldata->canon_column = 0;
|
||||
ldata->num_overrun = 0;
|
||||
ldata->no_room = 0;
|
||||
ldata->lnext = 0;
|
||||
tty->closing = 0;
|
||||
/* indicate buffer work may resume */
|
||||
clear_bit(TTY_LDISC_HALTED, &tty->flags);
|
||||
n_tty_set_termios(tty, NULL);
|
||||
tty_unthrottle(tty);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static inline int input_available_p(struct tty_struct *tty, int poll)
|
||||
|
@ -2411,7 +2420,7 @@ static unsigned long inq_canon(struct n_tty_data *ldata)
|
|||
tail = ldata->read_tail;
|
||||
nr = head - tail;
|
||||
/* Skip EOF-chars.. */
|
||||
while (head != tail) {
|
||||
while (MASK(head) != MASK(tail)) {
|
||||
if (test_bit(tail & (N_TTY_BUF_SIZE - 1), ldata->read_flags) &&
|
||||
read_buf(ldata, tail) == __DISABLED_CHAR)
|
||||
nr--;
|
||||
|
|
|
@ -617,6 +617,7 @@ EXPORT_SYMBOL_GPL(__serdev_device_driver_register);
|
|||
static void __exit serdev_exit(void)
|
||||
{
|
||||
bus_unregister(&serdev_bus_type);
|
||||
ida_destroy(&ctrl_ida);
|
||||
}
|
||||
module_exit(serdev_exit);
|
||||
|
||||
|
|
|
@ -3339,9 +3339,7 @@ static const struct pci_device_id blacklist[] = {
|
|||
/* multi-io cards handled by parport_serial */
|
||||
{ PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */
|
||||
{ PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */
|
||||
{ PCI_DEVICE(0x4348, 0x7173), }, /* WCH CH355 4S */
|
||||
{ PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */
|
||||
{ PCI_DEVICE(0x1c00, 0x3470), }, /* WCH CH384 4S */
|
||||
|
||||
/* Moxa Smartio MUE boards handled by 8250_moxa */
|
||||
{ PCI_VDEVICE(MOXA, 0x1024), },
|
||||
|
|
|
@ -784,7 +784,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
|
|||
if (!*vc->vc_uni_pagedir_loc)
|
||||
con_set_default_unimap(vc);
|
||||
|
||||
vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
|
||||
vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_KERNEL);
|
||||
if (!vc->vc_screenbuf)
|
||||
goto err_free;
|
||||
|
||||
|
@ -871,7 +871,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
|
|||
|
||||
if (new_screen_size > (4 << 20))
|
||||
return -EINVAL;
|
||||
newscreen = kmalloc(new_screen_size, GFP_USER);
|
||||
newscreen = kzalloc(new_screen_size, GFP_USER);
|
||||
if (!newscreen)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче