GBA: Verify ELF entrypoint against ROM header (#2714)

This commit is contained in:
Luna Mittelbach 2022-11-05 09:44:29 +01:00 committed by GitHub
parent b8c7196dd9
commit 694b80d289
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 68 additions and 4 deletions

View File

@ -12,6 +12,7 @@ Other fixes:
- VFS: Fix minizip write returning 0 on success instead of size
Misc:
- GB Serialize: Add missing savestate support for MBC6 and NT (newer)
- GBA: Improve detection of valid ELF ROMs
- macOS: Add category to plist (closes mgba.io/i/2691)
- macOS: Fix modern build with libepoxy (fixes mgba.io/i/2700)
- Qt: Keep track of current pslette preset name (fixes mgba.io/i/2680)

View File

@ -154,6 +154,12 @@ void GBAHalt(struct GBA* gba);
void GBAStop(struct GBA* gba);
void GBADebug(struct GBA* gba, uint16_t value);
#ifdef USE_ELF
struct ELF;
bool GBAVerifyELFEntry(struct ELF* elf, uint32_t target);
#endif
#ifdef USE_DEBUGGERS
struct mDebugger;
void GBAAttachDebugger(struct GBA* gba, struct mDebugger* debugger);

View File

@ -237,7 +237,7 @@ static bool _GBACoreInit(struct mCore* core) {
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
mDirectorySetInit(&core->dirs);
#endif
return true;
}
@ -512,7 +512,7 @@ static bool _GBACoreLoadROM(struct mCore* core, struct VFile* vf) {
#ifdef USE_ELF
struct ELF* elf = ELFOpen(vf);
if (elf) {
if (ELFEntry(elf) == BASE_CART0) {
if (GBAVerifyELFEntry(elf, BASE_CART0)) {
GBALoadNull(core->board);
}
bool success = mCoreLoadELF(core, elf);

View File

@ -595,6 +595,63 @@ void GBADebug(struct GBA* gba, uint16_t flags) {
gba->debugFlags = GBADebugFlagsClearSend(gba->debugFlags);
}
#ifdef USE_ELF
bool GBAVerifyELFEntry(struct ELF* elf, uint32_t target) {
if (ELFEntry(elf) == target) {
return true;
}
struct ELFProgramHeaders ph;
ELFProgramHeadersInit(&ph, 0);
ELFGetProgramHeaders(elf, &ph);
size_t i;
for (i = 0; i < ELFProgramHeadersSize(&ph); ++i) {
Elf32_Phdr* phdr = ELFProgramHeadersGetPointer(&ph, i);
if (!phdr->p_filesz) {
continue;
}
size_t phdrS = phdr->p_paddr;
size_t phdrE = phdrS + phdr->p_filesz;
// Does the segment contain our target address?
if (target < phdrS || target + 4 > phdrE) {
continue;
}
// File offset to what should be the rom entry instruction
size_t off = phdr->p_offset + target - phdrS;
size_t eSize;
const char* bytes = ELFBytes(elf, &eSize);
// Bounds and alignment check
if (off >= eSize || off & 3) {
continue;
}
uint32_t opcode;
LOAD_32(opcode, off, bytes);
struct ARMInstructionInfo info;
ARMDecodeARM(opcode, &info);
if (info.branchType != ARM_BRANCH && info.branchType != ARM_BRANCH_LINKED) {
continue;
}
uint32_t bTarget = target + info.op1.immediate + 8;
if (ELFEntry(elf) == bTarget) {
ELFProgramHeadersDeinit(&ph);
return true;
}
}
ELFProgramHeadersDeinit(&ph);
return false;
}
#endif
bool GBAIsROM(struct VFile* vf) {
if (!vf) {
return false;
@ -606,7 +663,7 @@ bool GBAIsROM(struct VFile* vf) {
uint32_t entry = ELFEntry(elf);
bool isGBA = true;
isGBA = isGBA && ELFMachine(elf) == EM_ARM;
isGBA = isGBA && (entry == BASE_CART0 || entry == BASE_WORKING_RAM + 0xC0);
isGBA = isGBA && (GBAVerifyELFEntry(elf, BASE_CART0) || GBAVerifyELFEntry(elf, BASE_WORKING_RAM + 0xC0));
ELFClose(elf);
return isGBA;
}
@ -662,7 +719,7 @@ bool GBAIsMB(struct VFile* vf) {
#ifdef USE_ELF
struct ELF* elf = ELFOpen(vf);
if (elf) {
bool isMB = ELFEntry(elf) == BASE_WORKING_RAM + 0xC0;
bool isMB = GBAVerifyELFEntry(elf, BASE_WORKING_RAM + 0xC0);
ELFClose(elf);
return isMB;
}