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

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


The following commit(s) were added to refs/heads/master by this push:
     new 6a2f56a1d98 [fix](fe) Bound length in MysqlProto.readLenEncodedString 
(#63604)
6a2f56a1d98 is described below

commit 6a2f56a1d98c69441e6005e337035daa2299b615
Author: MarkLee131 <[email protected]>
AuthorDate: Wed Jun 3 14:46:24 2026 +0800

    [fix](fe) Bound length in MysqlProto.readLenEncodedString (#63604)
    
    ### What problem does this PR solve?
    
    Issue Number: close #63603
    
    Problem Summary:
    
    `MysqlProto.readLenEncodedString` reads a length-encoded integer and
    passes it straight to `new byte[(int) length]` with no bound. The length
    is fully attacker-controlled (a `0xFE` lead byte carries an 8-byte
    value), and it is read before authentication from
    `MysqlAuthPacket.readFrom` (the auth-response field at
    `MysqlAuthPacket.java:93` and the connection-attributes loop at
    `MysqlAuthPacket.java:110-118`). A small handshake response can
    therefore request
    a ~2 GiB allocation, and a length with the high bit set casts to a
    negative size (`NegativeArraySizeException`).
    
    This PR rejects a length that is negative or larger than the bytes
    remaining in the buffer before allocating. A well-formed length-encoded
    string's payload always fits in the remaining buffer, so valid input is
    unaffected. One guard covers both reach paths.
---
 .../java/org/apache/doris/mysql/MysqlProto.java    |  8 +++
 .../doris/mysql/MysqlProtoLenEncStringTest.java    | 61 ++++++++++++++++++++++
 2 files changed, 69 insertions(+)

diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/MysqlProto.java 
b/fe/fe-core/src/main/java/org/apache/doris/mysql/MysqlProto.java
index 4f8914ef9fc..4e495a428ed 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mysql/MysqlProto.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/MysqlProto.java
@@ -329,6 +329,14 @@ public class MysqlProto {
 
     public static byte[] readLenEncodedString(ByteBuffer buffer) {
         long length = readVInt(buffer);
+        // The string payload must fit in the bytes actually remaining in the 
packet.
+        // Without this bound an attacker-controlled length is passed straight 
to
+        // new byte[(int) length], where the (int) cast can go negative or 
request
+        // up to ~2 GiB from a few bytes on the wire.
+        if (length < 0 || length > buffer.remaining()) {
+            throw new IllegalArgumentException("invalid length-encoded string 
length: " + length
+                    + ", remaining: " + buffer.remaining());
+        }
         byte[] buf = new byte[(int) length];
         buffer.get(buf);
         return buf;
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/mysql/MysqlProtoLenEncStringTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/mysql/MysqlProtoLenEncStringTest.java
new file mode 100644
index 00000000000..237632eb00b
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/mysql/MysqlProtoLenEncStringTest.java
@@ -0,0 +1,61 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.mysql;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+
+public class MysqlProtoLenEncStringTest {
+
+    // A length-encoded string whose declared length exceeds the bytes actually
+    // present must be rejected, not passed to new byte[(int) length]. Before 
the
+    // bound, a 0xFE lead byte plus an 8-byte length let a handful of bytes 
request
+    // ~2 GiB, and a high-bit length cast to a negative size.
+    @Test
+    public void readLenEncodedStringRejectsOversizedLength() {
+        ByteBuffer buffer = ByteBuffer.allocate(9);
+        buffer.put((byte) 0xFE); // 8-byte length follows
+        buffer.put(new byte[] {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 
0x7F, 0, 0, 0, 0}); // 0x7FFFFFFF
+        buffer.flip();
+        Assert.assertThrows(IllegalArgumentException.class,
+                () -> MysqlProto.readLenEncodedString(buffer));
+    }
+
+    @Test
+    public void readLenEncodedStringRejectsNegativeCastLength() {
+        ByteBuffer buffer = ByteBuffer.allocate(9);
+        buffer.put((byte) 0xFE);
+        buffer.put(new byte[] {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 
0xFF, 0, 0, 0, 0}); // (int) -> -1
+        buffer.flip();
+        Assert.assertThrows(IllegalArgumentException.class,
+                () -> MysqlProto.readLenEncodedString(buffer));
+    }
+
+    @Test
+    public void readLenEncodedStringAcceptsValidPayload() {
+        byte[] payload = "abc".getBytes(StandardCharsets.UTF_8);
+        ByteBuffer buffer = ByteBuffer.allocate(1 + payload.length);
+        buffer.put((byte) payload.length); // single-byte length < 251
+        buffer.put(payload);
+        buffer.flip();
+        Assert.assertArrayEquals(payload, 
MysqlProto.readLenEncodedString(buffer));
+    }
+}


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

Reply via email to