Fix off-by-one in TCP MBAP length validation (1-byte OOB write) - #123
Open
94xhn wants to merge 1 commit into
Open
Fix off-by-one in TCP MBAP length validation (1-byte OOB write)#12394xhn wants to merge 1 commit into
94xhn wants to merge 1 commit into
Conversation
recv_msg_header() accepted a TCP MBAP length field up to 255, but after the 8-byte MBAP header is parsed only 252 bytes remain available in msg.buf (uint8_t buf[260], valid indices 0-259, with 8 bytes already consumed). A length of 255 causes recv(nmbs, length - 2) to write 253 bytes starting at buf_idx 8, i.e. buf[8..260], one byte past the end of buf[260]. That extra byte lands on the low byte of the immediately following buf_idx struct member, corrupting internal library state from a single attacker-controlled byte on the wire (CWE-193). Change the upper bound from 255 to 254 so the maximum accepted length exactly fills buf[8..259] with no overflow, matching the actual space available after the MBAP header.
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.
Bug
In
recv_msg_header()(TCP branch), the MBAPlengthfield is validated with:At this point the 8-byte MBAP header has already been parsed, so
msg.buf_idx == 8.recv(nmbs, length - 2)writes starting atbuf_idx, i.e. intomsg.buf[buf_idx .. buf_idx + (length - 2) - 1].msg.bufis declared asuint8_t buf[260](nanomodbus.h), so valid indices are0..259. With the maximum currently-acceptedlength == 255, the write isrecv(nmbs, 253), coveringbuf[8..260]— index260is one byte past the end of the array. That extra byte lands on the low byte ofmsg.buf_idxitself, the very next struct member afterbuf, corrupting internal parser state from a single attacker-controlled length byte on the wire.I reproduced this with a mock
platform.readsending a crafted MBAP header (length = 0x00FF = 255) followed by 253 payload bytes:msg.buf_idxgets clobbered from8to the low byte of the last payload byte written.Fix
Tighten the upper bound from
255to254. Withlength == 254,recv(nmbs, 252)writes exactlybuf[8..259], fillingbuf[260]with zero slack and no overflow. Verified this boundary case is still accepted and produces no out-of-bounds write, and that ordinary small requests are unaffected.I also ran the project's own test suite (
tests/nanomodbus_tests.c) before and after the change with identical pass results.This is the same one-line class of issue as the existing off-by-one/overflow checks in this file; no other behavior is changed.