fix(parser_data_tamer): bound snapshot lengths before consuming them#184
Open
pabloinigoblasco wants to merge 2 commits into
Open
fix(parser_data_tamer): bound snapshot lengths before consuming them#184pabloinigoblasco wants to merge 2 commits into
pabloinigoblasco wants to merge 2 commits into
Conversation
The DataTamer snapshot framing carries two wire-declared uint32 lengths (mask_size, payload_size). parseScalarsImpl consumed them without checking against the bytes actually remaining. Deserialize<> memcpy's before its bounds check and BufferSpan::trimFront subtracts without a floor, so an inflated length underflows size_t and walks the read cursor into a wild pointer -> SIGSEGV on 64-bit desktop builds, reachable from any truncated or corrupt DataTamer source (MCAP or live channel). Validate each length against the remaining buffer before consuming it, and require the 4 header bytes to be present before each Deserialize<uint32_t>. Add regression tests for oversized mask_size, truncated header, and oversized payload_size.
…apshot-length-bounds
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The DataTamer snapshot framing carries two wire-declared
uint32lengths (mask_size,payload_size).parseScalarsImplconsumed both without checking them against the bytes actually remaining in the payload. Two shared primitives make that unsafe on their own:Deserialize<T>runsstd::memcpy(&var, buffer.data, N)before itsN > buffer.sizebounds check.BufferSpan::trimFront(n)doesdata += n; size -= n;with no floor, so an oversizednunderflowssize_t.An inflated length therefore underflows
sizeand walks the read cursor into a wild pointer → SIGSEGV on 64-bit desktop builds, reachable from any truncated or corrupt DataTamer source (MCAP with a DataTamer schema, or a live ZMQ/MQTT/UDP channel).Fix: validate each length against the remaining buffer before consuming it, and require the 4 header bytes to be present before each
Deserialize<uint32_t>. Reject withPJ::unexpectedinstead of reading past the end. This is the only bounds check between untrusted wire bytes and the readers, so the guard lives here (thedata_tamerdependency is a pinned upstream release).Why
A single truncated or corrupt DataTamer snapshot crashes the whole application with a wild-pointer read — no bad actor required, just a bag cut mid-write. Same defect class as the ROS2-CDR byte-sequence OOB (#183), in a different parser.
Testing
ctest -R data_tamer— three new regression tests, all rejecting cleanly with no crash:OversizedMaskSizeIsRejected—mask_size = 0xFFFFFFFFwith only the 4 header bytes presentTruncatedBeforeMaskSizeIsRejected— payload shorter than the 4-byte headerOversizedPayloadSizeIsRejected—payload_size = 0xFFFFFFFFwith nothing following the mask