A crafted UPS patch file can write beyond the bounds of Memory.ROM because the relative offset used during patch application is never validated against the output ROM size.
In memmap.cpp:3644-3652, the patch application loop accumulates a relative offset from values decoded from the patch data, then uses it to XOR bytes directly into Memory.ROM:
uint32 relative = 0;
while(addr < size - 12) {
relative += XPSdecode(data, addr, size);
while(addr < size - 12) {
uint8 x = data[addr++];
Memory.ROM[relative++] ^= x; // <-- no bounds check
if(!x) break;
}
}
While the function checks that out_size <= CMemory::MAX_ROM_SIZE at line 3636, it never validates that relative stays within out_size (or MAX_ROM_SIZE) during the XOR loop. A malicious UPS file can encode arbitrarily large offset values via XPSdecode, causing relative to exceed the allocated buffer and write out of bounds.
An attacker-crafted .ups file can trigger a heap-based out-of-bounds write on Memory.ROM, potentially leading to code execution or a crash. UPS patches are loaded by default when opening a ROM. The patching logic in memmap.cpp:3942 automatically searches for a .ups file matching the ROM filename and applies it without prompting the user. This means simply placing a malicious .ups file alongside a ROM (e.g., in a downloaded ROM pack or shared directory) is sufficient to trigger the vulnerability.
Reproduction: Create a UPS file with a valid UPS1 header and matching patch CRC32, but encode offset values in the patch body that cause the relative offset to exceed MAX_ROM_SIZE. I have also attached a ROM and patch file which will trigger a crash on 32 and 64 bit Windows builds of SNES9x.
Fix: Add a bounds check before the XOR write:
if (relative >= CMemory::MAX_ROM_SIZE) break;
Memory.ROM[relative++] ^= x;
A crafted UPS patch file can write beyond the bounds of
Memory.ROMbecause the relative offset used during patch application is never validated against the output ROM size.In memmap.cpp:3644-3652, the patch application loop accumulates a relative offset from values decoded from the patch data, then uses it to XOR bytes directly into
Memory.ROM:While the function checks that
out_size<=CMemory::MAX_ROM_SIZEat line 3636, it never validates that relative stays withinout_size(orMAX_ROM_SIZE) during the XOR loop. A malicious UPS file can encode arbitrarily large offset values via XPSdecode, causing relative to exceed the allocated buffer and write out of bounds.An attacker-crafted .ups file can trigger a heap-based out-of-bounds write on
Memory.ROM, potentially leading to code execution or a crash. UPS patches are loaded by default when opening a ROM. The patching logic in memmap.cpp:3942 automatically searches for a .ups file matching the ROM filename and applies it without prompting the user. This means simply placing a malicious .ups file alongside a ROM (e.g., in a downloaded ROM pack or shared directory) is sufficient to trigger the vulnerability.Reproduction: Create a UPS file with a valid UPS1 header and matching patch CRC32, but encode offset values in the patch body that cause the relative offset to exceed MAX_ROM_SIZE. I have also attached a ROM and patch file which will trigger a crash on 32 and 64 bit Windows builds of SNES9x.
Fix: Add a bounds check before the XOR write: