This is an automated email from the ASF dual-hosted git repository.

anchao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit d5304d02fbe5850e25c456a40cc05b6788e9ce95
Author: wangyongrong <[email protected]>
AuthorDate: Thu Oct 29 01:20:19 2026 +0800

    rpmsg/port_uart: reject rx frame shorter than the port header
    
    hdr->len is parsed from the received byte stream, but the frame
    validation at the END delimiter never checks it against the minimum
    frame size:
    
      if (hdr->len != next || (hdr->crc != 0 &&
          hdr->crc != rpmsg_port_uart_crc16(hdr)))
    
    A freshly fetched rx buffer is safe, because get_available_buffer()
    presets hdr->len to the queue length.  The reachable path is buffer
    reuse: on a duplicate START the RECV_NORMAL branch resets state and next
    but keeps hdr, so returning to WAIT_START finds hdr != NULL and reuses
    the buffer without re-presetting hdr->len.  By then hdr->len holds
    whatever the previous partial frame left at that offset - line data.  A
    short frame only writes the first bytes of the header, so len (at offset
    6) keeps that stale value.
    
    If an END arrives while the stale len happens to equal next (both 0, for
    instance), the first test passes and two things can go wrong depending
    on the stale crc:
    
    - crc == 0 short-circuits the second test, so the whole condition is
      false and the frame is queued as a valid one.  Consumers that derive
      the payload size by subtracting the header size then underflow; the
      LZF path does exactly that, rxlen = hdr->len - sizeof(*hdr).  This
      does not depend on CONFIG_RPMSG_PORT_UART_CRC: with the CRC compiled
      out the macro is a literal 0, so a non-zero stale crc compares equal
      to it and the frame is accepted just the same.
    - crc != 0 with the CRC compiled in evaluates
      crc16xor(&hdr->cmd, hdr->len - sizeof(hdr->crc)), and 0 - 2 underflows
      the size_t length argument, so crc16xor() walks far past the buffer.
    
    Reject len < sizeof(*hdr) as the first term of the condition.  The
    short-circuit then keeps the CRC from being computed at all, and the
    frame is dropped and its buffer returned like any other malformed frame.
    A frame whose len equals sizeof(*hdr) carries no payload and stays
    valid.  The port-spi driver already rejects such frames; port-uart did
    not.
    
    No upper bound is needed here: the copy loop only advances next while
    next < rxq->len, and the condition requires len == next.
    
    Signed-off-by: wangyongrong <[email protected]>
---
 drivers/rpmsg/rpmsg_port_uart.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/rpmsg/rpmsg_port_uart.c b/drivers/rpmsg/rpmsg_port_uart.c
index d8fb5fa1601..a19bf749548 100644
--- a/drivers/rpmsg/rpmsg_port_uart.c
+++ b/drivers/rpmsg/rpmsg_port_uart.c
@@ -715,8 +715,9 @@ static void rpmsg_port_uart_rx_worker(FAR struct 
rpmsg_port_uart_s *rpuart,
               }
             else if (buf[i] == RPMSG_PORT_UART_END)
               {
-                if (hdr->len != next || (hdr->crc != 0 &&
-                    hdr->crc != rpmsg_port_uart_crc16(hdr)))
+                if (hdr->len < sizeof(*hdr) || hdr->len != next ||
+                    (hdr->crc != 0 &&
+                     hdr->crc != rpmsg_port_uart_crc16(hdr)))
                   {
                     rpmsgerr("Recv error crc=%u len=%u next=%u i=%zd "
                              "dbg_i=%d\n", hdr->crc, hdr->len, next, i,

Reply via email to