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 - VFS: Fix minizip write returning 0 on success instead of size
Misc: Misc:
- GB Serialize: Add missing savestate support for MBC6 and NT (newer) - 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: Add category to plist (closes mgba.io/i/2691)
- macOS: Fix modern build with libepoxy (fixes mgba.io/i/2700) - macOS: Fix modern build with libepoxy (fixes mgba.io/i/2700)
- Qt: Keep track of current pslette preset name (fixes mgba.io/i/2680) - 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 GBAStop(struct GBA* gba);
void GBADebug(struct GBA* gba, uint16_t value); 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 #ifdef USE_DEBUGGERS
struct mDebugger; struct mDebugger;
void GBAAttachDebugger(struct GBA* gba, struct mDebugger* debugger); void GBAAttachDebugger(struct GBA* gba, struct mDebugger* debugger);

View File

@ -512,7 +512,7 @@ static bool _GBACoreLoadROM(struct mCore* core, struct VFile* vf) {
#ifdef USE_ELF #ifdef USE_ELF
struct ELF* elf = ELFOpen(vf); struct ELF* elf = ELFOpen(vf);
if (elf) { if (elf) {
if (ELFEntry(elf) == BASE_CART0) { if (GBAVerifyELFEntry(elf, BASE_CART0)) {
GBALoadNull(core->board); GBALoadNull(core->board);
} }
bool success = mCoreLoadELF(core, elf); bool success = mCoreLoadELF(core, elf);

View File

@ -595,6 +595,63 @@ void GBADebug(struct GBA* gba, uint16_t flags) {
gba->debugFlags = GBADebugFlagsClearSend(gba->debugFlags); 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) { bool GBAIsROM(struct VFile* vf) {
if (!vf) { if (!vf) {
return false; return false;
@ -606,7 +663,7 @@ bool GBAIsROM(struct VFile* vf) {
uint32_t entry = ELFEntry(elf); uint32_t entry = ELFEntry(elf);
bool isGBA = true; bool isGBA = true;
isGBA = isGBA && ELFMachine(elf) == EM_ARM; 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); ELFClose(elf);
return isGBA; return isGBA;
} }
@ -662,7 +719,7 @@ bool GBAIsMB(struct VFile* vf) {
#ifdef USE_ELF #ifdef USE_ELF
struct ELF* elf = ELFOpen(vf); struct ELF* elf = ELFOpen(vf);
if (elf) { if (elf) {
bool isMB = ELFEntry(elf) == BASE_WORKING_RAM + 0xC0; bool isMB = GBAVerifyELFEntry(elf, BASE_WORKING_RAM + 0xC0);
ELFClose(elf); ELFClose(elf);
return isMB; return isMB;
} }