From 584118b3b3c3bce04cbd97aea6058417d07afe15 Mon Sep 17 00:00:00 2001 From: Justin Wood Date: Wed, 13 May 2026 00:06:42 -0700 Subject: [PATCH] Reject zero-length TCP messages to prevent connection slot abuse (#71942) * Reject zero-length TCP messages to prevent connection slot abuse Zero-length messages (4-byte header of all zeros) were silently accepted as valid, keeping the connection alive. An attacker could hold all TCP connection slots (default: 4) indefinitely by sending just 4 zero bytes per probe, blocking legitimate CASE sessions. Reject zero-length messages and close the connection, since no valid Matter message has zero payload length. Co-Authored-By: Claude Opus 4.6 (1M context) * Address review: remove redundant CloseConnectionInternal, fix test - Remove explicit CloseConnectionInternal call since the caller (OnDataReceived) already handles connection closure on error return - Update test to expect CHIP_ERROR_INVALID_MESSAGE_LENGTH for zero-length messages Co-Authored-By: Claude Opus 4.6 (1M context) * Retrigger CI (REPL timeout) * Retrigger CI --------- Co-authored-by: Claude Opus 4.6 (1M context) Co-authored-by: Robert Szewczyk (cherry picked from commit 0e0a4aa81536291b08da6ab6411e99635dcf5555) --- src/transport/raw/TCP.cpp | 6 ++++-- src/transport/raw/tests/TestTCP.cpp | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/transport/raw/TCP.cpp b/src/transport/raw/TCP.cpp index cd4571ec145041..f87ffa16219170 100644 --- a/src/transport/raw/TCP.cpp +++ b/src/transport/raw/TCP.cpp @@ -347,8 +347,10 @@ CHIP_ERROR TCPBase::ProcessReceivedBuffer(Inet::TCPEndPoint * endPoint, const Pe if (messageSize == 0) { - // No payload but considered a valid message. Return success to keep the connection alive. - return CHIP_NO_ERROR; + // Zero-length messages are not valid Matter messages. Reject to + // prevent attackers from holding TCP connection slots indefinitely. + ChipLogError(Inet, "Received zero-length TCP message, closing connection."); + return CHIP_ERROR_INVALID_MESSAGE_LENGTH; } ReturnErrorOnFailure(ProcessSingleMessage(peerAddress, state, messageSize)); diff --git a/src/transport/raw/tests/TestTCP.cpp b/src/transport/raw/tests/TestTCP.cpp index dba7f0cd26e116..eac1c6c63d89a1 100644 --- a/src/transport/raw/tests/TestTCP.cpp +++ b/src/transport/raw/tests/TestTCP.cpp @@ -696,11 +696,11 @@ TEST_F(TestTCP, CheckProcessReceivedBuffer) TestData testData[2]; gMockTransportMgrDelegate.SetCallback(TestDataCallbackCheck, testData); - // Test a single packet buffer with zero message size. + // Test a single packet buffer with zero message size - should be rejected. System::PacketBufferHandle buf = System::PacketBufferHandle::NewWithData(messageSize_TEST, 4); ASSERT_NE(&buf, nullptr); err = TestAccess::ProcessReceivedBuffer(tcp, lEndPoint, lPeerAddress, std::move(buf)); - EXPECT_EQ(err, CHIP_NO_ERROR); + EXPECT_EQ(err, CHIP_ERROR_INVALID_MESSAGE_LENGTH); // Test a single packet buffer. gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0;