-
Notifications
You must be signed in to change notification settings - Fork 125
bugfix(network): Prevent out of bounds memory access in NetCommandWrapperListNode::copyChunkData() #1946
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bugfix(network): Prevent out of bounds memory access in NetCommandWrapperListNode::copyChunkData() #1946
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was considering if we might want to also validate the total data length, since we can't allocate MAX_UINT of memory for example in a 32bit application. If there is not a limit considered in the game already, then we should consider something sensible for a single transfer. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Having a transfer size cap does make sense.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess it's a matter of determining what we would consider our max, the game is still not large address aware so limited to 2/2.5GB of RAM at the moment. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 10 MB would be a reasonable limit for starters I think. But better be a separate change.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed, leave it for a followup. |
||
|
|
||
| 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) { | ||
xezon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| 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; | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I altered this for sanity reasons as the original name can get confusing when the data length of the data chunk is also being considered.
I did consider further refactoring the
NetWrapperCommandMsgbut chose to revert those changes for now as they were touchingNetPacketwhich has some waiting PR's to be merged