diff --git a/Core/ELF/ElfReader.cpp b/Core/ELF/ElfReader.cpp index d85867978c..a4a6bfb856 100644 --- a/Core/ELF/ElfReader.cpp +++ b/Core/ELF/ElfReader.cpp @@ -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 // Should we relocate? @@ -409,11 +426,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); } @@ -490,6 +507,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= size_) + continue; if (bRelocate) value += sectionAddrs[sectionIndex]; diff --git a/Core/ELF/ElfReader.h b/Core/ELF/ElfReader.h index f3ddbfee4b..ff10e5d31a 100644 --- a/Core/ELF/ElfReader.h +++ b/Core/ELF/ElfReader.h @@ -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 {