From a82043eb9d884d31e5fffd243e0f52fcaa09a478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 11 Aug 2026 01:29:24 +0200 Subject: [PATCH] CISOFileBlockDevice: reject frame/block count mismatches numFrames and numBlocks are derived from the same attacker-controlled 64-bit total_bytes field, but independently truncated to 32 bits using different divisors (frameSize vs. the fixed 2048-byte block size). With extreme total_bytes/block_size combinations the two truncations can disagree so that numBlocks (which gates ReadBlock's bounds check) describes more blocks than numFrames actually covers - ReadBlock then indexes the numFrames+1-sized `index` array one or more elements past its end. Reject any header where this could happen before allocating anything. --- Core/FileSystems/BlockDevices.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Core/FileSystems/BlockDevices.cpp b/Core/FileSystems/BlockDevices.cpp index 98e8a41564..b9aaf94c54 100644 --- a/Core/FileSystems/BlockDevices.cpp +++ b/Core/FileSystems/BlockDevices.cpp @@ -556,6 +556,18 @@ CISOFileBlockDevice::CISOFileBlockDevice(FileLoader *fileLoader) numBlocks = (u32)(totalSize / GetBlockSize()); VERBOSE_LOG(Log::Loader, "CSO numBlocks=%i numFrames=%i align=%i", numBlocks, numFrames, indexShift); + // numFrames and numBlocks are independently truncated to 32 bits from the same + // attacker-controlled 64-bit total_bytes, using different divisors (frameSize vs. + // the fixed 2048-byte block size). With extreme total_bytes/block_size values these + // can disagree so that numBlocks describes more blocks than numFrames actually has + // frames for - ReadBlock() would then index the numFrames+1-sized `index` array + // (via frameNumber+1, with frameNumber derived from a blockNumber < numBlocks) out + // of bounds. Reject any header where that could happen. + if ((u64)numBlocks > (u64)numFrames << blockShift) { + errorString_ = "Invalid CSO header (block/frame size mismatch)"; + return; + } + // We might read a bit of alignment too, so be prepared. readBufferSize = frameSize + (1u << indexShift); if (readBufferSize < CSO_READ_BUFFER_SIZE)