TTY/Serial/fbcon fixes for 5.8-rc7

Here are some small tty and serial and fbcon fixes for 5.8-rc7 to
 resolve some reported issues.
 
 The fbcon fix is in here as it was simpler to take it this way (and it
 was acked by the maintainer) as it was related to the vt console fix as
 well, both of which resolve syzbot-found issues in the console handling
 code.
 
 The other serial driver fixes are for small issues reported in the -rc
 releases.
 
 All of these have been in linux-next with no reported issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXx1ivg8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ym+LQCbBFMk78aB+Vb5PpH36m6oNroBB2MAoMUJSWLx
 Wm7QhLYa1Cbsb1rC7t5x
 =kf5B
 -----END PGP SIGNATURE-----

Merge tag 'tty-5.8-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty into master

Pull tty/serial/fbcon fixes from Greg KH:
 "Here are some small tty and serial and fbcon fixes for 5.8-rc7 to
  resolve some reported issues.

  The fbcon fix is in here as it was simpler to take it this way (and it
  was acked by the maintainer) as it was related to the vt console fix
  as well, both of which resolve syzbot-found issues in the console
  handling code.

  The other serial driver fixes are for small issues reported in the -rc
  releases.

  All of these have been in linux-next with no reported issues"

* tag 'tty-5.8-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  serial: exar: Fix GPIO configuration for Sealevel cards based on XR17V35X
  fbdev: Detect integer underflow at "struct fbcon_ops"->clear_margins.
  serial: 8250_mtk: Fix high-speed baud rates clamping
  serial: 8250: fix null-ptr-deref in serial8250_start_tx()
  serial: tegra: drop bogus NULL tty-port checks
  serial: tegra: fix CREAD handling for PIO
  tty: xilinx_uartps: Really fix id assignment
  vt: Reject zero-sized screen buffer size.
This commit is contained in:
Linus Torvalds 2020-07-26 09:09:43 -07:00
Родитель 17f50e28a8 5fdbe136ae
Коммит 7d22af6c5b
10 изменённых файлов: 69 добавлений и 32 удалений

Просмотреть файл

@ -524,6 +524,7 @@ static void __init serial8250_isa_init_ports(void)
*/ */
up->mcr_mask = ~ALPHA_KLUDGE_MCR; up->mcr_mask = ~ALPHA_KLUDGE_MCR;
up->mcr_force = ALPHA_KLUDGE_MCR; up->mcr_force = ALPHA_KLUDGE_MCR;
serial8250_set_defaults(up);
} }
/* chain base port ops to support Remote Supervisor Adapter */ /* chain base port ops to support Remote Supervisor Adapter */
@ -547,7 +548,6 @@ static void __init serial8250_isa_init_ports(void)
port->membase = old_serial_port[i].iomem_base; port->membase = old_serial_port[i].iomem_base;
port->iotype = old_serial_port[i].io_type; port->iotype = old_serial_port[i].io_type;
port->regshift = old_serial_port[i].iomem_reg_shift; port->regshift = old_serial_port[i].iomem_reg_shift;
serial8250_set_defaults(up);
port->irqflags |= irqflag; port->irqflags |= irqflag;
if (serial8250_isa_config != NULL) if (serial8250_isa_config != NULL)

Просмотреть файл

@ -326,7 +326,17 @@ static void setup_gpio(struct pci_dev *pcidev, u8 __iomem *p)
* devices will export them as GPIOs, so we pre-configure them safely * devices will export them as GPIOs, so we pre-configure them safely
* as inputs. * as inputs.
*/ */
u8 dir = pcidev->vendor == PCI_VENDOR_ID_EXAR ? 0xff : 0x00;
u8 dir = 0x00;
if ((pcidev->vendor == PCI_VENDOR_ID_EXAR) &&
(pcidev->subsystem_vendor != PCI_VENDOR_ID_SEALEVEL)) {
// Configure GPIO as inputs for Commtech adapters
dir = 0xff;
} else {
// Configure GPIO as outputs for SeaLevel adapters
dir = 0x00;
}
writeb(0x00, p + UART_EXAR_MPIOINT_7_0); writeb(0x00, p + UART_EXAR_MPIOINT_7_0);
writeb(0x00, p + UART_EXAR_MPIOLVL_7_0); writeb(0x00, p + UART_EXAR_MPIOLVL_7_0);

Просмотреть файл

@ -306,8 +306,21 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
} }
#endif #endif
/*
* Store the requested baud rate before calling the generic 8250
* set_termios method. Standard 8250 port expects bauds to be
* no higher than (uartclk / 16) so the baud will be clamped if it
* gets out of that bound. Mediatek 8250 port supports speed
* higher than that, therefore we'll get original baud rate back
* after calling the generic set_termios method and recalculate
* the speed later in this method.
*/
baud = tty_termios_baud_rate(termios);
serial8250_do_set_termios(port, termios, old); serial8250_do_set_termios(port, termios, old);
tty_termios_encode_baud_rate(termios, baud, baud);
/* /*
* Mediatek UARTs use an extra highspeed register (MTK_UART_HIGHS) * Mediatek UARTs use an extra highspeed register (MTK_UART_HIGHS)
* *
@ -339,6 +352,11 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
*/ */
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, baud);
/* set DLAB we have cval saved in up->lcr from the call to the core */ /* set DLAB we have cval saved in up->lcr from the call to the core */
serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB); serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB);
serial_dl_write(up, quot); serial_dl_write(up, quot);

Просмотреть файл

@ -635,7 +635,7 @@ static void tegra_uart_handle_tx_pio(struct tegra_uart_port *tup)
} }
static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup, static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup,
struct tty_port *tty) struct tty_port *port)
{ {
do { do {
char flag = TTY_NORMAL; char flag = TTY_NORMAL;
@ -653,16 +653,18 @@ static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup,
ch = (unsigned char) tegra_uart_read(tup, UART_RX); ch = (unsigned char) tegra_uart_read(tup, UART_RX);
tup->uport.icount.rx++; tup->uport.icount.rx++;
if (!uart_handle_sysrq_char(&tup->uport, ch) && tty) if (uart_handle_sysrq_char(&tup->uport, ch))
tty_insert_flip_char(tty, ch, flag); continue;
if (tup->uport.ignore_status_mask & UART_LSR_DR) if (tup->uport.ignore_status_mask & UART_LSR_DR)
continue; continue;
tty_insert_flip_char(port, ch, flag);
} while (1); } while (1);
} }
static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup, static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup,
struct tty_port *tty, struct tty_port *port,
unsigned int count) unsigned int count)
{ {
int copied; int copied;
@ -672,17 +674,13 @@ static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup,
return; return;
tup->uport.icount.rx += count; tup->uport.icount.rx += count;
if (!tty) {
dev_err(tup->uport.dev, "No tty port\n");
return;
}
if (tup->uport.ignore_status_mask & UART_LSR_DR) if (tup->uport.ignore_status_mask & UART_LSR_DR)
return; return;
dma_sync_single_for_cpu(tup->uport.dev, tup->rx_dma_buf_phys, dma_sync_single_for_cpu(tup->uport.dev, tup->rx_dma_buf_phys,
count, DMA_FROM_DEVICE); count, DMA_FROM_DEVICE);
copied = tty_insert_flip_string(tty, copied = tty_insert_flip_string(port,
((unsigned char *)(tup->rx_dma_buf_virt)), count); ((unsigned char *)(tup->rx_dma_buf_virt)), count);
if (copied != count) { if (copied != count) {
WARN_ON(1); WARN_ON(1);

Просмотреть файл

@ -1580,8 +1580,10 @@ static int cdns_uart_probe(struct platform_device *pdev)
* If register_console() don't assign value, then console_port pointer * If register_console() don't assign value, then console_port pointer
* is cleanup. * is cleanup.
*/ */
if (!console_port) if (!console_port) {
cdns_uart_console.index = id;
console_port = port; console_port = port;
}
#endif #endif
rc = uart_add_one_port(&cdns_uart_uart_driver, port); rc = uart_add_one_port(&cdns_uart_uart_driver, port);
@ -1594,8 +1596,10 @@ static int cdns_uart_probe(struct platform_device *pdev)
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE #ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
/* This is not port which is used for console that's why clean it up */ /* This is not port which is used for console that's why clean it up */
if (console_port == port && if (console_port == port &&
!(cdns_uart_uart_driver.cons->flags & CON_ENABLED)) !(cdns_uart_uart_driver.cons->flags & CON_ENABLED)) {
console_port = NULL; console_port = NULL;
cdns_uart_console.index = -1;
}
#endif #endif
cdns_uart_data->cts_override = of_property_read_bool(pdev->dev.of_node, cdns_uart_data->cts_override = of_property_read_bool(pdev->dev.of_node,

Просмотреть файл

@ -1092,10 +1092,19 @@ static const struct tty_port_operations vc_port_ops = {
.destruct = vc_port_destruct, .destruct = vc_port_destruct,
}; };
/*
* Change # of rows and columns (0 means unchanged/the size of fg_console)
* [this is to be used together with some user program
* like resize that changes the hardware videomode]
*/
#define VC_MAXCOL (32767)
#define VC_MAXROW (32767)
int vc_allocate(unsigned int currcons) /* return 0 on success */ int vc_allocate(unsigned int currcons) /* return 0 on success */
{ {
struct vt_notifier_param param; struct vt_notifier_param param;
struct vc_data *vc; struct vc_data *vc;
int err;
WARN_CONSOLE_UNLOCKED(); WARN_CONSOLE_UNLOCKED();
@ -1125,6 +1134,11 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
if (!*vc->vc_uni_pagedir_loc) if (!*vc->vc_uni_pagedir_loc)
con_set_default_unimap(vc); con_set_default_unimap(vc);
err = -EINVAL;
if (vc->vc_cols > VC_MAXCOL || vc->vc_rows > VC_MAXROW ||
vc->vc_screenbuf_size > KMALLOC_MAX_SIZE || !vc->vc_screenbuf_size)
goto err_free;
err = -ENOMEM;
vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_KERNEL); vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_KERNEL);
if (!vc->vc_screenbuf) if (!vc->vc_screenbuf)
goto err_free; goto err_free;
@ -1143,7 +1157,7 @@ err_free:
visual_deinit(vc); visual_deinit(vc);
kfree(vc); kfree(vc);
vc_cons[currcons].d = NULL; vc_cons[currcons].d = NULL;
return -ENOMEM; return err;
} }
static inline int resize_screen(struct vc_data *vc, int width, int height, static inline int resize_screen(struct vc_data *vc, int width, int height,
@ -1158,14 +1172,6 @@ static inline int resize_screen(struct vc_data *vc, int width, int height,
return err; return err;
} }
/*
* Change # of rows and columns (0 means unchanged/the size of fg_console)
* [this is to be used together with some user program
* like resize that changes the hardware videomode]
*/
#define VC_RESIZE_MAXCOL (32767)
#define VC_RESIZE_MAXROW (32767)
/** /**
* vc_do_resize - resizing method for the tty * vc_do_resize - resizing method for the tty
* @tty: tty being resized * @tty: tty being resized
@ -1201,7 +1207,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
user = vc->vc_resize_user; user = vc->vc_resize_user;
vc->vc_resize_user = 0; vc->vc_resize_user = 0;
if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW) if (cols > VC_MAXCOL || lines > VC_MAXROW)
return -EINVAL; return -EINVAL;
new_cols = (cols ? cols : vc->vc_cols); new_cols = (cols ? cols : vc->vc_cols);
@ -1212,7 +1218,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
if (new_cols == vc->vc_cols && new_rows == vc->vc_rows) if (new_cols == vc->vc_cols && new_rows == vc->vc_rows)
return 0; return 0;
if (new_screen_size > KMALLOC_MAX_SIZE) if (new_screen_size > KMALLOC_MAX_SIZE || !new_screen_size)
return -EINVAL; return -EINVAL;
newscreen = kzalloc(new_screen_size, GFP_USER); newscreen = kzalloc(new_screen_size, GFP_USER);
if (!newscreen) if (!newscreen)
@ -3393,6 +3399,7 @@ static int __init con_init(void)
INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK); INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
tty_port_init(&vc->port); tty_port_init(&vc->port);
visual_init(vc, currcons, 1); visual_init(vc, currcons, 1);
/* Assuming vc->vc_{cols,rows,screenbuf_size} are sane here. */
vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT); vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
vc_init(vc, vc->vc_rows, vc->vc_cols, vc_init(vc, vc->vc_rows, vc->vc_cols,
currcons || !vc->vc_sw->con_save_screen); currcons || !vc->vc_sw->con_save_screen);

Просмотреть файл

@ -216,7 +216,7 @@ static void bit_clear_margins(struct vc_data *vc, struct fb_info *info,
region.color = color; region.color = color;
region.rop = ROP_COPY; region.rop = ROP_COPY;
if (rw && !bottom_only) { if ((int) rw > 0 && !bottom_only) {
region.dx = info->var.xoffset + rs; region.dx = info->var.xoffset + rs;
region.dy = 0; region.dy = 0;
region.width = rw; region.width = rw;
@ -224,7 +224,7 @@ static void bit_clear_margins(struct vc_data *vc, struct fb_info *info,
info->fbops->fb_fillrect(info, &region); info->fbops->fb_fillrect(info, &region);
} }
if (bh) { if ((int) bh > 0) {
region.dx = info->var.xoffset; region.dx = info->var.xoffset;
region.dy = info->var.yoffset + bs; region.dy = info->var.yoffset + bs;
region.width = rs; region.width = rs;

Просмотреть файл

@ -201,7 +201,7 @@ static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info,
region.color = color; region.color = color;
region.rop = ROP_COPY; region.rop = ROP_COPY;
if (rw && !bottom_only) { if ((int) rw > 0 && !bottom_only) {
region.dx = 0; region.dx = 0;
region.dy = info->var.yoffset; region.dy = info->var.yoffset;
region.height = rw; region.height = rw;
@ -209,7 +209,7 @@ static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info,
info->fbops->fb_fillrect(info, &region); info->fbops->fb_fillrect(info, &region);
} }
if (bh) { if ((int) bh > 0) {
region.dx = info->var.xoffset + bs; region.dx = info->var.xoffset + bs;
region.dy = 0; region.dy = 0;
region.height = info->var.yres_virtual; region.height = info->var.yres_virtual;

Просмотреть файл

@ -184,7 +184,7 @@ static void cw_clear_margins(struct vc_data *vc, struct fb_info *info,
region.color = color; region.color = color;
region.rop = ROP_COPY; region.rop = ROP_COPY;
if (rw && !bottom_only) { if ((int) rw > 0 && !bottom_only) {
region.dx = 0; region.dx = 0;
region.dy = info->var.yoffset + rs; region.dy = info->var.yoffset + rs;
region.height = rw; region.height = rw;
@ -192,7 +192,7 @@ static void cw_clear_margins(struct vc_data *vc, struct fb_info *info,
info->fbops->fb_fillrect(info, &region); info->fbops->fb_fillrect(info, &region);
} }
if (bh) { if ((int) bh > 0) {
region.dx = info->var.xoffset; region.dx = info->var.xoffset;
region.dy = info->var.yoffset; region.dy = info->var.yoffset;
region.height = info->var.yres; region.height = info->var.yres;

Просмотреть файл

@ -231,7 +231,7 @@ static void ud_clear_margins(struct vc_data *vc, struct fb_info *info,
region.color = color; region.color = color;
region.rop = ROP_COPY; region.rop = ROP_COPY;
if (rw && !bottom_only) { if ((int) rw > 0 && !bottom_only) {
region.dy = 0; region.dy = 0;
region.dx = info->var.xoffset; region.dx = info->var.xoffset;
region.width = rw; region.width = rw;
@ -239,7 +239,7 @@ static void ud_clear_margins(struct vc_data *vc, struct fb_info *info,
info->fbops->fb_fillrect(info, &region); info->fbops->fb_fillrect(info, &region);
} }
if (bh) { if ((int) bh > 0) {
region.dy = info->var.yoffset; region.dy = info->var.yoffset;
region.dx = info->var.xoffset; region.dx = info->var.xoffset;
region.height = bh; region.height = bh;