diff --git a/Core/GameEngine/Include/Common/MapReaderWriterInfo.h b/Core/GameEngine/Include/Common/MapReaderWriterInfo.h index 0d42140ef47..8d9577dcabf 100644 --- a/Core/GameEngine/Include/Common/MapReaderWriterInfo.h +++ b/Core/GameEngine/Include/Common/MapReaderWriterInfo.h @@ -55,6 +55,11 @@ #define K_LIGHTING_VERSION_3 3 // Added 2 additional global lights for terrain. #define K_WORLDDICT_VERSION_1 1 #define K_MAPPREVIEW_VERSION_1 1 + +// TheSuperHackers @bugfix arcticdolphin 12/10/2026 Map size limits. +#define MAX_MAP_DIMENSION 8192 // The shroud texture spans the map and shoreline tiles pack each coordinate into 16 bits +#define MAX_MAP_AREA (4096*4096) // Terrain, pathfinding and partition arrays allocate per cell in a 32 bit process + /** Virtual helper class, so that we can write map data using FILE* or CFile. */ class OutputStream { public: diff --git a/Core/GameEngineDevice/Include/W3DDevice/GameClient/WorldHeightMap.h b/Core/GameEngineDevice/Include/W3DDevice/GameClient/WorldHeightMap.h index 10176bfa1aa..82422316e19 100644 --- a/Core/GameEngineDevice/Include/W3DDevice/GameClient/WorldHeightMap.h +++ b/Core/GameEngineDevice/Include/W3DDevice/GameClient/WorldHeightMap.h @@ -237,6 +237,7 @@ class WorldHeightMap : public RefCountClass, public: // height map info. static Int getMinHeightValue() {return K_MIN_HEIGHT;} static Int getMaxHeightValue() {return K_MAX_HEIGHT;} + static Bool isValidMapSize(Int width, Int height, Int borderSize); ///< Within MAX_MAP_DIMENSION and MAX_MAP_AREA, width and height include the border UnsignedByte *getDataPtr() {return m_data;} diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/WorldHeightMap.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/WorldHeightMap.cpp index c12e28b0db9..8465e2fc29a 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/WorldHeightMap.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/WorldHeightMap.cpp @@ -827,6 +827,24 @@ Bool WorldHeightMap::ParseObjectsDataChunk(DataChunkInput &file, DataChunkInfo * return (file.parse(userData)); } +Bool WorldHeightMap::isValidMapSize(Int width, Int height, Int borderSize) +{ + if (width <= 0 || width > MAX_MAP_DIMENSION) + return false; + if (height <= 0 || height > MAX_MAP_DIMENSION) + return false; + if (width * height > MAX_MAP_AREA) + return false; + if (borderSize < 0 || borderSize > (width - 1) / 2 || borderSize > (height - 1) / 2) + return false; + return true; +} + +static Bool isValidHeightDataSize(DataChunkInput &file, Int dataSize, Int width, Int height) +{ + return dataSize > 0 && dataSize == width * height && (UnsignedInt)dataSize <= file.getChunkDataSizeLeft(); +} + /** * WorldHeightMap::ParseHeightMapData - read a height map chunk. * Format is the newer CHUNKY format. @@ -857,6 +875,10 @@ Bool WorldHeightMap::ParseHeightMapData(DataChunkInput &file, DataChunkInfo *inf m_borderSize = 0; } + if (!isValidMapSize(m_width, m_height, m_borderSize)) { + throw ERROR_CORRUPT_FILE_FORMAT; + } + if (info->version >= K_HEIGHT_MAP_VERSION_4) { Int numBorders = file.readInt(); m_boundaries.resize(numBorders); @@ -871,11 +893,12 @@ Bool WorldHeightMap::ParseHeightMapData(DataChunkInput &file, DataChunkInfo *inf } m_dataSize = file.readInt(); - m_data = MSGNEW("WorldHeightMap_ParseHeightMapData") UnsignedByte[m_dataSize]; - if (m_dataSize <= 0 || (m_dataSize != (m_width*m_height))) { + if (!isValidHeightDataSize(file, m_dataSize, m_width, m_height)) { throw ERROR_CORRUPT_FILE_FORMAT ; } + m_data = MSGNEW("WorldHeightMap_ParseHeightMapData") UnsignedByte[m_dataSize]; + Int numBytesX = (m_width+7)/8; //how many bytes to fit all bitflags Int numBytesY = m_height; m_seismicUpdateWidth=numBytesX; @@ -931,6 +954,10 @@ Bool WorldHeightMap::ParseSizeOnly(DataChunkInput &file, DataChunkInfo *info, vo m_borderSize = 0; } + if (!isValidMapSize(m_width, m_height, m_borderSize)) { + throw ERROR_CORRUPT_FILE_FORMAT; + } + if (info->version >= K_HEIGHT_MAP_VERSION_4) { Int numBorders = file.readInt(); m_boundaries.resize(numBorders); @@ -945,10 +972,11 @@ Bool WorldHeightMap::ParseSizeOnly(DataChunkInput &file, DataChunkInfo *info, vo } m_dataSize = file.readInt(); - m_data = MSGNEW("WorldHeightMap_ParseSizeOnly") UnsignedByte[m_dataSize]; - if (m_dataSize <= 0 || (m_dataSize != (m_width*m_height))) { + if (!isValidHeightDataSize(file, m_dataSize, m_width, m_height)) { throw ERROR_CORRUPT_FILE_FORMAT ; } + + m_data = MSGNEW("WorldHeightMap_ParseSizeOnly") UnsignedByte[m_dataSize]; file.readArrayOfBytes((char *)m_data, m_dataSize); // Resize me. if (info->version == K_HEIGHT_MAP_VERSION_1) {