Skip to content

Fix infinite loop in WiFi frame skip when read fails#1660

Open
weebl2000 wants to merge 1 commit intomeshcore-dev:devfrom
weebl2000:fix/wifi-skip-loop-hang
Open

Fix infinite loop in WiFi frame skip when read fails#1660
weebl2000 wants to merge 1 commit intomeshcore-dev:devfrom
weebl2000:fix/wifi-skip-loop-hang

Conversation

@weebl2000
Copy link
Contributor

Severity: High

Summary

The WiFi interface's checkRecvFrame has two frame-skip loops that drain oversized or unexpected frames by reading one byte at a time. Each loop subtracts the return value of client.read(skip, 1) from frame_length. On ESP32, WiFiClient::read() returns -1 on error (disconnect, timeout). Subtracting -1 increments frame_length instead of decrementing it, turning the loop into an infinite hang.

How this can be exploited

A WiFi-connected client (e.g. a phone app, or anyone on the same WiFi network) can trigger this by:

  1. Connecting to the node's TCP server
  2. Sending a 3-byte frame header claiming a length > MAX_FRAME_SIZE (e.g. 65535)
  3. Disconnecting immediately (or sending no payload data)

The node enters the skip loop, client.read() returns -1 on the dead connection, frame_length increases on every iteration, and the loop never terminates. The node is now permanently hung — it can't process any radio traffic, BLE commands, or further WiFi connections. A physical reset is required to recover.

Users would see their node become completely unresponsive after a WiFi client connects and disconnects.

Fix

Switch from client.read(buf, 1) (which returns bytes read, possibly -1) to client.read() (single-byte read) and break on negative return. Decrement frame_length by exactly 1 per successful read. Both skip loops are fixed.

Test plan

  • Oversized WiFi frames are still correctly skipped
  • Unexpected frame types are still correctly skipped
  • Client disconnect during skip doesn't hang the node
  • Build tested on Heltec_v3_companion_radio_ble

The frame-skip loops in checkRecvFrame subtract the return value of
client.read() from frame_length. On ESP32, WiFiClient::read() returns
-1 on error. Subtracting -1 increments frame_length instead of
decrementing it, turning the loop into an infinite hang.

A WiFi client can trigger this by sending a frame header with a large
length and then disconnecting (or sending fewer bytes than claimed).
The node locks up in the skip loop and stops processing all traffic.

Switch to single-byte client.read() which returns the byte value or -1,
and break out of the loop on error. Decrement frame_length by exactly 1
per successful read.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant