feat(diag): reset-counters popup; harden repeater loop-detect bounds

- DiagnosticsScreen: Enter opens a confirm popup (defaults to Cancel) that
  zeroes the cumulative counters via Mesh::resetStats().
- Dispatcher::resetStats() made virtual; Mesh overrides it to also clear
  n_forwarded so the reset covers the repeater forward count.
- REPEAT_LOOP_MAX gains a 4-byte-hash entry and isRepeatLooped() bounds-
  checks hash_size, so it can't OOB-read if path_mode 3 is ever accepted.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-06-18 23:34:06 +02:00
co-authored by Claude Sonnet 4.6
parent d1d64dc612
commit f55b869fbe
4 changed files with 32 additions and 4 deletions
+6 -1
View File
@@ -525,7 +525,11 @@ bool MyMesh::filterRecvFloodPacket(mesh::Packet* packet) {
// thresholds (max times this node's hash may already appear in the path, by hash size).
// A companion moves around, so it re-enters its own flood's path more easily than a
// fixed repeater — hardcoded rather than configurable since there's no CLI here.
static const uint8_t REPEAT_LOOP_MAX[] = { 0, /*1-byte*/ 2, /*2-byte*/ 1, /*3-byte*/ 1 };
// Indexed by getPathHashSize() = (path_len>>6)+1, so 1..4. Index 0 is unused
// (hash size is never 0); index 4 covers path_mode 3, which tryParsePacket
// currently rejects — kept in-bounds so this can't OOB-read if that guard is
// ever relaxed.
static const uint8_t REPEAT_LOOP_MAX[] = { 0, /*1-byte*/ 2, /*2-byte*/ 1, /*3-byte*/ 1, /*4-byte*/ 1 };
// Caps how many hops an ADVERT flood gets repeated, matching simple_repeater's default
// flood_max_advert — adverts are the most frequent flood traffic, so this is the one
// depth limit worth keeping even without the rest of simple_repeater's flood_max knobs.
@@ -533,6 +537,7 @@ static const uint8_t REPEAT_MAX_ADVERT_HOPS = 8;
bool MyMesh::isRepeatLooped(const mesh::Packet* packet) const {
uint8_t hash_size = packet->getPathHashSize();
if (hash_size >= sizeof(REPEAT_LOOP_MAX)) return true; // unknown hash size: treat as looped, don't forward
uint8_t hash_count = packet->getPathHashCount();
uint8_t n = 0;
const uint8_t* path = packet->path;