From b1b3b7c9d785688458e85ed13a6385355ad1bd22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 6 Jun 2017 23:41:23 +0200 Subject: [PATCH] Refuse to load truncated ~PSP files. --- Core/ELF/ElfReader.h | 53 ++++++++++++++++------------------ Core/HLE/sceKernelModule.cpp | 55 ++++++++++++++++++++++-------------- 2 files changed, 59 insertions(+), 49 deletions(-) diff --git a/Core/ELF/ElfReader.h b/Core/ELF/ElfReader.h index 5895a4a6c3..78680c0f42 100644 --- a/Core/ELF/ElfReader.h +++ b/Core/ELF/ElfReader.h @@ -37,8 +37,7 @@ enum { R_MIPS_GPREL32 }; -enum KnownElfTypes -{ +enum KnownElfTypes { KNOWNELF_PSP = 0, KNOWNELF_DS = 1, KNOWNELF_GBA = 2, @@ -46,29 +45,24 @@ enum KnownElfTypes typedef int SectionID; -class ElfReader -{ +class ElfReader { public: - ElfReader(const void *ptr) : - sectionOffsets(0), - sectionAddrs(0), - bRelocate(false), - entryPoint(0), - vaddr(0) { + ElfReader(const void *ptr, size_t size) { base = (const char*)ptr; base32 = (const u32 *)ptr; header = (const Elf32_Ehdr*)ptr; segments = (const Elf32_Phdr *)(base + header->e_phoff); sections = (const Elf32_Shdr *)(base + header->e_shoff); + size_ = size; } ~ElfReader() { - delete [] sectionOffsets; - delete [] sectionAddrs; + delete[] sectionOffsets; + delete[] sectionAddrs; } - u32 Read32(int off) { - return base32[off>>2]; + u32 Read32(int off) const { + return base32[off >> 2]; } // Quick accessors @@ -100,13 +94,15 @@ public: int GetSectionSize(SectionID section) const { return sections[section].sh_size; } - SectionID GetSectionByName(const char *name, int firstSection=0) const; //-1 for not found + + //-1 for not found + SectionID GetSectionByName(const char *name, int firstSection = 0) const; u32 GetSegmentPaddr(int segment) const { - return segments[segment].p_paddr; + return segments[segment].p_paddr; } u32 GetSegmentOffset(int segment) const { - return segments[segment].p_offset; + return segments[segment].p_offset; } u32 GetSegmentVaddr(int segment) const { return segmentVAddr[segment]; @@ -140,16 +136,17 @@ public: void LoadRelocations2(int rel_seg); private: - const char *base; - const u32 *base32; - const Elf32_Ehdr *header; - const Elf32_Phdr *segments; - const Elf32_Shdr *sections; - u32 *sectionOffsets; - u32 *sectionAddrs; - bool bRelocate; - u32 entryPoint; - u32 totalSize; - u32 vaddr; + const char *base = nullptr; + const u32 *base32 = nullptr; + const Elf32_Ehdr *header = nullptr; + const Elf32_Phdr *segments = nullptr; + const Elf32_Shdr *sections = nullptr; + u32 *sectionOffsets = nullptr; + u32 *sectionAddrs = nullptr; + bool bRelocate = false; + u32 entryPoint = 0; + u32 totalSize = 0; + u32 vaddr = 0; u32 segmentVAddr[32]; + size_t size_ = 0; }; diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 37d90b3b6a..4431ad1a7a 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -1043,7 +1043,7 @@ static bool KernelImportModuleFuncs(Module *module, u32 *firstImportStubAddr, bo return true; } -static Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, bool fromTop, std::string *error_string, u32 *magic, u32 &error) { +static Module *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 loadAddress, bool fromTop, std::string *error_string, u32 *magic, u32 &error) { Module *module = new Module; kernelObjects.Create(module); loadedModules.insert(module->GetUID()); @@ -1055,7 +1055,9 @@ static Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, bool fromT u32_le *magicPtr = (u32_le *) ptr; if (*magicPtr == 0x4543537e) { // "~SCE" INFO_LOG(SCEMODULE, "~SCE module, skipping header"); - ptr += *(u32_le*)(ptr + 4); + u32 headerSize = *(u32_le*)(ptr + 4); + ptr += headerSize; + elfSize -= headerSize; magicPtr = (u32_le *)ptr; } *magic = *magicPtr; @@ -1081,8 +1083,14 @@ static Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, bool fromT const u8 *in = ptr; // Kind of odd. - u32 size = std::max(head->elf_size, head->psp_size); - newptr = new u8[size]; + u32 size = head->psp_size; + if (size > elfSize) { + *error_string = StringFromFormat("ELF/PRX truncated: %d > %d", (int)size, (int)elfSize); + module->Cleanup(); + kernelObjects.Destroy(module->GetUID()); + return nullptr; + } + newptr = new u8[std::max(head->elf_size, head->psp_size)]; ptr = newptr; magicPtr = (u32_le *)ptr; int ret = pspDecryptPRX(in, (u8*)ptr, head->psp_size); @@ -1147,8 +1155,9 @@ static Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, bool fromT error = SCE_KERNEL_ERROR_UNSUPPORTED_PRX_TYPE; return 0; } + // Open ELF reader - ElfReader reader((void*)ptr); + ElfReader reader((void*)ptr, elfSize); int result = reader.LoadInto(loadAddress, fromTop); if (result != SCE_KERNEL_ERROR_OK) { @@ -1439,8 +1448,7 @@ static Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, bool fromT return module; } -static Module *__KernelLoadModule(u8 *fileptr, SceKernelLMOption *options, std::string *error_string) -{ +static Module *__KernelLoadModule(u8 *fileptr, size_t fileSize, SceKernelLMOption *options, std::string *error_string) { Module *module = 0; // Check for PBP if (memcmp(fileptr, "\0PBP", 4) == 0) { @@ -1455,28 +1463,33 @@ static Module *__KernelLoadModule(u8 *fileptr, SceKernelLMOption *options, std:: for (int i = 1; i < numfiles; i++) memcpy(&offsets[i], fileptr + 12 + 4*i, 4); + if (offsets[6] > fileSize) { + // File is too small to fully contain the ELF! Must have been truncated. + *error_string = "ELF file truncated - can't load"; + return nullptr; + } + u32 magic = 0; - u8 *temp = 0; + u8 *temp = nullptr; + size_t elfSize = offsets[6] - offsets[5]; if (offsets[5] & 3) { - // Our loader does NOT like to load from an unaligned address on ARM! - size_t size = offsets[6] - offsets[5]; - temp = new u8[size]; - memcpy(temp, fileptr + offsets[5], size); + // Our loader does NOT like to load from an unaligned address on ARM! Copy to a new block. + temp = new u8[elfSize]; + + memcpy(temp, fileptr + offsets[5], elfSize); INFO_LOG(LOADER, "PBP: ELF unaligned (%d: %d), aligning!", offsets[5], offsets[5] & 3); } u32 error; - module = __KernelLoadELFFromPtr(temp ? temp : fileptr + offsets[5], PSP_GetDefaultLoadAddress(), false, error_string, &magic, error); + module = __KernelLoadELFFromPtr(temp ? temp : fileptr + offsets[5], elfSize, PSP_GetDefaultLoadAddress(), false, error_string, &magic, error); if (temp) { delete [] temp; } - } - else - { + } else { u32 error; u32 magic = 0; - module = __KernelLoadELFFromPtr(fileptr, PSP_GetDefaultLoadAddress(), false, error_string, &magic, error); + module = __KernelLoadELFFromPtr(fileptr, fileSize, PSP_GetDefaultLoadAddress(), false, error_string, &magic, error); } return module; @@ -1582,7 +1595,7 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str pspFileSystem.ReadFile(handle, temp, (size_t)info.size); - Module *module = __KernelLoadModule(temp, 0, error_string); + Module *module = __KernelLoadModule(temp, (size_t)info.size, 0, error_string); if (!module || module->isFake) { if (module) { @@ -1797,7 +1810,7 @@ u32 sceKernelLoadModule(const char *name, u32 flags, u32 optionAddr) { u32 magic; u32 error; std::string error_string; - module = __KernelLoadELFFromPtr(temp, 0, lmoption ? lmoption->position == 1 : false, &error_string, &magic, error); + module = __KernelLoadELFFromPtr(temp, (size_t)size, 0, lmoption ? lmoption->position == 1 : false, &error_string, &magic, error); delete [] temp; pspFileSystem.CloseFile(handle); @@ -2243,7 +2256,7 @@ static u32 sceKernelLoadModuleByID(u32 id, u32 flags, u32 lmoptionPtr) u8 *temp = new u8[size - pos]; pspFileSystem.ReadFile(handle, temp, size - pos); u32 magic; - module = __KernelLoadELFFromPtr(temp, 0, lmoption ? lmoption->position == 1 : false, &error_string, &magic, error); + module = __KernelLoadELFFromPtr(temp, size - pos, 0, lmoption ? lmoption->position == 1 : false, &error_string, &magic, error); delete [] temp; if (!module) { @@ -2300,7 +2313,7 @@ static SceUID sceKernelLoadModuleBufferUsbWlan(u32 size, u32 bufPtr, u32 flags, Module *module = 0; u32 magic; u32 error; - module = __KernelLoadELFFromPtr(Memory::GetPointer(bufPtr), 0, lmoption ? lmoption->position == 1 : false, &error_string, &magic, error); + module = __KernelLoadELFFromPtr(Memory::GetPointer(bufPtr), size, 0, lmoption ? lmoption->position == 1 : false, &error_string, &magic, error); if (!module) { // Some games try to load strange stuff as PARAM.SFO as modules and expect it to fail.