From c7fc2bd57f993f4b369ced0fc8c08ca8398c4d86 Mon Sep 17 00:00:00 2001 From: Mauller <26652186+Mauller@users.noreply.github.com> Date: Fri, 5 Dec 2025 16:32:52 +0000 Subject: [PATCH] bugfix(network): Fix out of bounds memory access for wrapped net commands --- .../GameNetwork/NetCommandWrapperList.h | 2 +- .../GameNetwork/NetCommandWrapperList.cpp | 46 +++++++++++++------ 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/Core/GameEngine/Include/GameNetwork/NetCommandWrapperList.h b/Core/GameEngine/Include/GameNetwork/NetCommandWrapperList.h index f4ea0bed06..fac7ea7964 100644 --- a/Core/GameEngine/Include/GameNetwork/NetCommandWrapperList.h +++ b/Core/GameEngine/Include/GameNetwork/NetCommandWrapperList.h @@ -49,7 +49,7 @@ class NetCommandWrapperListNode : public MemoryPoolObject protected: UnsignedShort m_commandID; UnsignedByte *m_data; - UnsignedInt m_dataLength; + UnsignedInt m_totalDataLength; Bool *m_chunksPresent; UnsignedInt m_numChunks; UnsignedInt m_numChunksPresent; diff --git a/Core/GameEngine/Source/GameNetwork/NetCommandWrapperList.cpp b/Core/GameEngine/Source/GameNetwork/NetCommandWrapperList.cpp index 698a6b3334..86333e9016 100644 --- a/Core/GameEngine/Source/GameNetwork/NetCommandWrapperList.cpp +++ b/Core/GameEngine/Source/GameNetwork/NetCommandWrapperList.cpp @@ -45,8 +45,8 @@ NetCommandWrapperListNode::NetCommandWrapperListNode(NetWrapperCommandMsg *msg) m_chunksPresent[i] = FALSE; } - m_dataLength = msg->getTotalDataLength(); - m_data = NEW UnsignedByte[m_dataLength]; // pool[]ify + m_totalDataLength = msg->getTotalDataLength(); + m_data = NEW UnsignedByte[m_totalDataLength]; // pool[]ify m_commandID = msg->getWrappedCommandID(); } @@ -75,7 +75,7 @@ UnsignedShort NetCommandWrapperListNode::getCommandID() { } UnsignedInt NetCommandWrapperListNode::getRawDataLength() { - return m_dataLength; + return m_totalDataLength; } void NetCommandWrapperListNode::copyChunkData(NetWrapperCommandMsg *msg) { @@ -84,22 +84,42 @@ void NetCommandWrapperListNode::copyChunkData(NetWrapperCommandMsg *msg) { return; } - DEBUG_ASSERTCRASH(msg->getChunkNumber() < m_numChunks, ("MunkeeChunk %d of %d", - msg->getChunkNumber(), m_numChunks)); - if (msg->getChunkNumber() >= m_numChunks) + UnsignedInt chunkNumber = msg->getChunkNumber(); + + if (chunkNumber >= m_numChunks) { + DEBUG_CRASH(("Data chunk %u exceeds the expected maximum of %u chunks", chunkNumber, m_numChunks)); return; + } - DEBUG_LOG(("NetCommandWrapperListNode::copyChunkData() - copying chunk %d", - msg->getChunkNumber())); + // we already received this chunk, no need to recopy it. + if (m_chunksPresent[chunkNumber] == TRUE) { + return; + } - if (m_chunksPresent[msg->getChunkNumber()] == TRUE) { - // we already received this chunk, no need to recopy it. + UnsignedInt chunkDataOffset = msg->getDataOffset(); + UnsignedInt chunkDataLength = msg->getDataLength(); + + // TheSuperHackers @security Mauller 04/12/2025 Prevent out of bounds memory access + if (chunkDataOffset >= m_totalDataLength) { + DEBUG_CRASH(("Data chunk offset %u exceeds the total data length %u", chunkDataOffset, m_totalDataLength)); return; } - m_chunksPresent[msg->getChunkNumber()] = TRUE; - UnsignedInt offset = msg->getDataOffset(); - memcpy(m_data + offset, msg->getData(), msg->getDataLength()); + if (chunkDataLength > MAX_PACKET_SIZE ) { + DEBUG_CRASH(("Data Chunk size %u greater than max packet size %u", chunkDataLength, MAX_PACKET_SIZE)); + return; + } + + if (chunkDataOffset + chunkDataLength > m_totalDataLength) { + DEBUG_CRASH(("Data chunk exceeds data array size")); + return; + } + + DEBUG_LOG(("NetCommandWrapperListNode::copyChunkData() - copying chunk %u", chunkNumber)); + + memcpy(m_data + chunkDataOffset, msg->getData(), chunkDataLength); + + m_chunksPresent[chunkNumber] = TRUE; ++m_numChunksPresent; }