mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-02-04 12:37:08 +00:00
Loader: Validate offsets and truncation in ELF.
This commit is contained in:
parent
bc9215ca93
commit
4ecdce2a37
@ -34,9 +34,10 @@ const char *ElfReader::GetSectionName(int section) const {
|
||||
if (sections[section].sh_type == SHT_NULL)
|
||||
return nullptr;
|
||||
|
||||
int stringsOffset = GetSectionDataOffset(header->e_shstrndx);
|
||||
int nameOffset = sections[section].sh_name;
|
||||
if (nameOffset < 0 || (size_t)nameOffset >= size_) {
|
||||
ERROR_LOG(LOADER, "ELF: Bad name offset %d in section %d (max = %d)", nameOffset, section, (int)size_);
|
||||
if (nameOffset < 0 || (size_t)nameOffset + stringsOffset >= size_) {
|
||||
ERROR_LOG(LOADER, "ELF: Bad name offset %d + %d in section %d (max = %d)", nameOffset, stringsOffset, section, (int)size_);
|
||||
return nullptr;
|
||||
}
|
||||
const char *ptr = (const char *)GetSectionDataPtr(header->e_shstrndx);
|
||||
@ -235,6 +236,10 @@ void ElfReader::LoadRelocations2(int rel_seg)
|
||||
const Elf32_Phdr *ph = segments + rel_seg;
|
||||
|
||||
buf = (u8*)GetSegmentPtr(rel_seg);
|
||||
if (!buf) {
|
||||
ERROR_LOG(LOADER, "Rel2 segment invalid");
|
||||
return;
|
||||
}
|
||||
end = buf+ph->p_filesz;
|
||||
|
||||
flag_bits = buf[2];
|
||||
@ -383,6 +388,12 @@ int ElfReader::LoadInto(u32 loadAddress, bool fromTop)
|
||||
{
|
||||
DEBUG_LOG(LOADER,"String section: %i", header->e_shstrndx);
|
||||
|
||||
if (size_ < sizeof(Elf32_Ehdr)) {
|
||||
ERROR_LOG(LOADER, "Truncated ELF header, %d bytes", (int)size_);
|
||||
// Probably not the right error code.
|
||||
return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;
|
||||
}
|
||||
|
||||
if (header->e_ident[0] != ELFMAG0 || header->e_ident[1] != ELFMAG1
|
||||
|| header->e_ident[2] != ELFMAG2 || header->e_ident[3] != ELFMAG3)
|
||||
return SCE_KERNEL_ERROR_UNSUPPORTED_PRX_TYPE;
|
||||
@ -399,6 +410,12 @@ int ElfReader::LoadInto(u32 loadAddress, bool fromTop)
|
||||
if (header->e_ident[EI_DATA] != ELFDATA2LSB)
|
||||
return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;
|
||||
|
||||
if (size_ < header->e_phoff + sizeof(Elf32_Phdr) * GetNumSegments() || size_ < header->e_shoff + sizeof(Elf32_Shdr) * GetNumSections()) {
|
||||
ERROR_LOG(LOADER, "Truncated ELF, %d bytes with %d sections and %d segments", (int)size_, GetNumSections(), GetNumSegments());
|
||||
// Probably not the right error code.
|
||||
return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;
|
||||
}
|
||||
|
||||
// e_ident[EI_VERSION] is ignored
|
||||
|
||||
sectionOffsets = new u32[GetNumSections()];
|
||||
@ -412,11 +429,11 @@ int ElfReader::LoadInto(u32 loadAddress, bool fromTop)
|
||||
for (int i = 0; i < GetNumSections(); i++) {
|
||||
const Elf32_Shdr *s = §ions[i];
|
||||
const char *name = GetSectionName(i);
|
||||
if (name && !strcmp(name, ".rodata.sceModuleInfo")) {
|
||||
if (name && !strcmp(name, ".rodata.sceModuleInfo") && s->sh_offset + sizeof(PspModuleInfo) <= size_) {
|
||||
modInfo = (const PspModuleInfo *)GetPtr(s->sh_offset);
|
||||
}
|
||||
}
|
||||
if (!modInfo && GetNumSegments() >= 1) {
|
||||
if (!modInfo && GetNumSegments() >= 1 && (segments[0].p_paddr & 0x7FFFFFFF) + sizeof(PspModuleInfo) <= size_) {
|
||||
modInfo = (const PspModuleInfo *)GetPtr(segments[0].p_paddr & 0x7FFFFFFF);
|
||||
}
|
||||
|
||||
@ -493,6 +510,10 @@ int ElfReader::LoadInto(u32 loadAddress, bool fromTop)
|
||||
u32 writeAddr = segmentVAddr[i];
|
||||
|
||||
const u8 *src = GetSegmentPtr(i);
|
||||
if (!src || p->p_offset + p->p_filesz > size_) {
|
||||
ERROR_LOG(LOADER, "Segment %d pointer invalid - truncated?", i);
|
||||
continue;
|
||||
}
|
||||
u8 *dst = Memory::GetPointerWrite(writeAddr);
|
||||
u32 srcSize = p->p_filesz;
|
||||
u32 dstSize = p->p_memsz;
|
||||
@ -557,9 +578,11 @@ int ElfReader::LoadInto(u32 loadAddress, bool fromTop)
|
||||
int numRelocs = s->sh_size / sizeof(Elf32_Rel);
|
||||
|
||||
Elf32_Rel *rels = (Elf32_Rel *)GetSectionDataPtr(i);
|
||||
if (GetSectionDataOffset(i) + sizeof(Elf32_Rel) * numRelocs > size_)
|
||||
rels = nullptr;
|
||||
|
||||
DEBUG_LOG(LOADER,"%s: Performing %i relocations on %s : offset = %08x", name, numRelocs, GetSectionName(sectionToModify), sections[i].sh_offset);
|
||||
if (!LoadRelocations(rels, numRelocs)) {
|
||||
if (!rels || !LoadRelocations(rels, numRelocs)) {
|
||||
WARN_LOG(LOADER, "LoadInto: Relocs failed, trying anyway");
|
||||
}
|
||||
}
|
||||
@ -607,7 +630,9 @@ int ElfReader::LoadInto(u32 loadAddress, bool fromTop)
|
||||
int numRelocs = p->p_filesz / sizeof(Elf32_Rel);
|
||||
|
||||
Elf32_Rel *rels = (Elf32_Rel *)GetSegmentPtr(i);
|
||||
if (!LoadRelocations(rels, numRelocs)) {
|
||||
if (p->p_offset + p->p_filesz > size_)
|
||||
rels = nullptr;
|
||||
if (!rels || !LoadRelocations(rels, numRelocs)) {
|
||||
ERROR_LOG(LOADER, "LoadInto: Relocs failed, trying anyway (2)");
|
||||
}
|
||||
} else if (p->p_type == PT_PSPREL2) {
|
||||
@ -695,11 +720,17 @@ bool ElfReader::LoadSymbols()
|
||||
int stringSection = sections[sec].sh_link;
|
||||
|
||||
const char *stringBase = (const char*)GetSectionDataPtr(stringSection);
|
||||
u32 stringOffset = GetSectionDataOffset(stringSection);
|
||||
|
||||
//We have a symbol table!
|
||||
Elf32_Sym *symtab = (Elf32_Sym *)(GetSectionDataPtr(sec));
|
||||
u32 symtabOffset = GetSectionDataOffset(sec);
|
||||
|
||||
int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym);
|
||||
if (!stringBase || !symtab || symtabOffset + sections[sec].sh_size > size_) {
|
||||
ERROR_LOG(LOADER, "Symbols truncated - ignoring");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int sym = 0; sym<numSymbols; sym++)
|
||||
{
|
||||
@ -712,6 +743,8 @@ bool ElfReader::LoadSymbols()
|
||||
int sectionIndex = symtab[sym].st_shndx;
|
||||
int value = symtab[sym].st_value;
|
||||
const char *name = stringBase + symtab[sym].st_name;
|
||||
if (stringOffset + symtab[sym].st_name >= size_)
|
||||
continue;
|
||||
|
||||
if (bRelocate)
|
||||
value += sectionAddrs[sectionIndex];
|
||||
|
@ -77,15 +77,23 @@ public:
|
||||
const u8 *GetPtr(u32 offset) const {
|
||||
return (const u8*)base + offset;
|
||||
}
|
||||
const u8 *GetSectionDataPtr(int section) const {
|
||||
// Note: zero is not a valid output, means unavailable.
|
||||
u32 GetSectionDataOffset(int section) const {
|
||||
if (section < 0 || section >= header->e_shnum)
|
||||
return 0;
|
||||
if (sections[section].sh_type == SHT_NOBITS)
|
||||
return 0;
|
||||
return sections[section].sh_offset;
|
||||
}
|
||||
const u8 *GetSectionDataPtr(int section) const {
|
||||
u32 offset = GetSectionDataOffset(section);
|
||||
if (offset == 0 || offset > size_)
|
||||
return nullptr;
|
||||
if (sections[section].sh_type != SHT_NOBITS)
|
||||
return GetPtr(sections[section].sh_offset);
|
||||
else
|
||||
return nullptr;
|
||||
return GetPtr(offset);
|
||||
}
|
||||
const u8 *GetSegmentPtr(int segment) const {
|
||||
if (segments[segment].p_offset > size_)
|
||||
return nullptr;
|
||||
return GetPtr(segments[segment].p_offset);
|
||||
}
|
||||
u32 GetSectionAddr(SectionID section) const {
|
||||
|
Loading…
x
Reference in New Issue
Block a user