From 32abdd63bfa3aef1669c76a177b72fa537af3d23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 1 Aug 2026 11:28:11 +0200 Subject: [PATCH] Fix EP-map parsing OOB read in PSMF video stream params EP_MAP_STRIDE * EPMapEntriesNum was computed in 32-bit and could wrap, passing the range check while the loop read the unwrapped count; and the check was skipped entirely when headerOffset == 0 (the player tempbuf path). - Use 64-bit math for the EP map size. - Keep the guest-RAM range check when headerOffset != 0. - Cap the entry count for the headerOffset == 0 path so the reads stay within the player's 64KB tempbuf. --- Core/HLE/scePsmf.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/Core/HLE/scePsmf.cpp b/Core/HLE/scePsmf.cpp index a8f3bf48b6..fcb57013b9 100644 --- a/Core/HLE/scePsmf.cpp +++ b/Core/HLE/scePsmf.cpp @@ -290,9 +290,21 @@ public: videoHeight_ = addr[13] * 16; const u32 EP_MAP_STRIDE = 1 + 1 + 4 + 4; - if (psmf->headerOffset != 0 && !Memory::IsValidRange(psmf->headerOffset, psmf->EPMapOffset + EP_MAP_STRIDE * psmf->EPMapEntriesNum)) { - ERROR_LOG(Log::ME, "Invalid PSMF EP map entry count: %d", psmf->EPMapEntriesNum); - psmf->EPMapEntriesNum = Memory::ClampValidSizeAt(psmf->headerOffset + psmf->EPMapOffset, EP_MAP_STRIDE * psmf->EPMapEntriesNum) / EP_MAP_STRIDE; + // Compute in 64-bit so EP_MAP_STRIDE * EPMapEntriesNum can't overflow + // and pass a wrapped range check while the loop below still iterates + // the unwrapped count. + const u64 epMapBytes = EP_MAP_STRIDE * (u64)psmf->EPMapEntriesNum; + if (psmf->headerOffset != 0) { + if (epMapBytes > 0xFFFFFFFFull - psmf->EPMapOffset || !Memory::IsValidRange(psmf->headerOffset, psmf->EPMapOffset + (u32)epMapBytes)) { + ERROR_LOG(Log::ME, "Invalid PSMF EP map entry count: %d", psmf->EPMapEntriesNum); + psmf->EPMapEntriesNum = Memory::ClampValidSizeAt(psmf->headerOffset + psmf->EPMapOffset, (u32)epMapBytes) / EP_MAP_STRIDE; + } + } else { + // No guest address to validate against (player tempbuf path, + // where the buffer is 64KB): cap so the reads below stay in bounds. + if (epMapBytes > 0x10000) { + psmf->EPMapEntriesNum = 0x10000 / EP_MAP_STRIDE; + } } psmf->EPMap.clear();