Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

[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)

Đang mở
#11,878 1 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
35/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
c
Lĩnh vực
networking

Hướng nghiên cứu

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.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

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):

  1. Build bsp/qemu-vexpress-a9 with lwIP 2.2.1 + LWIP_USING_DHCPD=y;
    start the DHCP server on e0 with pool 10.0.2.2–10.0.2.254.
  2. 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.
  3. Verify the device works: ping 10.0.2.2 from msh → 4/4, 0% loss.
  4. Send DISCOVER #254 with a new chaddr.
  5. 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 (49f985e0f chaddr clamp, c00f13005
    pbuf leak, 1e24039cf8 RELEASE loop) do not touch this path.
  • Suggested fix: cap the dhcp_alloc_again walk at pool-size iterations and
    fail cleanly when exhausted; make lease_end a real expiry timestamp
    checked by a periodic timer so nodes are recycled.
Ngôn ngữ chính
C
Star
12.3k
Fork
5.5k
Merge trung bình
7 ngày 23 giờ
Pull request đã merge (30 ngày)
30

Chuẩn bị môi trường

Mở trong Codespaces

Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của RT-Thread/rt-thread

Tất cả issue của RT-Thread/rt-thread

Issue tương tự

Thêm issue về C

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.