From 8164f2b2db6993170aced27d171bdc4e1f2eb5c8 Mon Sep 17 00:00:00 2001 From: Ty Date: Fri, 12 Dec 2025 15:46:36 +0000 Subject: [PATCH] CDVD: Fix an out of bounds read exploit in MG SCMD handlers --- pcsx2/CDVD/CDVD.cpp | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/pcsx2/CDVD/CDVD.cpp b/pcsx2/CDVD/CDVD.cpp index 0c5ff56f02..86952a378d 100644 --- a/pcsx2/CDVD/CDVD.cpp +++ b/pcsx2/CDVD/CDVD.cpp @@ -2942,8 +2942,19 @@ static void cdvdWrite16(u8 rt) // SCOMMAND bit_ofs = mg_BIToffset(&cdvd.mg_buffer[0]); - memcpy(&cdvd.mg_kbit[0], &cdvd.mg_buffer[bit_ofs - 0x20], 0x10); - memcpy(&cdvd.mg_kcon[0], &cdvd.mg_buffer[bit_ofs - 0x10], 0x10); + const size_t buf_size = sizeof(cdvd.mg_buffer); + + if (bit_ofs < 0x20 || (size_t)bit_ofs > buf_size) + { + fail_pol_cal(); + break; + } + + const size_t kbit_ofs = bit_ofs - 0x20; + const size_t kcon_ofs = bit_ofs - 0x10; + + std::memcpy(&cdvd.mg_kbit[0], &cdvd.mg_buffer[kbit_ofs], 0x10); + std::memcpy(&cdvd.mg_kcon[0], &cdvd.mg_buffer[kcon_ofs], 0x10); if ((cdvd.mg_buffer[bit_ofs + 5] || cdvd.mg_buffer[bit_ofs + 6] || cdvd.mg_buffer[bit_ofs + 7]) || (GetBufferU16(&cdvd.mg_buffer[0],bit_ofs + 4) * 16 + bit_ofs + 8 + 16 != GetBufferU16(&cdvd.mg_buffer[0], 0x14))) @@ -2969,7 +2980,31 @@ static void cdvdWrite16(u8 rt) // SCOMMAND { SetSCMDResultSize(3); //in:0 const int bit_ofs = mg_BIToffset(&cdvd.mg_buffer[0]); - memcpy(&cdvd.mg_buffer[0], &cdvd.mg_buffer[bit_ofs], static_cast(8 + 16 * static_cast(cdvd.mg_buffer[bit_ofs + 4]))); + + if (bit_ofs < 0) + { + fail_pol_cal(); + break; + } + + const size_t bufsize = sizeof(cdvd.mg_buffer); + const size_t ofs = static_cast(bit_ofs); + + if (ofs > bufsize - 5) // Make sure we can read the block count + { + fail_pol_cal(); + break; + } + const unsigned int blocks = static_cast(cdvd.mg_buffer[ofs + 4]); + const size_t copy_len = 8 + 16 * static_cast(blocks); + + if (copy_len > bufsize - ofs) // Make sure we can read the blocks + { + fail_pol_cal(); + break; + } + + std::memmove(&cdvd.mg_buffer[0], &cdvd.mg_buffer[ofs], copy_len); cdvd.mg_maxsize = 0; // don't allow any write cdvd.mg_size = 8 + 16 * cdvd.mg_buffer[4]; //new offset, i just moved the data