Refuse to load truncated ~PSP files.

This commit is contained in:
Henrik Rydgård 2017-06-06 23:41:23 +02:00
parent 57a20f02ed
commit b1b3b7c9d7
2 changed files with 59 additions and 49 deletions

View File

@ -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;
};

View File

@ -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>(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.