This is an automated email from the ASF dual-hosted git repository.
ptupitsyn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new c0a134be86b IGNITE-28110 Fix buffer leak in
ClientInboundMessageHandler on invalid message (#7733)
c0a134be86b is described below
commit c0a134be86bdf1a5cd385dc3fef82621cec28e88
Author: Pavel Tupitsyn <[email protected]>
AuthorDate: Mon Mar 9 17:19:49 2026 +0100
IGNITE-28110 Fix buffer leak in ClientInboundMessageHandler on invalid
message (#7733)
---
.../ignite/client/handler/ItClientHandlerTest.java | 54 ++++++++++++++++++++++
.../handler/ClientInboundMessageHandler.java | 38 ++++++++-------
2 files changed, 76 insertions(+), 16 deletions(-)
diff --git
a/modules/client-handler/src/integrationTest/java/org/apache/ignite/client/handler/ItClientHandlerTest.java
b/modules/client-handler/src/integrationTest/java/org/apache/ignite/client/handler/ItClientHandlerTest.java
index 1d8a197991c..88ecf25bfa8 100644
---
a/modules/client-handler/src/integrationTest/java/org/apache/ignite/client/handler/ItClientHandlerTest.java
+++
b/modules/client-handler/src/integrationTest/java/org/apache/ignite/client/handler/ItClientHandlerTest.java
@@ -580,6 +580,60 @@ public class ItClientHandlerTest extends
BaseIgniteAbstractTest {
}
}
+ @Test
+ void testInvalidHandshakeStateDropsConnection() throws Exception {
+ try (var sock = new Socket("127.0.0.1", serverPort)) {
+ OutputStream out = sock.getOutputStream();
+
+ // Magic: IGNI
+ out.write(MAGIC);
+
+ // Send first handshake.
+ try (var packer1 = MessagePack.newDefaultBufferPacker()) {
+ packer1.packInt(0);
+ packer1.packInt(0);
+ packer1.packInt(0);
+ packer1.packInt(7); // Size.
+
+ packer1.packInt(3); // Major
+ packer1.packInt(0); // Minor
+ packer1.packInt(0); // Patch
+
+ packer1.packInt(2); // Client type: general purpose.
+
+ packer1.packBinaryHeader(0); // Features.
+ packer1.packInt(0); // Extensions.
+
+ out.write(packer1.toByteArray());
+ }
+
+ // Second message before handshake completes.
+ // This should trigger "Unexpected message received before
handshake completion"
+ try (var packer2 = MessagePack.newDefaultBufferPacker()) {
+ packer2.packInt(0);
+ packer2.packInt(0);
+ packer2.packInt(0);
+ packer2.packInt(7); // Size.
+
+ packer2.packInt(3); // Major
+ packer2.packInt(0); // Minor
+ packer2.packInt(0); // Patch
+
+ packer2.packInt(2); // Client type: general purpose.
+
+ packer2.packBinaryHeader(0); // Features.
+ packer2.packInt(0); // Extensions.
+
+ out.write(packer2.toByteArray());
+ }
+
+ out.flush();
+
+ // Server drops the connection due to invalid message.
+ assertThrows(IOException.class, () -> writeAndFlushLoop(sock));
+ }
+ }
+
private static void writeAndFlushLoop(Socket socket) throws Exception {
var stop = System.currentTimeMillis() + 5000;
var out = socket.getOutputStream();
diff --git
a/modules/client-handler/src/main/java/org/apache/ignite/client/handler/ClientInboundMessageHandler.java
b/modules/client-handler/src/main/java/org/apache/ignite/client/handler/ClientInboundMessageHandler.java
index 9d63ccd9c41..e1cb98429e8 100644
---
a/modules/client-handler/src/main/java/org/apache/ignite/client/handler/ClientInboundMessageHandler.java
+++
b/modules/client-handler/src/main/java/org/apache/ignite/client/handler/ClientInboundMessageHandler.java
@@ -421,28 +421,34 @@ public class ClientInboundMessageHandler
// Each inbound handler in a pipeline has to release the received
messages.
var unpacker = new ClientMessageUnpacker(byteBuf);
- metrics.bytesReceivedAdd(byteBuf.readableBytes() +
ClientMessageCommon.HEADER_SIZE);
- switch (state) {
- case STATE_BEFORE_HANDSHAKE:
- state = STATE_HANDSHAKE_REQUESTED;
-
metrics.bytesReceivedAdd(ClientMessageCommon.MAGIC_BYTES.length);
- handshake(ctx, unpacker);
+ try {
+ metrics.bytesReceivedAdd(byteBuf.readableBytes() +
ClientMessageCommon.HEADER_SIZE);
- break;
+ switch (state) {
+ case STATE_BEFORE_HANDSHAKE:
+ state = STATE_HANDSHAKE_REQUESTED;
+
metrics.bytesReceivedAdd(ClientMessageCommon.MAGIC_BYTES.length);
+ handshake(ctx, unpacker);
- case STATE_HANDSHAKE_REQUESTED:
- // Handshake is in progress, any messages are not allowed.
- throw new IgniteException(PROTOCOL_ERR, "Unexpected message
received before handshake completion");
+ break;
- case STATE_HANDSHAKE_RESPONSE_SENT:
- assert clientContext != null : "Client context != null";
- processOperation(ctx, unpacker);
+ case STATE_HANDSHAKE_REQUESTED:
+ // Handshake is in progress, any messages are not allowed.
+ throw new IgniteException(PROTOCOL_ERR, "Unexpected
message received before handshake completion");
- break;
+ case STATE_HANDSHAKE_RESPONSE_SENT:
+ assert clientContext != null : "Client context != null";
+ processOperation(ctx, unpacker);
- default:
- throw new IllegalStateException("Unexpected state: " + state);
+ break;
+
+ default:
+ throw new IllegalStateException("Unexpected state: " +
state);
+ }
+ } catch (Throwable t) {
+ unpacker.close();
+ throw t;
}
}