lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Mon, 16 Oct 2023 15:13:56 +0300 (EEST)
From:   Ilpo Järvinen <ilpo.jarvinen@...ux.intel.com>
To:     Richard Laing <richard.laing@...iedtelesis.co.nz>
cc:     Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
        Jiri Slaby <jirislaby@...nel.org>, robh+dt@...nel.org,
        krzysztof.kozlowski+dt@...aro.org, conor+dt@...nel.org,
        ilpo.jarvinen@...ux.intel.com,
        Andy Shevchenko <andriy.shevchenko@...ux.intel.com>,
        LKML <linux-kernel@...r.kernel.org>,
        linux-serial <linux-serial@...r.kernel.org>,
        devicetree@...r.kernel.org
Subject: Re: [PATCH] serial: 8250_dw: Allow TX FIFO to drain before writing
 to UART_LCR An issue has been observed on the Broadcom BCM56160 serial port
 which appears closely related to a similar issue on the Marvell Armada 38x
 serial port.

On Mon, 16 Oct 2023, Richard Laing wrote:

Your subject line is way too long. If you refer to some other issue, 
please link to it properly with commit id and/or with Link: tags.

> Writes to UART_LCR can result in characters that are currently held in the
> TX FIFO being lost rather than sent, even if the userspace process has
> attempted to flush them.
> 
> This is most visible when using the "resize" command (tested on Busybox),
> where we have observed the escape code for restoring cursor position
> becoming mangled.
> 
> Since this appears to be a more common problem add a new driver option
> to flush the TX FIFO before writing to the UART_LCR.

This looks like a problem we already have solution for, the userspace can 
use TCSADRAIN/FLUSH to indicate what kind of flushing it wants for Tx 
when it makes the tcsetattr() call. Thus, userspace can avoid the Tx side 
corruption as long as its behavior is sane and doesn't e.g. try to race 
writes with tcsetattr() call as mentioned in commit 094fb49a2d0d ("tty: 
Prevent writing chars during tcsetattr TCSADRAIN/FLUSH").

Have you tried to use the userspace solution? Isn't it working for some 
reason?

-- 
 i.

> 
> Signed-off-by: Richard Laing <richard.laing@...iedtelesis.co.nz>
> ---
>  drivers/tty/serial/8250/8250_dw.c    | 18 ++++++++++++++++++
>  drivers/tty/serial/8250/8250_dwlib.h |  1 +
>  2 files changed, 19 insertions(+)
> 
> diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
> index f4cafca1a7da..17ee824294c7 100644
> --- a/drivers/tty/serial/8250/8250_dw.c
> +++ b/drivers/tty/serial/8250/8250_dw.c
> @@ -161,6 +161,10 @@ static void dw8250_serial_out(struct uart_port *p, int offset, int value)
>  {
>  	struct dw8250_data *d = to_dw8250_data(p->private_data);
>  
> +	/* Allow the TX to drain before we reconfigure */
> +	if (offset == UART_LCR && d->drain_before_lcr_change)
> +		dw8250_tx_wait_empty(p);
> +
>  	writeb(value, p->membase + (offset << p->regshift));
>  
>  	if (offset == UART_LCR && !d->uart_16550_compatible)
> @@ -197,6 +201,10 @@ static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
>  {
>  	struct dw8250_data *d = to_dw8250_data(p->private_data);
>  
> +	/* Allow the TX to drain before we reconfigure */
> +	if (offset == UART_LCR && d->drain_before_lcr_change)
> +		dw8250_tx_wait_empty(p);
> +
>  	value &= 0xff;
>  	__raw_writeq(value, p->membase + (offset << p->regshift));
>  	/* Read back to ensure register write ordering. */
> @@ -211,6 +219,10 @@ static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
>  {
>  	struct dw8250_data *d = to_dw8250_data(p->private_data);
>  
> +	/* Allow the TX to drain before we reconfigure */
> +	if (offset == UART_LCR && d->drain_before_lcr_change)
> +		dw8250_tx_wait_empty(p);
> +
>  	writel(value, p->membase + (offset << p->regshift));
>  
>  	if (offset == UART_LCR && !d->uart_16550_compatible)
> @@ -228,6 +240,10 @@ static void dw8250_serial_out32be(struct uart_port *p, int offset, int value)
>  {
>  	struct dw8250_data *d = to_dw8250_data(p->private_data);
>  
> +	/* Allow the TX to drain before we reconfigure */
> +	if (offset == UART_LCR && d->drain_before_lcr_change)
> +		dw8250_tx_wait_empty(p);
> +
>  	iowrite32be(value, p->membase + (offset << p->regshift));
>  
>  	if (offset == UART_LCR && !d->uart_16550_compatible)
> @@ -597,6 +613,8 @@ static int dw8250_probe(struct platform_device *pdev)
>  	/* Always ask for fixed clock rate from a property. */
>  	device_property_read_u32(dev, "clock-frequency", &p->uartclk);
>  
> +	data->drain_before_lcr_change = device_property_read_bool(dev, "drain-before-lcr-change");
> +
>  	/* If there is separate baudclk, get the rate from it. */
>  	data->clk = devm_clk_get_optional(dev, "baudclk");
>  	if (data->clk == NULL)
> diff --git a/drivers/tty/serial/8250/8250_dwlib.h b/drivers/tty/serial/8250/8250_dwlib.h
> index f13e91f2cace..f7d88fa8f058 100644
> --- a/drivers/tty/serial/8250/8250_dwlib.h
> +++ b/drivers/tty/serial/8250/8250_dwlib.h
> @@ -45,6 +45,7 @@ struct dw8250_data {
>  
>  	unsigned int		skip_autocfg:1;
>  	unsigned int		uart_16550_compatible:1;
> +	unsigned int		drain_before_lcr_change:1;
>  };
>  
>  void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, const struct ktermios *old);

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ