From 942a76cfaa175331bf4052b4a1895b8ea975f36b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 1 Aug 2026 12:11:21 +0200 Subject: [PATCH] Fix heap overflow via unsigned underflow in legacy Atrac::EnqueueForSas The space-left clamp was computed in unsigned 32-bit arithmetic, so a crafted fileoffset/FirstOffsetExtra could underflow to a huge value and leave addbytes unclamped, driving a Memory::Memcpy past dataBuf_. Compute the clamp in signed 64-bit, clamp negatives to 0, and skip the copy when there's nothing to write. --- Core/HLE/AtracCtx.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Core/HLE/AtracCtx.cpp b/Core/HLE/AtracCtx.cpp index 1906b80708..5c274d7fb7 100644 --- a/Core/HLE/AtracCtx.cpp +++ b/Core/HLE/AtracCtx.cpp @@ -960,15 +960,24 @@ void Atrac::CheckForSas() { } int Atrac::EnqueueForSas(u32 bufPtr, u32 bytesToAdd) { - int addbytes = std::min(bytesToAdd, track_.fileSize - first_.fileoffset - track_.FirstOffsetExtra()); - Memory::Memcpy(dataBuf_ + first_.fileoffset + track_.FirstOffsetExtra(), bufPtr, addbytes, "AtracAddStreamData"); + // Compute in signed 64-bit so an attacker-controlled fileoffset / + // FirstOffsetExtra can't underflow the space-left clamp and leave + // addbytes unclamped. + const s64 destOffset = (s64)first_.fileoffset + track_.FirstOffsetExtra(); + const s64 spaceLeft = (s64)track_.fileSize - destOffset; + s64 addbytes = std::min((s64)bytesToAdd, spaceLeft); + if (addbytes < 0) + addbytes = 0; + if (addbytes > 0) { + Memory::Memcpy(dataBuf_ + destOffset, bufPtr, (size_t)addbytes, "AtracAddStreamData"); + } first_.size += bytesToAdd; if (first_.size >= track_.fileSize) { first_.size = track_.fileSize; if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED; } - first_.fileoffset += addbytes; + first_.fileoffset += (u32)addbytes; // refresh context_ WriteContextToPSPMem(); return 0;