From 224658694ff722e4b1be17db1b1db1a72f855779 Mon Sep 17 00:00:00 2001 From: Valentin Metz Date: Wed, 11 Nov 2026 05:23:22 +0100 Subject: [PATCH] Fix stack-buffer overflow in CLI reply buffers The remote-CLI reply buffers in onPeerDataRecv() (repeater, room server, sensor) and BaseChatMesh were sized temp[166] for a 5-byte datagram header plus 161 bytes of reply. But MyMesh::handleCommand() first reflects a 3-byte correlation prefix (e.g. 'aa|') into the reply, after which CommonCLI commands may write up to 160 chars + NUL into the remaining 158 bytes -- overflowing the buffer by 2 bytes (e.g. a full 'regions' listing via exportTo(reply, 160)). Triggering this remotely crashes the node (observed as an unresponsive repeater after a prefixed 'regions' query); the 2 out-of-bounds bytes are a printable region-name character and a NUL. Size the buffers for the full worst case instead: 5 header + 3 prefix + 160 reply + 1 NUL = 169. Verified with a host ASan harness reproducing the exact layout: prefixed 'regions' with a 25-region listing overflowed temp[166] (BufStream::write, RegionMap.cpp) and now passes clean with temp[169]; unprefixed (serial) path unaffected. --- examples/simple_repeater/MyMesh.cpp | 3 ++- examples/simple_room_server/MyMesh.cpp | 3 ++- examples/simple_sensor/SensorMesh.cpp | 3 ++- src/helpers/BaseChatMesh.cpp | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index 99cd35bbaf5..7d06811f4d4 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -779,7 +779,8 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx, } } - uint8_t temp[166]; + // 5-byte datagram header + 3-byte reflected CLI prefix + 160-byte reply text + NUL + uint8_t temp[169]; char *command = (char *)&data[5]; char *reply = (char *)&temp[5]; if (is_retry) { diff --git a/examples/simple_room_server/MyMesh.cpp b/examples/simple_room_server/MyMesh.cpp index b1a88dd8765..c1a6b09ff07 100644 --- a/examples/simple_room_server/MyMesh.cpp +++ b/examples/simple_room_server/MyMesh.cpp @@ -462,7 +462,8 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx, mesh::Utils::sha256((uint8_t *)&ack_hash, 4, data, 5 + strlen((char *)&data[5]), client->id.pub_key, PUB_KEY_SIZE); - uint8_t temp[166]; + // 5-byte datagram header + 3-byte reflected CLI prefix + 160-byte reply text + NUL + uint8_t temp[169]; bool send_ack; if (flags == TXT_TYPE_CLI_DATA || flags == TXT_TYPE_CLI_COMMAND) { if (client->isAdmin()) { diff --git a/examples/simple_sensor/SensorMesh.cpp b/examples/simple_sensor/SensorMesh.cpp index bb747f63caa..2798c690117 100644 --- a/examples/simple_sensor/SensorMesh.cpp +++ b/examples/simple_sensor/SensorMesh.cpp @@ -667,7 +667,8 @@ void SensorMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_i // len can be > original length, but 'text' will be padded with zeroes data[len] = 0; // need to make a C string again, with null terminator - uint8_t temp[166]; + // 5-byte datagram header + 3-byte reflected CLI prefix + 160-byte reply text + NUL + uint8_t temp[169]; char *command = (char *) &data[5]; char *reply = (char *) &temp[5]; handleCommand(from, sender_timestamp, command, reply); diff --git a/src/helpers/BaseChatMesh.cpp b/src/helpers/BaseChatMesh.cpp index 4368d17f1c2..58c08deaa3f 100644 --- a/src/helpers/BaseChatMesh.cpp +++ b/src/helpers/BaseChatMesh.cpp @@ -266,7 +266,8 @@ void BaseChatMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender onCommandDataRecv(from, packet, sender_timestamp, text); // let UI know // NOTE: no ack expected for CLI_DATA replies } else if (flags == TXT_TYPE_CLI_COMMAND) { - uint8_t temp[166]; + // 5-byte datagram header + 3-byte reflected CLI prefix + 160-byte reply text + NUL + uint8_t temp[169]; char *command = (char *)&data[5]; char *reply = (char *)&temp[5]; *reply = 0;