Permalink
Browse files

Merge pull request #9783 from hrydgard/elf-safety

Various ELF loading size checks for safety
  • Loading branch information...
hrydgard committed Jun 7, 2017
2 parents b7263b6 + 42bdf3e commit 2cd8bb53d5df84d8e47677a80b6700a849c32b74
Showing with 63 additions and 56 deletions.
  1. +2 −2 Core/ELF/ElfReader.cpp
  2. +25 −28 Core/ELF/ElfReader.h
  3. +36 −26 Core/HLE/sceKernelModule.cpp
View
@@ -29,8 +29,8 @@ const char *ElfReader::GetSectionName(int section) const {
return nullptr;
int nameOffset = sections[section].sh_name;
if (nameOffset < 0) { // TODO: Where can we get a solid upper limit?
ERROR_LOG(LOADER, "ELF: Bad name offset %d in section %d", nameOffset, section);
if (nameOffset < 0 || nameOffset >= size_) {
ERROR_LOG(LOADER, "ELF: Bad name offset %d in section %d (max = %d)", nameOffset, section, (int)size_);
return nullptr;
}
const char *ptr = (const char *)GetSectionDataPtr(header->e_shstrndx);
View
@@ -37,38 +37,32 @@ enum {
R_MIPS_GPREL32
};
enum KnownElfTypes
{
enum KnownElfTypes {
KNOWNELF_PSP = 0,
KNOWNELF_DS = 1,
KNOWNELF_GBA = 2,
};
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 @@ class ElfReader
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 @@ class ElfReader
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;
};
@@ -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;
@@ -1080,12 +1082,15 @@ static Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, bool fromT
}
const u8 *in = ptr;
u32 size = head->elf_size;
if (head->psp_size > size)
{
size = head->psp_size;
// Kind of odd.
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[head->elf_size + head->psp_size];
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);
@@ -1148,10 +1153,11 @@ static Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, bool fromT
module->Cleanup();
kernelObjects.Destroy<Module>(module->GetUID());
error = SCE_KERNEL_ERROR_UNSUPPORTED_PRX_TYPE;
return 0;
return nullptr;
}
// Open ELF reader
ElfReader reader((void*)ptr);
ElfReader reader((void*)ptr, elfSize);
int result = reader.LoadInto(loadAddress, fromTop);
if (result != SCE_KERNEL_ERROR_OK) {
@@ -1161,7 +1167,7 @@ static Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, bool fromT
module->Cleanup();
kernelObjects.Destroy<Module>(module->GetUID());
error = result;
return 0;
return nullptr;
}
module->memoryBlockAddr = reader.GetVaddr();
module->memoryBlockSize = reader.GetTotalSize();
@@ -1442,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) {
@@ -1458,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;
@@ -1585,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) {
@@ -1800,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);
@@ -2246,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) {
@@ -2303,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.

0 comments on commit 2cd8bb5

Please sign in to comment.