Skip to content

Commit

Permalink
Merge tag 'tty-4.18-rc3' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/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().
  • Loading branch information
Linus Torvalds committed Jul 1, 2018
2 parents c2aee37 + 21eff69 commit 652788a
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 27 deletions.
55 changes: 32 additions & 23 deletions drivers/tty/n_tty.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)];
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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);

/*
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
Expand All @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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++;
}

/**
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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') {
Expand Down Expand Up @@ -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++;
}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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--;
Expand Down
1 change: 1 addition & 0 deletions drivers/tty/serdev/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
2 changes: 0 additions & 2 deletions drivers/tty/serial/8250/8250_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -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), },
Expand Down
4 changes: 2 additions & 2 deletions drivers/tty/vt/vt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand Down

0 comments on commit 652788a

Please sign in to comment.