mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-06-02 12:45:14 -06:00
RawSPU: bound ELF loads; PPUInterpreter: fix modulo 127->128 (#18797)
Two small fixes that stop the emulator from writing past buffer boundaries. RawSPU: when loading a program onto an SPU processor, it now checks that the program actually fits in 256 KB before copying it. Before this, a corrupted file could write past the buffer into random host memory. PPUInterpreter: a one-character typo fix. A modulo operation used % 127 instead of % 128 when computing cross-boundary data sizes. This caused reservation checks to compare the wrong number of bytes on every load that crossed a cache line. This fix was pointed out by @AniLeo in the spam PR #18795 (Discovered by Opus 4.7) The PS3 hardware enforces these limits: - Each SPU has exactly 256 KB of memory (from Cell Broadband Engine Handbook v1.1) - The PPE cache line is 128 bytes — all reservation logic uses this granularity Neither fix should affect the usual games. They only applying to corrupted or malformed files. Will highly appreciate feedback and suggestions for this PR Tested on CI: CI passes on my fork 9 of 10 platforms (Mac Intel failed downloading a dependency). Title and Desc written by Codex
This commit is contained in:
parent
a87d175295
commit
b41b10a031
@ -501,7 +501,7 @@ auto ppu_feed_data(ppu_thread& ppu, u64 addr)
|
|||||||
if (raddr / 128 == addr / 128)
|
if (raddr / 128 == addr / 128)
|
||||||
src = &ppu.rdata[addr & 127], size = std::min<u32>(128 - (addr % 128), sizeof(T));
|
src = &ppu.rdata[addr & 127], size = std::min<u32>(128 - (addr % 128), sizeof(T));
|
||||||
else
|
else
|
||||||
src = &ppu.rdata[0], size = (addr + u32{sizeof(T)}) % 127, offs = sizeof(T) - size;
|
src = &ppu.rdata[0], size = (addr + u32{sizeof(T)}) % 128, offs = sizeof(T) - size;
|
||||||
|
|
||||||
if (std::memcmp(buffer + offs, src, size))
|
if (std::memcmp(buffer + offs, src, size))
|
||||||
{
|
{
|
||||||
|
|||||||
@ -427,6 +427,12 @@ void spu_load_exec(const spu_exec_object& elf)
|
|||||||
{
|
{
|
||||||
if (prog.p_type == 0x1u /* LOAD */ && prog.p_memsz)
|
if (prog.p_type == 0x1u /* LOAD */ && prog.p_memsz)
|
||||||
{
|
{
|
||||||
|
if (prog.p_vaddr >= SPU_LS_SIZE || prog.p_filesz > SPU_LS_SIZE - prog.p_vaddr)
|
||||||
|
{
|
||||||
|
spu_log.error("spu_load_exec: skipping segment with vaddr=0x%x filesz=0x%x (exceeds LS=0x%x)", prog.p_vaddr, prog.p_filesz, static_cast<u32>(SPU_LS_SIZE));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
std::memcpy(spu->_ptr<void>(prog.p_vaddr), prog.bin.data(), prog.p_filesz);
|
std::memcpy(spu->_ptr<void>(prog.p_vaddr), prog.bin.data(), prog.p_filesz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -496,6 +502,12 @@ void spu_load_rel_exec(const spu_rel_object& elf)
|
|||||||
{
|
{
|
||||||
if (shdr.sh_type == sec_type::sht_progbits && shdr.sh_flags().all_of(sh_flag::shf_alloc))
|
if (shdr.sh_type == sec_type::sht_progbits && shdr.sh_flags().all_of(sh_flag::shf_alloc))
|
||||||
{
|
{
|
||||||
|
if (offs >= SPU_LS_SIZE || shdr.sh_size > SPU_LS_SIZE - offs)
|
||||||
|
{
|
||||||
|
spu_log.error("spu_load_rel_exec: skipping section at offs=0x%x sh_size=0x%x (exceeds LS=0x%x)", offs, shdr.sh_size, static_cast<u32>(SPU_LS_SIZE));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
std::memcpy(spu->_ptr<void>(offs), shdr.get_bin().data(), shdr.sh_size);
|
std::memcpy(spu->_ptr<void>(offs), shdr.get_bin().data(), shdr.sh_size);
|
||||||
offs = utils::align<u32>(offs + shdr.sh_size, 4);
|
offs = utils::align<u32>(offs + shdr.sh_size, 4);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user