[BUG] drivers/net/lan9250.c: `.bss`/global `pktbuf` overflow in `lan9250_recv_buffer` — RX-status packet length bounded only by `DEBUGASSERT` (SPI path only)
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 68/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- c
- Ambito
- embedded-iot
Direzione di ricerca
Inizia in drivers/net/lan9250.c, da lan9250_receive() e lan9250_recv_buffer(). Poi controlla come viene dimensionato pktbuf e come i percorsi SPI e QSPI/SQI copiano i dati. Aggiungi un controllo della capacità sempre attivo prima di ogni copia e scarta i frame troppo grandi. Il lavoro è completo quando le lunghezze ricevute non possono scrivere oltre pktbuf su nessuno dei due percorsi.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
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:
/* 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:
/* 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:
/* 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 (
#elsepath): 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:
- Build the LAN9250 driver (SPI with default
CONFIG_DEBUG_ASSERTIONSunset, or any QSPI/SQI build). - 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. - The copy writes
pktlenbytes into the 596-byteg_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:
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
- I have verified before submitting the report.
- Lingua principale
- C
- Stelle
- 4.1k
- Fork
- 1.7k
- Merge medio
- 1g 10h
- PR unite (30g)
- 649
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di apache/nuttx
-
Arch: all Area: Drivers OS: Linux Type: Bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
apache/nuttx#19435 · 8 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Type: Bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
apache/nuttx#17343 · 4 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Arch: all OS: Linux Type: Bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
apache/nuttx#16249 · 7 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Arch: arm Area: Build system OS: Mac Type: Bug
Difficoltà 4/5 3-5 giorni Idoneità per principianti 15/100
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di apache/nuttx
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
I maintainer di solito rispondono entro 1 giorno
-
area:docs area:stdlib found-by:duet-audit kind:docs-drift
Difficoltà 2/5 1-3 ore Idoneità per principianti 86/100
InauguralSystems/EigenScript#2251 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 74/100
flux-framework/flux-coral2#513 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
ly05010419/MacNativeGames#1420 ·
I maintainer di solito rispondono entro 1 giorno
-
Isaac workingAperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
seedds/nxnative#763 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno