From 241b4c97155b8a050895cb7b0de696fd933f75e9 Mon Sep 17 00:00:00 2001 From: lopsi <40902730+Lpsd@users.noreply.github.com> Date: Fri, 11 Sep 2026 21:02:07 +0100 Subject: [PATCH 1/2] Add small overhead for event size constraints --- Server/mods/deathmatch/logic/CGame.cpp | 3 ++- .../logic/packets/CLuaEventPacket.cpp | 2 +- .../deathmatch/logic/packets/CLuaEventPacket.h | 1 + .../mods/deathmatch/logic/CLatentReceiver.cpp | 17 +++++++++-------- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Server/mods/deathmatch/logic/CGame.cpp b/Server/mods/deathmatch/logic/CGame.cpp index c6d4001455d..62cc083721a 100644 --- a/Server/mods/deathmatch/logic/CGame.cpp +++ b/Server/mods/deathmatch/logic/CGame.cpp @@ -1131,7 +1131,8 @@ bool CGame::StaticProcessNetworkPacket(unsigned char ucPacketID, const NetServer { if (ucPacketID == PACKET_ID_LUA_EVENT) { - if (pBitStream->GetNumberOfUnreadBits() > CLuaEventPacket::MAX_LUA_EVENT_ARGUMENTS_SIZE * 8) + if (pBitStream->GetNumberOfUnreadBits() > + (CLuaEventPacket::MAX_LUA_EVENT_ARGUMENTS_SIZE + CLuaEventPacket::LUA_EVENT_ENVELOPE_HEADROOM) * 8) return false; } diff --git a/Server/mods/deathmatch/logic/packets/CLuaEventPacket.cpp b/Server/mods/deathmatch/logic/packets/CLuaEventPacket.cpp index c0706f681f3..f56de37a4bc 100644 --- a/Server/mods/deathmatch/logic/packets/CLuaEventPacket.cpp +++ b/Server/mods/deathmatch/logic/packets/CLuaEventPacket.cpp @@ -32,7 +32,7 @@ bool CLuaEventPacket::Read(NetBitStreamInterface& BitStream) { if (usNameLength < (MAX_EVENT_NAME_LENGTH - 1) && BitStream.ReadStringCharacters(m_strName, usNameLength) && BitStream.Read(m_ElementID)) { - if (BitStream.GetNumberOfUnreadBits() > MAX_LUA_LATENT_EVENT_ARGUMENTS_SIZE * 8) + if (BitStream.GetNumberOfUnreadBits() > (MAX_LUA_LATENT_EVENT_ARGUMENTS_SIZE + LUA_EVENT_ENVELOPE_HEADROOM) * 8) return false; // Faster than using a constructor diff --git a/Server/mods/deathmatch/logic/packets/CLuaEventPacket.h b/Server/mods/deathmatch/logic/packets/CLuaEventPacket.h index 281c5334df0..d244f44d8b1 100644 --- a/Server/mods/deathmatch/logic/packets/CLuaEventPacket.h +++ b/Server/mods/deathmatch/logic/packets/CLuaEventPacket.h @@ -17,6 +17,7 @@ class CLuaEventPacket final : public CPacket { public: + static constexpr int LUA_EVENT_ENVELOPE_HEADROOM = 64 * 1024; // Limit for the size of the arguments in a single triggerEvent. (1MB) static constexpr int MAX_LUA_EVENT_ARGUMENTS_SIZE = 1024 * 1024; // Limit for the size of the arguments in a single triggerLatentEvent. (10MB) diff --git a/Shared/mods/deathmatch/logic/CLatentReceiver.cpp b/Shared/mods/deathmatch/logic/CLatentReceiver.cpp index fc2115dbeb9..037e78c31ee 100644 --- a/Shared/mods/deathmatch/logic/CLatentReceiver.cpp +++ b/Shared/mods/deathmatch/logic/CLatentReceiver.cpp @@ -128,12 +128,10 @@ void CLatentReceiver::OnReceive(NetBitStreamInterface* pBitStream) if (uiFinalSize > 100 * 1024 * 1024) return OnReceiveError("uiFinalSize too large"); - // CATEGORY_PACKET reassembles raw packet data and feeds it into - // the main packet dispatch (CGame::StaticProcessPacket). Without - // a tighter cap, an attacker can craft a 100MB payload targeting - // packet handlers that scale poorly with input size (e.g. - // CPlayerModInfoPacket). 10MB is well above any legitimate use. - constexpr uint LATENT_PACKET_MAX_SIZE = 10 * 1024 * 1024; + // uiFinalSize includes the 5-byte CATEGORY_PACKET wrapper and the + // serialized event envelope. Keep 10 MiB available for argument data + // while allowing a small amount of protocol overhead. + constexpr uint LATENT_PACKET_MAX_SIZE = 10 * 1024 * 1024 + 64 * 1024; if (usCategory == CATEGORY_PACKET && uiFinalSize > LATENT_PACKET_MAX_SIZE) return OnReceiveError("CATEGORY_PACKET payload too large"); @@ -159,8 +157,11 @@ void CLatentReceiver::OnReceive(NetBitStreamInterface* pBitStream) // // Read body // - if (activeRx.uiWritePosition + usSizeSent > activeRx.buffer.GetSize()) - return OnReceiveError("Buffer would overflow"); + if (activeRx.uiWritePosition > activeRx.buffer.GetSize() || usSizeSent > activeRx.buffer.GetSize() - activeRx.uiWritePosition) + { + return OnReceiveError( + SString("Buffer would overflow (size:%u pos:%u chunk:%u)", activeRx.buffer.GetSize(), activeRx.uiWritePosition, usSizeSent)); + } if (bIsTail && activeRx.uiWritePosition + usSizeSent != activeRx.buffer.GetSize()) return OnReceiveError("Buffer size wrong"); From 2be87cb383a64403306813918a8523abdd0fbd46 Mon Sep 17 00:00:00 2001 From: lopsi <40902730+Lpsd@users.noreply.github.com> Date: Fri, 11 Sep 2026 21:19:18 +0100 Subject: [PATCH 2/2] Run clang-format --- Server/mods/deathmatch/logic/CGame.cpp | 3 +-- Shared/mods/deathmatch/logic/CLatentReceiver.cpp | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Server/mods/deathmatch/logic/CGame.cpp b/Server/mods/deathmatch/logic/CGame.cpp index 62cc083721a..a34a50f2cec 100644 --- a/Server/mods/deathmatch/logic/CGame.cpp +++ b/Server/mods/deathmatch/logic/CGame.cpp @@ -1131,8 +1131,7 @@ bool CGame::StaticProcessNetworkPacket(unsigned char ucPacketID, const NetServer { if (ucPacketID == PACKET_ID_LUA_EVENT) { - if (pBitStream->GetNumberOfUnreadBits() > - (CLuaEventPacket::MAX_LUA_EVENT_ARGUMENTS_SIZE + CLuaEventPacket::LUA_EVENT_ENVELOPE_HEADROOM) * 8) + if (pBitStream->GetNumberOfUnreadBits() > (CLuaEventPacket::MAX_LUA_EVENT_ARGUMENTS_SIZE + CLuaEventPacket::LUA_EVENT_ENVELOPE_HEADROOM) * 8) return false; } diff --git a/Shared/mods/deathmatch/logic/CLatentReceiver.cpp b/Shared/mods/deathmatch/logic/CLatentReceiver.cpp index 037e78c31ee..1acdaa1b64a 100644 --- a/Shared/mods/deathmatch/logic/CLatentReceiver.cpp +++ b/Shared/mods/deathmatch/logic/CLatentReceiver.cpp @@ -159,8 +159,7 @@ void CLatentReceiver::OnReceive(NetBitStreamInterface* pBitStream) // if (activeRx.uiWritePosition > activeRx.buffer.GetSize() || usSizeSent > activeRx.buffer.GetSize() - activeRx.uiWritePosition) { - return OnReceiveError( - SString("Buffer would overflow (size:%u pos:%u chunk:%u)", activeRx.buffer.GetSize(), activeRx.uiWritePosition, usSizeSent)); + return OnReceiveError(SString("Buffer would overflow (size:%u pos:%u chunk:%u)", activeRx.buffer.GetSize(), activeRx.uiWritePosition, usSizeSent)); } if (bIsTail && activeRx.uiWritePosition + usSizeSent != activeRx.buffer.GetSize())