Skip to content

fix(mesh): widen TRACE offset to uint16 to avoid narrowing#2532

Open
swaits wants to merge 1 commit into
meshcore-dev:mainfrom
swaits:fix/trace-offset-widening
Open

fix(mesh): widen TRACE offset to uint16 to avoid narrowing#2532
swaits wants to merge 1 commit into
meshcore-dev:mainfrom
swaits:fix/trace-offset-widening

Conversation

@swaits
Copy link
Copy Markdown

@swaits swaits commented May 12, 2026

Summary

In the TRACE-packet forwarding branch of Mesh::onRecvPacket (src/Mesh.cpp), the byte-offset computed as pkt->path_len << path_sz was being narrowed to uint8_t. With path_sz = 3 (an 8-byte path hash entry) and pkt->path_len ≥ 32, the shift overflowed the destination type and wrapped, steering the subsequent isHashMatch() read to the wrong byte in pkt->payload. This is a logic / mis-routing bug, not a memory-safety bug — the read still lands inside the 184-byte payload buffer. Fix is a one-line type widening.

Background

uint8_t path_sz = flags & 0x03;       // 0..3
uint8_t len    = pkt->payload_len - i;
uint8_t offset = pkt->path_len << path_sz;   // <-- narrowing
if (offset >= len) { ... }
else if (self_id.isHashMatch(&pkt->payload[i + offset], 1 << path_sz) && ...) { ... }

pkt->path_len is uint16_t (src/Packet.h). pkt->path_len << path_sz is performed in int, then assigned to uint8_t, taking the low 8 bits. For path_len = 32, path_sz = 3 the true byte offset is 256 (wraps to 0); for path_len = 33, true offset is 264 (wraps to 8); etc. The receiver then reads path_sz-sized entries from the wrong position, producing either spurious "I am the next hop" matches or silent drops.

Change

src/Mesh.cpp — widen offset to uint16_t and explicitly cast the shifted operand to uint16_t to avoid any future surprise from integer promotion rules.

Why this is the minimal fix

A one-line type widening. No callers need to change — isHashMatch and pkt->payload[] indexing both already accept the wider value cleanly.

Risk / compatibility

  • Wire format: unchanged.
  • Behaviour: correct for the path_len*entry_size > 255 case (previously mis-routed); identical for the common case where it stays in uint8_t range.

References

  • CWE-197 — Numeric Truncation Error.
  • ISO/IEC 9899 §6.3.1.3 ("Signed and unsigned integers"): conversion of a value that doesn't fit in the destination type yields an implementation-defined / wrap-around result; the C++ rule for unsigned narrowing is modular.

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