From 6fdc2dde4121ae8ef9adf2b4d72887b73733797f Mon Sep 17 00:00:00 2001 From: yi chen <94xhn1@gmail.com> Date: Fri, 10 Jul 2026 06:12:11 +0800 Subject: [PATCH] drivers/serial: hold xmit.lock around echo in uart_readv() uart_putxmitchar() manipulates dev->xmit.head/buffer directly with no internal locking - every other caller (uart_write()) takes dev->xmit.lock first. uart_readv()'s ECHO handling (both the backspace/delete erase sequence and the normal character echo) calls uart_putxmitchar() without taking that lock, so a concurrent uart_write() and a local echo can race on the same circular buffer state, corrupting it. Take dev->xmit.lock around each echo's uart_putxmitchar() calls, matching what uart_write() already does. uart_readv() holds dev->recv.lock for its own duration, but no other code path ever acquires recv.lock while holding xmit.lock, so nesting xmit.lock inside the existing recv.lock scope here doesn't introduce a new lock-ordering cycle. Fixes #14845 Signed-off-by: yi chen <94xhn1@gmail.com> --- drivers/serial/serial.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index 5f54d972a98..da80d2e9e66 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -1031,9 +1031,11 @@ static ssize_t uart_readv(FAR struct file *filep, FAR struct uio *uio) recvd--; if (dev->tc_lflag & ECHO) { + nxmutex_lock(&dev->xmit.lock); uart_putxmitchar(dev, '\b', true); uart_putxmitchar(dev, ' ', true); uart_putxmitchar(dev, '\b', true); + nxmutex_unlock(&dev->xmit.lock); #ifdef CONFIG_SERIAL_TXDMA uart_dmatxavail(dev); @@ -1088,12 +1090,14 @@ static ssize_t uart_readv(FAR struct file *filep, FAR struct uio *uio) if (!iscntrl(ch & 0xff) || ch == '\n') { + nxmutex_lock(&dev->xmit.lock); if (ch == '\n') { uart_putxmitchar(dev, '\r', true); } uart_putxmitchar(dev, ch, true); + nxmutex_unlock(&dev->xmit.lock); /* Mark the tx buffer have echoed content here, * to avoid the tx buffer is empty such as special escape