[Bug] lwip-dhcpd: dhcp_client_alloc infinite loop after lease pool exhaustion — pre-auth remote permanent DoS of the whole lwIP stack (dhcp_server_raw.c)
Mantenedores costumam responder em até 1 dia
Ninguém assumiu esta issue ainda.
Avaliação
- Dificuldade
- 4/5
- Tempo estimado
- 3-5 dias
- Facilidade para iniciantes
- 35/100
- Tipo de issue
- Bug
- Clareza
- Claramente especificada
- Status de atividade
- Ativa
- Stack de tecnologia
- c
- Domínio
- networking
Direção de pesquisa
Start with components/net/lwip-dhcpd/dhcp_server_raw.c, especially dhcp_client_alloc() and the lease writes around lines 380 and 457. Trace how dhcp_server_recv() handles a new DISCOVER after the pool is full, then reproduce using the QEMU vexpress-a9 DHCP setup described in the issue. Done means allocation exits cleanly on exhaustion, leases expire so addresses can be reused, and the tcpip thread continues processing packets.
Escrita pelo modelo de indexação a partir do texto da issue.
Descrição
RT-Thread Version
master 5d1fb66d13 (2026-10-15). Introduced by 330e68e5f4 ("[DHCPD] add
new version DHCPD use lwip raw api.", 2018-06-20); first affected release is
v4.0.0 (2019-01-27). All releases v4.0.0–v5.3.0 and master are affected.
Affected area
Components / lwIP (components/net/lwip-dhcpd, DHCP server)
Hardware/BSP vendor
Not applicable / Other
Architecture
ARM / AArch64 / any (component-level bug; reproduced on Cortex-A9 QEMU, code
path is architecture-independent)
Board and hardware details
QEMU vexpress-a9 (bsp/qemu-vexpress-a9), RT_USING_LWIP + lwIP 2.2.1 +
LWIP_USING_DHCPD=y. Server started through the component's own exported
dhcp_server_start() (the same dhcp_server_recv udp callback that
dhcpd_start() registers; in products it is auto-started by WLAN AP mode —
components/drivers/wlan/dev_wlan_lwip.c:188 — and by the USB ECM/RNDIS
gadget demos via dhcpd_start("u0")).
Develop Toolchain
GCC (arm-none-eabi 12)
Describe the bug
dhcp_client_alloc() in components/net/lwip-dhcpd/dhcp_server_raw.c
(lines 252–263) searches the address pool with an unbounded
goto dhcp_alloc_again loop:
dhcp_alloc_again:
node = dhcp_client_find_by_ip(dhcpserver, &dhcpserver->current);
if (node != NULL)
{
ipaddr = (ntohl(dhcpserver->current.addr) + 1);
if (ipaddr > ntohl(dhcpserver->end.addr))
ipaddr = ntohl(dhcpserver->start.addr);
dhcpserver->current.addr = htonl(ipaddr);
goto dhcp_alloc_again; /* no iteration cap, no exhaustion exit */
}
There is no iteration limit and no "pool exhausted" failure path. In
addition node->lease_end is written (lines 380/457) but never read —
leases never expire, so once every address in the pool has a node, the pool
stays exhausted forever. After that, any DISCOVER carrying a new MAC makes
dhcp_client_find_by_ip() return non-NULL for every candidate and the loop
never terminates.
dhcp_server_recv() runs as a udp PCB callback in the lwIP tcpip thread,
so the loop spins the whole network stack thread: no further packet is ever
consumed (ip4_input never runs again) and every thread blocked in a socket
call (including msh while running ping) hangs permanently. Only a reboot
recovers.
Steps to reproduce (full chain under QEMU; scripts available on request):
- Build
bsp/qemu-vexpress-a9with lwIP 2.2.1 +LWIP_USING_DHCPD=y;
start the DHCP server one0with pool 10.0.2.2–10.0.2.254. - Send 253 DHCP DISCOVER packets with unique
chaddr(one UDP packet each,
~300 bytes, no authentication). GDB check:nodes=253,
current=10.0.2.254. - Verify the device works:
ping 10.0.2.2from msh → 4/4, 0% loss. - Send DISCOVER #254 with a new
chaddr. - Attach GDB — the tcpip thread is spinning inside the loop:
#0 dhcp_client_alloc dhcp_server_raw.c:256
#1 dhcp_server_recv dhcp_server_raw.c:375
#2 udp_input udp.c:404
#3 ip4_input ip4.c:737
#4 ethernet_input ethernet.c:186
#5 tcpip_thread_handle_msg / #6 tcpip_thread
Two GDB samples ~3 s apart show the cursor advancing inside the pool
(current=10.0.2.13 → current=10.0.2.118) — the loop never exits.
Two further probe packets are never processed (ip4_input breakpoint:
0 hits) and msh no longer echoes (help produces no output).
Expected behavior: bounded pool search with an exhaustion failure path
(return NULL → sender gets no OFFER); leases expire and addresses are
recycled.
Actual behavior: permanent pre-auth remote denial of service of the
whole network stack (and any thread waiting on sockets) after 254 UDP
packets; pool exhaustion alone (253 packets) already permanently disables
address allocation.
Other additional context
- Severity: CVSS 3.1
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H(7.5 High),
CWE-835 (+ CWE-665 for the missing lease lifecycle). - Related fixes in this file so far (
49f985e0fchaddr clamp,c00f13005
pbuf leak,1e24039cf8RELEASE loop) do not touch this path. - Suggested fix: cap the
dhcp_alloc_againwalk at pool-size iterations and
fail cleanly when exhausted; makelease_enda real expiry timestamp
checked by a periodic timer so nodes are recycled.
- Linguagem predominante
- C
- Estrelas
- 12.3k
- Forks
- 5.5k
- Merge médio
- 6d 32min
- PRs com merge (30d)
- 24
Preparar o ambiente
Inicia o contêiner de desenvolvimento do projeto no navegador, com a sua própria conta do GitHub.
- Sem Dockerfile nem arquivo Docker Compose
- Tem um modelo de pull request
- Ler o guia de contribuição
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Mais de RT-Thread/rt-thread
-
[Bug] [libc] timer_gettime 拆秒前将总纳秒截断为 uint32_t,剩余时间查询错误Talvez já em andamento @Yunlk assumiu há 2 dias. Abertain progress
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 68/100
RT-Thread/rt-thread#11924 · 6 comentários · 1 responsável ·
Mantenedores costumam responder em até 1 dia
-
bug Component component: net
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
RT-Thread/rt-thread#11913 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
[Bug] dfs_v2 tmpfs: ftruncate(fd, 0) frees the file buffer but reports success — use-after-free read/write and double free from a legal POSIX callTalvez já em andamento @remukisama assumiu há 6 dias. Abertain progress
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
RT-Thread/rt-thread#11902 · 4 comentários · 1 responsável ·
Mantenedores costumam responder em até 1 dia
-
[bsp][stm32][bluepill] README「快速上手」缺少重新生成 MDK 工程这一步,按文档操作无法编译通过Talvez já em andamento @moment-NEW assumiu há 23 dias. Abertain progress
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 75/100
RT-Thread/rt-thread#11818 · 4 comentários · 1 responsável ·
Mantenedores costumam responder em até 1 dia
-
BSP BSP: Loongson bug RT-Smart
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 72/100
RT-Thread/rt-thread#11717 · 2 comentários ·
Mantenedores costumam responder em até 1 dia
Todas as issues de RT-Thread/rt-thread
Issues semelhantes
-
Dificuldade 1/5 Menos de uma hora Facilidade para iniciantes 72/100
Mantenedores costumam responder em até 1 dia
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
yunusemreyl/omen-space#337 ·
Mantenedores costumam responder em até 1 dia
-
dependency component: oneMKL module: dpclang
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 82/100
intel/torch-xpu-ops#5880 ·
Mantenedores costumam responder em até 2 dias
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 74/100
Mantenedores costumam responder em até 1 dia
-
area/ci-build bug
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 65/100
DarkFlippers/qUnleashed#423 ·
Mantenedores costumam responder em até 1 dia