K-ANOY opened a new issue, #21112:
URL: https://github.com/apache/nuttx/issues/21112

   ### Description / Steps to reproduce the issue
   
   In `drivers/net/lan9250.c` (LAN9250 Ethernet driver over SPI/QSPI) the 
received frame length taken
   from the RX Status FIFO is used as a copy length into `priv->pktbuf`, 
bounded on the SPI path **only**
   by an assert that compiles to nothing in the default build, and on the 
QSPI/SQI path by **no capacity
   check at all**. `priv` is a `static` global object, so this is an 
out-of-bounds **write** into `.bss`
   that first clobbers the structure members immediately following `pktbuf` (a 
watchdog timer and several
   work structures) and then adjacent globals. The attacker is a peer on the 
same L2 network sending an
   oversized frame, or a malicious/faulty LAN9250 PHY.
   
   `lan9250_receive()` takes the received frame length from the LAN9250 RX 
Status FIFO register and
   passes it as the copy length, with only a non-zero check:
   
   ```c
   /* drivers/net/lan9250.c:1747-1748  (lan9250_receive) */
   regval = lan9250_get_reg(priv, LAN9250_RXSFR);        /* RX Status FIFO 
register */
   pktlen = (regval & RXSFF_PL_M) >> RXSFF_PL_S;         /* 14-bit length 
field, 0..16383 */
   if (pktlen)                                           /* only a non-zero 
check */
       lan9250_recv_buffer(priv, priv->dev.d_buf, pktlen);  /* buflen = pktlen 
*/
   ```
   
   The copy then runs into `priv->pktbuf`. On the **SPI** path the length is 
bounded only by a
   `DEBUGASSERT`; on the **QSPI/SQI** path there is no capacity check:
   
   ```c
   /* drivers/net/lan9250.c:853 (inside #ifdef CONFIG_LAN9250_SPI) */
   DEBUGASSERT(buflen <= sizeof(priv->pktbuf));          /* SPI path: 
default-off assert */
   ...
   SPI_RECVBLOCK(priv->spi, buffer, buflen);             /* buffer = 
priv->dev.d_buf = priv->pktbuf */
   
   /* drivers/net/lan9250.c:881-899 (#else — QSPI/SQI path) */
   meminfo.buflen = buflen;                               /* no capacity check 
at all */
   QSPI_MEMORY(priv->qspi, &meminfo);
   ```
   
   `priv->pktbuf` is `uint32_t pktbuf[LAN9250_PKTBUF_SIZE / 4]` (`:212`), with
   `LAN9250_PKTBUF_SIZE = LAN9250_ALIGN(MAX_NETDEV_PKTSIZE + 
CONFIG_NET_GUARDSIZE + 4)` (`:142`). In the
   default IPv4/Ethernet config (`CONFIG_NET_ETH_PKTSIZE = 590`, 
`CONFIG_NET_GUARDSIZE = 2`) that is
   `ALIGN(596) = 596` bytes — about one max Ethernet frame. Any ordinary frame 
larger than ~596 bytes
   (a normal 1514/1518-byte Ethernet frame already qualifies) therefore 
overflows it. `pktlen` is a
   14-bit RX-status register field (max 16383); that width is the hardware 
status-field size, **not** a
   demonstration that a peer can inject a 16 KB frame — the practically 
reachable and sufficient case is
   simply "frame > ~596 bytes".
   
   **Memory class:** the driver state is a `static` global, not a heap 
allocation:
   
   ```c
   /* drivers/net/lan9250.c:230 */
   static struct lan9250_driver_s g_lan9250;
   /* :2440 / :2512 */  priv = &g_lan9250;   /* no kmm_malloc/kmm_zalloc of the 
driver state */
   ```
   
   `pktbuf` (`:212`) is immediately followed in the struct by `txtout_timer` 
(`struct wdog_s`),
   `txtout_work` / `txpoll_work` / `irq_work` (`struct work_s`), and `dev` 
(`:214-224`). So the overflow
   is a **`.bss`/global-buffer overflow** that corrupts those sibling members 
(watchdog + work queue
   state) first, then neighbouring `.bss` objects — it is **not** a heap 
overflow.
   
   **Configuration dimension:**
   - SPI build, `CONFIG_DEBUG_ASSERTIONS = n` (**default**): the guard is 
compiled out → overflow.
   - SPI build, `CONFIG_DEBUG_ASSERTIONS = y`: the assert fires → controlled 
panic (DoS), no overflow.
   - **QSPI/SQI build (`#else` path): there is no capacity check in any 
configuration**, so enabling
     assertions does **not** prevent the overflow on QSPI/SQI targets.
   
   **Why this is a bug:** the length is a parameter at the sink 
(`lan9250_recv_buffer`)
   that originates in the caller (`lan9250_receive`), and the only guard 
anywhere on the SPI path is the
   default-off `DEBUGASSERT` at `:853` (and nothing at all on the QSPI path). 
The caller's `if (pktlen)`
   check is non-zero-only, with no upper bound against `MAX_NETDEV_PKTSIZE` 
before handing the
   device-reported length to the copy.
   
   Steps:
   1. Build the LAN9250 driver (SPI with default `CONFIG_DEBUG_ASSERTIONS` 
unset, or any QSPI/SQI build).
   2. A peer on the same L2 network sends a frame larger than ~596 bytes (an 
ordinary full-size Ethernet
      frame suffices), or a malicious/faulty LAN9250 PHY reports an oversized 
RX-status length.
   3. The copy writes `pktlen` bytes into the 596-byte `g_lan9250.pktbuf`, 
overflowing into the adjacent
      watchdog/work members and `.bss`.
   
   An AddressSanitizer build of the copy with the real buffer sizing (as a 
596-byte global region)
   reports a `global-buffer-overflow WRITE`.
   
   **Suggested fix:** add an always-compiled check before 
`lan9250_recv_buffer`, and/or replace the
   `DEBUGASSERT`, and add the equivalent check on the QSPI/SQI path:
   
   ```c
   if (pktlen > MAX_NETDEV_PKTSIZE)
     {
       /* drop oversized frame */
       return;
     }
   ```
   
   and in `lan9250_recv_buffer` replace the SPI `DEBUGASSERT` with `if (buflen 
> sizeof(priv->pktbuf)) return;`
   and add the same guard before the QSPI `QSPI_MEMORY` transfer.
   
   ### On which OS does this issue occur?
   
   [OS: Linux]
   
   ### What is the version of your OS?
   
   ubuntu 22
   
   ### NuttX Version
   
   master
   
   ### Issue Architecture
   
   [Arch: all]
   
   ### Issue Area
   
   [Area: Drivers]
   
   ### Host information
   
   _No response_
   
   ### Verification
   
   - [x] I have verified before submitting the report.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to