This is an automated email from the ASF dual-hosted git repository.

wasphin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brpc.git


The following commit(s) were added to refs/heads/master by this push:
     new 5934fc0e Reject empty MySQL response packets (#3536)
5934fc0e is described below

commit 5934fc0e8ce4d7e0b552e4671e7d32c1a11a0813
Author: Xiaofeng Wang <[email protected]>
AuthorDate: Sat Sep 12 16:20:33 2026 +0800

    Reject empty MySQL response packets (#3536)
    
    Validate packet payload lengths before reading the response type byte.
    This prevents an empty packet from borrowing the first byte of a
    following packet during response parsing.
---
 src/brpc/policy/mysql/mysql_reply.cpp    | 10 ++++++++
 test/brpc_mysql_reply_parse_unittest.cpp | 41 ++++++++++++++++++++++++++++++++
 2 files changed, 51 insertions(+)

diff --git a/src/brpc/policy/mysql/mysql_reply.cpp 
b/src/brpc/policy/mysql/mysql_reply.cpp
index 2f3a9707..1a277339 100644
--- a/src/brpc/policy/mysql/mysql_reply.cpp
+++ b/src/brpc/policy/mysql/mysql_reply.cpp
@@ -200,6 +200,11 @@ ParseError MysqlReply::ConsumePartialIOBuf(butil::IOBuf& 
buf,
     }
     uint8_t header[4 + 1];  // use the extra byte to judge message type
     const uint8_t* p = (const uint8_t*)buf.fetch(header, sizeof(header));
+    if (_type == MYSQL_RSP_UNKNOWN &&
+        (p == nullptr || mysql_uint3korr(p) == 0)) {
+        LOG(ERROR) << "Invalid mysql packet with empty payload";
+        return PARSE_ERROR_ABSOLUTELY_WRONG;
+    }
     uint8_t type = (_type == MYSQL_RSP_UNKNOWN) ? p[4] : (uint8_t)_type;
     // During the connection (auth) phase the server may send an AuthMoreData
     // packet (first byte 0x01) as part of the caching_sha2_password exchange
@@ -243,6 +248,11 @@ ParseError MysqlReply::ConsumePartialIOBuf(butil::IOBuf& 
buf,
             butil::IOBuf discard;
             buf.cutn(&discard, amd_total);
             const uint8_t* p2 = (const uint8_t*)buf.fetch(header, 
sizeof(header));
+            if (p2 == nullptr || mysql_uint3korr(p2) == 0) {
+                LOG(ERROR) << "Invalid mysql packet with empty payload after "
+                              "fast-auth marker";
+                return PARSE_ERROR_ABSOLUTELY_WRONG;
+            }
             type = p2[4];
         } else {
             _type = MYSQL_RSP_AUTH_MORE_DATA;
diff --git a/test/brpc_mysql_reply_parse_unittest.cpp 
b/test/brpc_mysql_reply_parse_unittest.cpp
index 33ab95a5..f10773db 100644
--- a/test/brpc_mysql_reply_parse_unittest.cpp
+++ b/test/brpc_mysql_reply_parse_unittest.cpp
@@ -101,6 +101,47 @@ TEST(MysqlReplyParseTest, RejectOversizedTextFieldLength) {
     ASSERT_EQ(brpc::PARSE_ERROR_ABSOLUTELY_WRONG, rc);
 }
 
+TEST(MysqlReplyParseTest, RejectZeroPayloadPacket) {
+    butil::IOBuf buf;
+    buf.append(std::string("\x00\x00\x00\x01", 4));
+
+    brpc::MysqlReply reply;
+    butil::Arena arena;
+    bool more_results = false;
+    brpc::ParseError rc = reply.ConsumePartialIOBuf(
+        buf, &arena, false, brpc::MYSQL_NORMAL_STATEMENT, &more_results);
+    ASSERT_EQ(brpc::PARSE_ERROR_ABSOLUTELY_WRONG, rc);
+}
+
+TEST(MysqlReplyParseTest, RejectZeroPayloadPacketWithTrailingBytes) {
+    std::string wire("\x00\x00\x00\x01", 4);
+    AppendPacket(&wire, 2, std::string("\x00\x00\x00\x00\x00\x00\x00", 7));
+    butil::IOBuf buf;
+    buf.append(wire);
+
+    brpc::MysqlReply reply;
+    butil::Arena arena;
+    bool more_results = false;
+    brpc::ParseError rc = reply.ConsumePartialIOBuf(
+        buf, &arena, false, brpc::MYSQL_NORMAL_STATEMENT, &more_results);
+    ASSERT_EQ(brpc::PARSE_ERROR_ABSOLUTELY_WRONG, rc);
+}
+
+TEST(MysqlReplyParseTest, RejectZeroPayloadPacketAfterFastAuthMarker) {
+    std::string wire;
+    AppendPacket(&wire, 2, std::string("\x01\x03", 2));
+    wire.append(std::string("\x00\x00\x00\x03", 4));
+    butil::IOBuf buf;
+    buf.append(wire);
+
+    brpc::MysqlReply reply;
+    butil::Arena arena;
+    bool more_results = false;
+    brpc::ParseError rc = reply.ConsumePartialIOBuf(
+        buf, &arena, true, brpc::MYSQL_NORMAL_STATEMENT, &more_results);
+    ASSERT_EQ(brpc::PARSE_ERROR_ABSOLUTELY_WRONG, rc);
+}
+
 // A well-formed field whose length matches the bytes present still parses, so
 // the guard does not reject legitimate result sets.
 TEST(MysqlReplyParseTest, AcceptWellFormedTextField) {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to