mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
ELF: bound the segment table, and reject ELFs with no loadable segment
segmentVAddr is a 32-entry array, but LoadInto filled it from e_phnum, which is a u16 - so an ELF declaring 65535 program headers wrote 65535 u32s into it, straight through the rest of the ElfReader object. The only check standing in front of that verified the program headers fit in the file, which a ~2MB crafted PRX satisfies. Rejected up front now: LoadRelocations already ignores segment numbers at or past the array size, so a module with more than that couldn't be relocated correctly anyway. Real modules have a handful - PSP_Header::nsegments is a u8 and no more than 4 are ever used. Second one from the same loop: with no PT_LOAD segment at all, totalStart stayed 0xFFFFFFFF and totalEnd 0, so totalSize came out as 1 (0 - 0xFFFFFFFF) and the loader went on to allocate a 1-byte block at 0xFFFFFFFF. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
This commit is contained in:
1 parent
b00e239e41
commit
7e79334c18
1 file changed
+16
@@ -438,6 +438,14 @@ int ElfReader::LoadInto(u32 loadAddress, bool fromTop) {
|
||||
return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;
|
||||
}
|
||||
|
||||
// e_phnum is a u16, but we can only record the load address of ARRAY_SIZE(segmentVAddr) segments,
|
||||
// and the relocation code can't refer to segments beyond that either (see LoadRelocations). Real
|
||||
// PSP modules have a handful - PSP_Header::nsegments is a u8 and no more than 4 are ever used.
|
||||
if (GetNumSegments() > (int)ARRAY_SIZE(segmentVAddr)) {
|
||||
ERROR_LOG(Log::Loader, "ELF has %d segments, we support at most %d", GetNumSegments(), (int)ARRAY_SIZE(segmentVAddr));
|
||||
return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;
|
||||
}
|
||||
|
||||
// e_ident[EI_VERSION] is ignored
|
||||
|
||||
// Should we relocate?
|
||||
@@ -467,9 +475,11 @@ int ElfReader::LoadInto(u32 loadAddress, bool fromTop) {
|
||||
entryPoint = header->e_entry;
|
||||
u32 totalStart = 0xFFFFFFFF;
|
||||
u32 totalEnd = 0;
|
||||
int numLoadSegments = 0;
|
||||
for (int i = 0; i < header->e_phnum; i++) {
|
||||
const Elf32_Phdr *p = &segments[i];
|
||||
if (p->p_type == PT_LOAD) {
|
||||
numLoadSegments++;
|
||||
if (p->p_vaddr < totalStart) {
|
||||
totalStart = p->p_vaddr;
|
||||
firstSegAlign = p->p_align;
|
||||
@@ -478,6 +488,12 @@ int ElfReader::LoadInto(u32 loadAddress, bool fromTop) {
|
||||
totalEnd = p->p_vaddr + p->p_memsz;
|
||||
}
|
||||
}
|
||||
// Without this, totalStart stays 0xFFFFFFFF and totalEnd 0, so totalSize would come out as 1
|
||||
// and we'd go on to allocate at 0xFFFFFFFF.
|
||||
if (numLoadSegments == 0) {
|
||||
ERROR_LOG(Log::Loader, "ELF has no loadable segments");
|
||||
return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;
|
||||
}
|
||||
totalSize = totalEnd - totalStart;
|
||||
|
||||
// If a load address is specified that's in regular RAM, override kernel module status
|
||||
|
||||
Reference in new issue
Block a user