From 33be9a23464df51e827976cee89effa4b704d362 Mon Sep 17 00:00:00 2001 From: dahuib Date: Sat, 14 Nov 2026 17:58:14 +0100 Subject: [PATCH] Validate reply-path length in repeater anonymous request handlers --- examples/simple_repeater/MyMesh.cpp | 42 ++++++++++++++--------------- examples/simple_repeater/MyMesh.h | 6 ++--- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index 21f833a588d..283c654b2eb 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -144,14 +144,21 @@ uint8_t MyMesh::handleLoginReq(const mesh::Identity& sender, const uint8_t* secr return 13; // reply length } -uint8_t MyMesh::handleAnonRegionsReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data) { +static bool extractReplyPath(const uint8_t* data, size_t len, uint8_t* reply_path, uint8_t& reply_path_len) { + if (len < 1) return false; + uint8_t path_len = *data++; + if (!mesh::Packet::isValidPathLen(path_len)) return false; + size_t path_byte_len = (size_t)(path_len & 63) * ((path_len >> 6) + 1); + if (1 + path_byte_len > len) return false; + reply_path_len = path_len; + mesh::Packet::writePath(reply_path, data, path_len); + return true; +} + +uint8_t MyMesh::handleAnonRegionsReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data, size_t len) { if (anon_limiter.allow(rtc_clock.getCurrentTime())) { // request data has: {reply-path-len}{reply-path} - reply_path_len = *data++; - if (!mesh::Packet::isValidPathLen(reply_path_len)) return 0; // reject - bad encoding - - mesh::Packet::writePath(reply_path, data, reply_path_len); - // data += (uint8_t)reply_path_len * reply_path_hash_size; + if (!extractReplyPath(data, len, reply_path, reply_path_len)) return 0; // reject - bad/incomplete encoding memcpy(reply_data, &sender_timestamp, 4); // prefix with sender_timestamp, like a tag uint32_t now = getRTCClock()->getCurrentTime(); @@ -162,14 +169,10 @@ uint8_t MyMesh::handleAnonRegionsReq(const mesh::Identity& sender, uint32_t send return 0; } -uint8_t MyMesh::handleAnonOwnerReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data) { +uint8_t MyMesh::handleAnonOwnerReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data, size_t len) { if (anon_limiter.allow(rtc_clock.getCurrentTime())) { // request data has: {reply-path-len}{reply-path} - reply_path_len = *data++; - if (!mesh::Packet::isValidPathLen(reply_path_len)) return 0; // reject - bad encoding - - mesh::Packet::writePath(reply_path, data, reply_path_len); - // data += (uint8_t)reply_path_len * reply_path_hash_size; + if (!extractReplyPath(data, len, reply_path, reply_path_len)) return 0; // reject - bad/incomplete encoding memcpy(reply_data, &sender_timestamp, 4); // prefix with sender_timestamp, like a tag uint32_t now = getRTCClock()->getCurrentTime(); @@ -181,14 +184,10 @@ uint8_t MyMesh::handleAnonOwnerReq(const mesh::Identity& sender, uint32_t sender return 0; } -uint8_t MyMesh::handleAnonClockReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data) { +uint8_t MyMesh::handleAnonClockReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data, size_t len) { if (anon_limiter.allow(rtc_clock.getCurrentTime())) { // request data has: {reply-path-len}{reply-path} - reply_path_len = *data++; - if (!mesh::Packet::isValidPathLen(reply_path_len)) return 0; // reject - bad encoding - - mesh::Packet::writePath(reply_path, data, reply_path_len); - // data += (uint8_t)reply_path_len * reply_path_hash_size; + if (!extractReplyPath(data, len, reply_path, reply_path_len)) return 0; // reject - bad/incomplete encoding memcpy(reply_data, &sender_timestamp, 4); // prefix with sender_timestamp, like a tag uint32_t now = getRTCClock()->getCurrentTime(); @@ -572,6 +571,7 @@ void MyMesh::onAnonDataRecv(mesh::Packet *packet, const uint8_t *secret, const m uint8_t *data, size_t len) { if (packet->getPayloadType() == PAYLOAD_TYPE_ANON_REQ) { // received an initial request by a possible admin // client (unknown at this stage) + if (len < 5) return; uint32_t timestamp; memcpy(×tamp, data, 4); @@ -582,11 +582,11 @@ void MyMesh::onAnonDataRecv(mesh::Packet *packet, const uint8_t *secret, const m if (data[4] == 0 || data[4] >= ' ') { // is password, ie. a login request reply_len = handleLoginReq(sender, secret, timestamp, &data[4], packet->isRouteFlood()); } else if (data[4] == ANON_REQ_TYPE_REGIONS && packet->isRouteDirect()) { - reply_len = handleAnonRegionsReq(sender, timestamp, &data[5]); + reply_len = handleAnonRegionsReq(sender, timestamp, &data[5], len - 5); } else if (data[4] == ANON_REQ_TYPE_OWNER && packet->isRouteDirect()) { - reply_len = handleAnonOwnerReq(sender, timestamp, &data[5]); + reply_len = handleAnonOwnerReq(sender, timestamp, &data[5], len - 5); } else if (data[4] == ANON_REQ_TYPE_BASIC && packet->isRouteDirect()) { - reply_len = handleAnonClockReq(sender, timestamp, &data[5]); + reply_len = handleAnonClockReq(sender, timestamp, &data[5], len - 5); } else { reply_len = 0; // unknown/invalid request type } diff --git a/examples/simple_repeater/MyMesh.h b/examples/simple_repeater/MyMesh.h index 7e4cfd4f22e..2ece6df4fb1 100644 --- a/examples/simple_repeater/MyMesh.h +++ b/examples/simple_repeater/MyMesh.h @@ -118,9 +118,9 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks { void putNeighbour(const mesh::Identity& id, uint32_t timestamp, float snr); uint8_t handleLoginReq(const mesh::Identity& sender, const uint8_t* secret, uint32_t sender_timestamp, const uint8_t* data, bool is_flood); - uint8_t handleAnonRegionsReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data); - uint8_t handleAnonOwnerReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data); - uint8_t handleAnonClockReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data); + uint8_t handleAnonRegionsReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data, size_t len); + uint8_t handleAnonOwnerReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data, size_t len); + uint8_t handleAnonClockReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data, size_t len); int handleRequest(ClientInfo* sender, uint32_t sender_timestamp, uint8_t* payload, size_t payload_len); mesh::Packet* createSelfAdvert();