check field length against remaining buffer in mysql Field::Parse#3381
check field length against remaining buffer in mysql Field::Parse#3381ubeddulla wants to merge 2 commits into
Conversation
Signed-off-by: ubeddulla khan <ubed@bugqore.com>
There was a problem hiding this comment.
Pull request overview
This PR hardens the MySQL text-protocol reply parser (MysqlReply::Field::Parse) by rejecting length-encoded field sizes that exceed the remaining packet buffer, preventing uninitialized memory exposure and stream desynchronization when parsing malformed/malicious server responses.
Changes:
- Add a
len > buf.size()guard beforebuf.cutn(&str, len)in the text-protocolMysqlReply::Field::Parse. - Log and return
PARSE_ERROR_ABSOLUTELY_WRONGwhen an oversized length is encountered.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (len > buf.size()) { | ||
| LOG(WARNING) << "MysqlReply::Field::Parse: field length " << len | ||
| << " exceeds remaining buffer size " << buf.size(); | ||
| return PARSE_ERROR_ABSOLUTELY_WRONG; | ||
| } |
There was a problem hiding this comment.
Good call, added one in test/brpc_mysql_reply_parse_unittest.cpp. It crafts a text result set whose single row field uses a 0xFD lenenc prefix claiming 0xFFFFFF bytes with nothing left in the buffer, and asserts ConsumePartialIOBuf returns PARSE_ERROR_ABSOLUTELY_WRONG. There's also a well-formed-field case so the guard doesn't reject legitimate rows.
Signed-off-by: ubeddulla khan <ubed@bugqore.com>
What problem does this PR solve?
Issue Number: resolve N/A
Problem Summary:
The text-protocol
MysqlReply::Field::Parseinsrc/brpc/policy/mysql/mysql_reply.cppreads a length-encoded field length from the server and callsbuf.cutn(&str, len)without checkinglenagainst the remaining buffer.IOBuf::cutnclamps to what is available, so a field whose length-encoded prefix claims more bytes than remain makes the string branch allocatelenarena bytes, copy only the fewer bytes actually present, and then publish_data.stras a StringPiece oflenbytes. The tail is uninitialized arena memory that gets read back by the caller, and the short read desyncs the packet stream. A malicious or compromised MySQL server can trigger it through any text result set. Every sibling length-encoded read in the same file (the binaryField::Parse,Column::Parse, the auth-plugin path,ParseBinaryTime/ParseBinaryDataTime) already rejectslen > buf.size(); only this text overload was missing the check.What is changed and the side effects?
Changed:
Added the same
len > buf.size()guard before thecutnin the textField::Parse, returningPARSE_ERROR_ABSOLUTELY_WRONGon an oversized length. Valid result sets are unaffected since a well-formed field always fits in the buffer.Side effects:
Performance effects: none, a single size comparison per field.
Breaking backward compatibility: none.
Check List: