From 6ea6ca4ac2beddf02fcb9ff085c920f2e8226d50 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 31 Mar 2026 08:47:34 +0000 Subject: [PATCH] fix: prevent overflow/OOM in Raw chunk parsing and fix global scene ID in BuildSceneGraph Agent-Logs-Url: https://github.com/DarkflameUniverse/DarkflameServer/sessions/5cf247c9-7028-4f94-9ab9-8dfd8e6101fa Co-authored-by: aronwk-aaron <26027722+aronwk-aaron@users.noreply.github.com> --- dZoneManager/Raw.cpp | 49 +++++++++++++++++++++++++++++------ dZoneManager/dZoneManager.cpp | 2 +- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/dZoneManager/Raw.cpp b/dZoneManager/Raw.cpp index f74b2c6a..b9f2ae01 100644 --- a/dZoneManager/Raw.cpp +++ b/dZoneManager/Raw.cpp @@ -6,6 +6,11 @@ #include #include +namespace { +constexpr uint32_t kMaxResolution = 4096; +constexpr size_t kMaxBlobBytes = 64ULL * 1024 * 1024; // 64 MiB +} // namespace + namespace Raw { /** @@ -106,9 +111,17 @@ namespace Raw { chunk.colorMapResolution = chunk.width; // Default to chunk width for older versions } - uint32_t colorMapPixelCount = chunk.colorMapResolution * chunk.colorMapResolution * 4; // RGBA + if (chunk.colorMapResolution > kMaxResolution) { + LOG("Chunk colorMapResolution %u exceeds maximum %u", chunk.colorMapResolution, kMaxResolution); + return false; + } + const size_t colorMapPixelCount = static_cast(chunk.colorMapResolution) * chunk.colorMapResolution * 4; // RGBA + if (colorMapPixelCount > kMaxBlobBytes) { + LOG("Chunk colorMap size %zu exceeds maximum %zu bytes", colorMapPixelCount, kMaxBlobBytes); + return false; + } chunk.colorMap.resize(colorMapPixelCount); - stream.read(reinterpret_cast(chunk.colorMap.data()), colorMapPixelCount); + stream.read(reinterpret_cast(chunk.colorMap.data()), static_cast(colorMapPixelCount)); if (stream.fail()) { return false; @@ -117,8 +130,12 @@ namespace Raw { uint32_t lightMapSize; BinaryIO::BinaryRead(stream, lightMapSize); + if (lightMapSize > kMaxBlobBytes) { + LOG("Chunk lightMap size %u exceeds maximum %zu bytes", lightMapSize, kMaxBlobBytes); + return false; + } chunk.lightMap.resize(lightMapSize); - stream.read(reinterpret_cast(chunk.lightMap.data()), lightMapSize); + stream.read(reinterpret_cast(chunk.lightMap.data()), static_cast(lightMapSize)); if (stream.fail()) { return false; @@ -131,9 +148,17 @@ namespace Raw { chunk.textureMapResolution = chunk.width; // Default to chunk width for older versions } - uint32_t textureMapPixelCount = chunk.textureMapResolution * chunk.textureMapResolution * 4; + if (chunk.textureMapResolution > kMaxResolution) { + LOG("Chunk textureMapResolution %u exceeds maximum %u", chunk.textureMapResolution, kMaxResolution); + return false; + } + const size_t textureMapPixelCount = static_cast(chunk.textureMapResolution) * chunk.textureMapResolution * 4; + if (textureMapPixelCount > kMaxBlobBytes) { + LOG("Chunk textureMap size %zu exceeds maximum %zu bytes", textureMapPixelCount, kMaxBlobBytes); + return false; + } chunk.textureMap.resize(textureMapPixelCount); - stream.read(reinterpret_cast(chunk.textureMap.data()), textureMapPixelCount); + stream.read(reinterpret_cast(chunk.textureMap.data()), static_cast(textureMapPixelCount)); if (stream.fail()) { return false; @@ -146,8 +171,12 @@ namespace Raw { uint32_t blendMapDDSSize; BinaryIO::BinaryRead(stream, blendMapDDSSize); + if (blendMapDDSSize > kMaxBlobBytes) { + LOG("Chunk blendMap size %u exceeds maximum %zu bytes", blendMapDDSSize, kMaxBlobBytes); + return false; + } chunk.blendMap.resize(blendMapDDSSize); - stream.read(reinterpret_cast(chunk.blendMap.data()), blendMapDDSSize); + stream.read(reinterpret_cast(chunk.blendMap.data()), static_cast(blendMapDDSSize)); if (stream.fail()) { return false; @@ -170,10 +199,14 @@ namespace Raw { // Scene map (version 32+ only) if (version >= 32) { - uint32_t sceneMapSize = chunk.colorMapResolution * chunk.colorMapResolution; + const size_t sceneMapSize = static_cast(chunk.colorMapResolution) * chunk.colorMapResolution; + if (sceneMapSize > kMaxBlobBytes) { + LOG("Chunk sceneMap size %zu exceeds maximum %zu bytes", sceneMapSize, kMaxBlobBytes); + return false; + } chunk.sceneMap.resize(sceneMapSize); - stream.read(reinterpret_cast(chunk.sceneMap.data()), sceneMapSize); + stream.read(reinterpret_cast(chunk.sceneMap.data()), static_cast(sceneMapSize)); if (stream.fail()) { return false; diff --git a/dZoneManager/dZoneManager.cpp b/dZoneManager/dZoneManager.cpp index f4df5ccb..54905de2 100644 --- a/dZoneManager/dZoneManager.cpp +++ b/dZoneManager/dZoneManager.cpp @@ -406,7 +406,7 @@ void dZoneManager::BuildSceneGraph() { } // Scene 0 (global scene) is always loaded and adjacent to all other scenes - LWOSCENEID globalScene = LWOSCENEID(m_ZoneID.GetMapID(), 0); + LWOSCENEID globalScene = LWOSCENEID(0, 0); for (auto& [sceneID, adjacentScenes] : m_SceneAdjacencyList) { if (sceneID != globalScene) { // Add global scene to this scene's adjacency list if not already present