Skip to content

Harden framing and exact I/O paths for partial read/write safety (plus related parser and stats improvements)#1905

Open
robekl wants to merge 1 commit intomeshcore-dev:devfrom
robekl:fix/checked-framing-io-layer
Open

Harden framing and exact I/O paths for partial read/write safety (plus related parser and stats improvements)#1905
robekl wants to merge 1 commit intomeshcore-dev:devfrom
robekl:fix/checked-framing-io-layer

Conversation

@robekl
Copy link

@robekl robekl commented Mar 3, 2026

Summary

This PR focuses on the primary reliability issue for embedded environments: partial reads/writes and unchecked I/O causing stream/file corruption, parse desync, or silent persistence failures.

The core change introduces and applies stricter exact-I/O behavior, then extends related hardening in packet framing/parsing and serial bridge ingress/egress paths.

Problem

On constrained devices and links, reads/writes can be partial. Existing code paths had several risks:

  • file reads/writes assuming one call transfers all bytes
  • socket frame handling that could desynchronize after partial writes/reads
  • packet parsing paths with weaker bounds/consistency checks
  • some persistence paths ignoring write return values

These issues can lead to:

  • corrupted on-disk state
  • broken framed stream alignment
  • dropped/invalid packets being mishandled
  • hard-to-debug reliability failures under load/noisy links

Primary Changes (Partial Read/Write Handling)

1) Added strict exact file I/O helper

  • Added: src/helpers/CheckedIO.h
  • Provides:
    • checked_io::readExact(...) with loop-until-complete or fail
    • checked_io::writeExact(...) with loop-until-complete or fail
    • typed wrappers readValue/writeValue

2) Applied checked exact I/O to persistence paths

  • Updated: src/helpers/ClientACL.cpp
    • replaced raw read/write checks with checked exact/value helpers
  • Updated: src/helpers/IdentityStore.cpp
    • checked reads for optional display name
    • save now returns real success/failure (no unconditional true)
    • checked exact write for display name block
  • Updated: src/helpers/CommonCLI.cpp
    • prefs load switched to compatibility-safe incremental checked reads
    • prefs save now checks all writes via checked exact/value helpers
    • logs when save path encounters partial/short write failure

3) Hardened WiFi framed I/O for partial read/write failures

  • Updated: src/helpers/esp32/SerialWifiInterface.cpp
    • exact header/payload socket reads
    • exact discard helper for oversized/unexpected frames
    • on partial TX write: treat as framing corruption, disconnect/reset queues/header
    • on header/payload read failure: disconnect/reset
    • on discard failure: disconnect/reset
    • drop counter incremented for dropped/error conditions
  • Updated: src/helpers/esp32/SerialWifiInterface.h
    • added WiFi drop counter storage + getter override
  • Updated: src/helpers/BaseSerialInterface.h
    • added default getDropCount() API (returns 0 by default)

Related / Derived Hardening Changes

Packet framing/parsing correctness

  • Updated: src/Packet.h, src/Packet.cpp
    • Packet::readFrom now takes size_t
    • strict bounds checks before transport/path/payload reads
    • validates payload version/path encoding early
    • commits packet state only after full validation succeeds
  • Updated: src/Dispatcher.cpp
    • parser path delegates to hardened Packet::readFrom
    • simplified and tightened invalid packet handling/logging
  • Updated: src/helpers/BaseChatMesh.cpp
    • now checks readFrom return and releases packet on failure

Bridge/radio ingress bounds

  • Updated: src/helpers/bridges/RS232Bridge.cpp
    • max packet length checks aligned to MAX_TRANS_UNIT
    • uses updated readFrom(..., size_t)
  • Updated: src/helpers/esp32/ESPNOWRadio.cpp
    • clamp received length to local buffer size
    • clamp copy length to destination size in recvRaw

Crypto input guard

  • Updated: src/Utils.cpp
    • rejects MAC+ciphertext lengths not aligned to cipher block size before decrypt

Stats surface for WiFi drops (no protocol framing changes)

  • Updated: src/helpers/StatsFormatHelper.h
    • stats-radio JSON now includes wifi_drops
  • Updated: src/helpers/CommonCLI.h
    • added getSerialDropCount() callback hook (default 0)
  • Updated call sites:
    • examples/simple_sensor/SensorMesh.cpp
    • examples/simple_room_server/MyMesh.cpp
    • examples/simple_repeater/MyMesh.cpp
  • Updated docs: docs/cli_commands.md
    • clarified WiFi drop count field context

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