Skip to content

Handle very rare stream failure when packets contain magic bytes - #104

Merged
lukipuki merged 11 commits into
meshtastic:mainfrom
ProjectMoon:main
Aug 17, 2026
Merged

Handle very rare stream failure when packets contain magic bytes#104
lukipuki merged 11 commits into
meshtastic:mainfrom
ProjectMoon:main

Conversation

@ProjectMoon

@ProjectMoon ProjectMoon commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Summary
Fixes a very rare situation where the stream parser can start attempting to parse a legitimate packet's bytes as a new frame/packet when that packet contains the Meshtastic protocol magic bytes, and then the parser just starts eating all incoming bytes as part of that frame, and never completing the packet emission. This completely halts the stream.

Proposed Changes

  • The approach in this PR recognizes strange packet sizes and is like "no way."
  • Attempt to decode a supposedly malformed packet before actually deciding it is malformed.

Checklist

  • Tests pass locally
  • Documentation updated if needed

Summary by CodeRabbit

Summary by CodeRabbit

  • Bug Fixes
    • Improved packet validation when payload data contains byte sequences resembling malformed packet markers.
    • Valid packets now decode correctly when these sequences appear within their payload.
    • Connection streams continue processing subsequent packets after misleading marker data is encountered.
    • Added regression coverage for affected packets and following recovery packets.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6e76de58-e292-479d-8aef-5fc110b89394

📥 Commits

Reviewing files that changed from the base of the PR and between 6e7e236 and 30caf87.

📒 Files selected for processing (1)
  • src/connections/stream_buffer.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/connections/stream_buffer.rs

Included review availability: Your plan includes up to 2 reviews per rolling hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The stream buffer now validates the payload at the declared packet length before rejecting an apparent internal header. A regression test verifies that both the packet and a following recovery packet decode successfully.

Changes

Stream buffer validation

Layer / File(s) Summary
Payload validation and regression coverage
src/connections/stream_buffer.rs
The stream buffer accepts a packet when its declared payload decodes successfully. An asynchronous test covers a coincidental internal header sequence and verifies the following packet.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 30caf

This localized parser change is intended to prevent valid packets containing protocol magic bytes from stalling the stream; no actionable merge-blocking risk remains after normal checks and review.

Poem

A rabbit checks the header twice,
Then finds the payload sound and nice.
The first packet hops on through,
The recovery packet follows too.
The stream stays clear and true!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the primary change: fixing a rare stream failure caused by packets containing protocol magic bytes.
Description check ✅ Passed The description explains the failure, proposed fix, and test coverage, but it omits the Related Issues section and leaves checklist items unchecked.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ProjectMoon ProjectMoon changed the title Handle very rare stream failure when packets contained magic bytes Handle very rare stream failure when packets contain magic bytes Aug 4, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/connections/stream_buffer.rs`:
- Around line 747-785: Update
resync_after_false_header_match_with_implausible_size to embed [0x94, 0xc3, 254,
6] within the declared payload of a valid length-delimited packet, rather than
appending it between encoded packets. Assert that this affected packet and the
following packet are both delivered and the buffer is empty; if the test fails,
adjust validate_packet_in_buffer framing/resynchronization so the outer valid
frame is preserved instead of drained as MalformedPacket.
- Around line 45-46: Update match patterns for StreamBufferError::DecodeFailure
to use the tuple-variant form DecodeFailure(..), matching its declaration with
the prost::DecodeError payload.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e577820d-07ca-472f-8ba9-29955f7169ba

📥 Commits

Reviewing files that changed from the base of the PR and between 86fd2a4 and 4dd2139.

📒 Files selected for processing (1)
  • src/connections/stream_buffer.rs

Comment thread src/connections/stream_buffer.rs
Comment thread src/connections/stream_buffer.rs Outdated
@ProjectMoon

Copy link
Copy Markdown
Contributor Author

OK, new solution, as the previous would drop the packet. Now both packets are decoded, and also there's a test with the actual type of packet that can cause this.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/connections/stream_buffer.rs`:
- Around line 764-770: Update the collision assertion for encoded_outer to
inspect only the payload bytes after PACKET_HEADER_SIZE, then scan those bytes
for the [0x94, 0xc3] window. Preserve the existing assertion message and
collision expectation.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d4db51d2-92ae-40b9-ada0-6dea9378bf22

📥 Commits

Reviewing files that changed from the base of the PR and between 7d68ebd and 794e1e1.

📒 Files selected for processing (1)
  • src/connections/stream_buffer.rs

Comment thread src/connections/stream_buffer.rs
ProjectMoon and others added 2 commits August 5, 2026 19:29
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Comment thread src/connections/stream_buffer.rs Outdated
// Only malformed if it doesn't decode at the declared length.
let declared_packet =
&self.buffer[packet_data_start_index..packet_data_start_index + packet_data_size];
if protobufs::FromRadio::decode(declared_packet).is_ok() {

@lukipuki lukipuki Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FromRadio::decode is an expensive operation. The chance of calling it by accident is only 1/65536 (1/2^16), though, so this should be OK - assuming the payloads are mostly random.

A malicious actor can send payloads containing [0x94, 0xc3] to trigger this code and burn CPU cycles, but this can only happen on public meshes. Private meshes are protected by passwords.

Let me think about this a bit more, I'd like to know why the code looks for the next packet inside of the current packet. Maybe there's a more elegant way of doing this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A better way would be a full state machine, I would think. If we don't see an end marker, but encounter magic bytes start marker, then we have to assume those bytes are part of the current packet?

Comment thread src/connections/stream_buffer.rs
Comment thread src/connections/stream_buffer.rs Outdated
Comment thread src/connections/stream_buffer.rs Outdated
ProjectMoon and others added 4 commits August 17, 2026 10:11
Co-authored-by: Lukáš Poláček <lukas@polacek.email>
Co-authored-by: Lukáš Poláček <lukas@polacek.email>
Co-authored-by: Lukáš Poláček <lukas@polacek.email>
@lukipuki
lukipuki merged commit ecc51ab into meshtastic:main Aug 17, 2026
10 of 13 checks passed
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.

2 participants