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.
This commit is contained in:
Henrik Rydgård committed 2026-08-01 13:16:21 +02:00
1 parent 725cd691b3
commit 942a76cfaa
1 file changed
+12 -3
+12 -3
View File
@@ -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>((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;