fix some ELF parsing vulnerabilities #255
Implement the recommendations described in issue #255 by @zzazzdzz: - Check bounds when reading ELF program header sections. - Skip reading ELF section headers if the string table pointer is NULL. - Increase the buffer size for dissassembled instructions in the dissassembly view and pass the buffer size to the disArm() and disThumb() functions so that rudimentary bounds checking can be done. Also add the constants WORK_RAM_SIZE and ROM_SIZE to reduce incidence of magic numbers and make the code a bit cleaner.
This commit is contained in:
parent
c63d364058
commit
6b4862581e
|
@ -76,7 +76,7 @@ static profile_segment* profilSegment = NULL;
|
|||
#endif
|
||||
|
||||
#ifdef BKPT_SUPPORT
|
||||
uint8_t freezeWorkRAM[0x40000];
|
||||
uint8_t freezeWorkRAM[WORK_RAM_SIZE];
|
||||
uint8_t freezeInternalRAM[0x8000];
|
||||
uint8_t freezeVRAM[0x18000];
|
||||
uint8_t freezePRAM[0x400];
|
||||
|
@ -459,7 +459,7 @@ variable_desc saveGameStruct[] = {
|
|||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
static int romSize = 0x2000000;
|
||||
static int romSize = ROM_SIZE;
|
||||
|
||||
#ifdef PROFILING
|
||||
void cpuProfil(profile_segment* seg)
|
||||
|
@ -596,7 +596,7 @@ unsigned int CPUWriteState(uint8_t* data, unsigned size)
|
|||
|
||||
utilWriteMem(data, internalRAM, 0x8000);
|
||||
utilWriteMem(data, paletteRAM, 0x400);
|
||||
utilWriteMem(data, workRAM, 0x40000);
|
||||
utilWriteMem(data, workRAM, WORK_RAM_SIZE);
|
||||
utilWriteMem(data, vram, 0x20000);
|
||||
utilWriteMem(data, oam, 0x400);
|
||||
utilWriteMem(data, pix, 4 * 240 * 160);
|
||||
|
@ -646,7 +646,7 @@ bool CPUReadState(const uint8_t* data, unsigned size)
|
|||
|
||||
utilReadMem(internalRAM, data, 0x8000);
|
||||
utilReadMem(paletteRAM, data, 0x400);
|
||||
utilReadMem(workRAM, data, 0x40000);
|
||||
utilReadMem(workRAM, data, WORK_RAM_SIZE);
|
||||
utilReadMem(vram, data, 0x20000);
|
||||
utilReadMem(oam, data, 0x400);
|
||||
utilReadMem(pix, data, 4 * 240 * 160);
|
||||
|
@ -710,7 +710,7 @@ static bool CPUWriteState(gzFile gzFile)
|
|||
|
||||
utilGzWrite(gzFile, internalRAM, 0x8000);
|
||||
utilGzWrite(gzFile, paletteRAM, 0x400);
|
||||
utilGzWrite(gzFile, workRAM, 0x40000);
|
||||
utilGzWrite(gzFile, workRAM, WORK_RAM_SIZE);
|
||||
utilGzWrite(gzFile, vram, 0x20000);
|
||||
utilGzWrite(gzFile, oam, 0x400);
|
||||
utilGzWrite(gzFile, pix, 4 * 241 * 162);
|
||||
|
@ -824,7 +824,7 @@ static bool CPUReadState(gzFile gzFile)
|
|||
|
||||
utilGzRead(gzFile, internalRAM, 0x8000);
|
||||
utilGzRead(gzFile, paletteRAM, 0x400);
|
||||
utilGzRead(gzFile, workRAM, 0x40000);
|
||||
utilGzRead(gzFile, workRAM, WORK_RAM_SIZE);
|
||||
utilGzRead(gzFile, vram, 0x20000);
|
||||
utilGzRead(gzFile, oam, 0x400);
|
||||
if (version < SAVE_GAME_VERSION_6)
|
||||
|
@ -1467,20 +1467,20 @@ void SetMapMasks()
|
|||
|
||||
int CPULoadRom(const char* szFile)
|
||||
{
|
||||
romSize = 0x2000000;
|
||||
romSize = ROM_SIZE;
|
||||
if (rom != NULL) {
|
||||
CPUCleanUp();
|
||||
}
|
||||
|
||||
systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
|
||||
|
||||
rom = (uint8_t*)malloc(0x2000000);
|
||||
rom = (uint8_t*)malloc(romSize);
|
||||
if (rom == NULL) {
|
||||
systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
|
||||
"ROM");
|
||||
return 0;
|
||||
}
|
||||
workRAM = (uint8_t*)calloc(1, 0x40000);
|
||||
workRAM = (uint8_t*)calloc(1, WORK_RAM_SIZE);
|
||||
if (workRAM == NULL) {
|
||||
systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
|
||||
"WRAM");
|
||||
|
@ -1527,7 +1527,7 @@ int CPULoadRom(const char* szFile)
|
|||
|
||||
uint16_t* temp = (uint16_t*)(rom + ((romSize + 1) & ~1));
|
||||
int i;
|
||||
for (i = (romSize + 1) & ~1; i < 0x2000000; i += 2) {
|
||||
for (i = (romSize + 1) & ~1; i < romSize; i += 2) {
|
||||
WRITE16LE(temp, (i >> 1) & 0xFFFF);
|
||||
temp++;
|
||||
}
|
||||
|
@ -1593,20 +1593,20 @@ int CPULoadRom(const char* szFile)
|
|||
|
||||
int CPULoadRomData(const char* data, int size)
|
||||
{
|
||||
romSize = 0x2000000;
|
||||
romSize = ROM_SIZE;
|
||||
if (rom != NULL) {
|
||||
CPUCleanUp();
|
||||
}
|
||||
|
||||
systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
|
||||
|
||||
rom = (uint8_t*)malloc(0x2000000);
|
||||
rom = (uint8_t*)malloc(romSize);
|
||||
if (rom == NULL) {
|
||||
systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
|
||||
"ROM");
|
||||
return 0;
|
||||
}
|
||||
workRAM = (uint8_t*)calloc(1, 0x40000);
|
||||
workRAM = (uint8_t*)calloc(1, WORK_RAM_SIZE);
|
||||
if (workRAM == NULL) {
|
||||
systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
|
||||
"WRAM");
|
||||
|
@ -1620,7 +1620,7 @@ int CPULoadRomData(const char* data, int size)
|
|||
|
||||
uint16_t* temp = (uint16_t*)(rom + ((romSize + 1) & ~1));
|
||||
int i;
|
||||
for (i = (romSize + 1) & ~1; i < 0x2000000; i += 2) {
|
||||
for (i = (romSize + 1) & ~1; i < romSize; i += 2) {
|
||||
WRITE16LE(temp, (i >> 1) & 0xFFFF);
|
||||
temp++;
|
||||
}
|
||||
|
|
|
@ -153,6 +153,9 @@ extern struct EmulatedSystem GBASystem;
|
|||
#define R14_FIQ 43
|
||||
#define SPSR_FIQ 44
|
||||
|
||||
#define WORK_RAM_SIZE 0x40000
|
||||
#define ROM_SIZE 0x2000000
|
||||
|
||||
#include "Cheats.h"
|
||||
#include "EEprom.h"
|
||||
#include "Flash.h"
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
/* Arm/Thumb command set disassembler */
|
||||
/************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <cstring>
|
||||
|
||||
#include "../System.h"
|
||||
#include "../common/Port.h"
|
||||
|
@ -214,8 +215,13 @@ char* addHex(char* dest, int siz, uint32_t val)
|
|||
return dest;
|
||||
}
|
||||
|
||||
int disArm(uint32_t offset, char* dest, int flags)
|
||||
int disArm(uint32_t offset, char* dest, unsigned dest_sz, int flags)
|
||||
{
|
||||
if (dest_sz < 80) {
|
||||
*dest = '\0';
|
||||
return 4;
|
||||
}
|
||||
|
||||
uint32_t opcode = debuggerReadMemory(offset);
|
||||
|
||||
const Opcodes* sp = armOpcodes;
|
||||
|
@ -523,8 +529,15 @@ int disArm(uint32_t offset, char* dest, int flags)
|
|||
return 4;
|
||||
}
|
||||
|
||||
int disThumb(uint32_t offset, char* dest, int flags)
|
||||
int disThumb(uint32_t offset, char* dest, unsigned dest_sz, int flags)
|
||||
{
|
||||
if (dest_sz < 80) {
|
||||
*dest = '\0';
|
||||
return 2;
|
||||
}
|
||||
|
||||
char* end = dest + dest_sz;
|
||||
|
||||
uint32_t opcode = debuggerReadHalfWord(offset);
|
||||
|
||||
const Opcodes* sp = thumbOpcodes;
|
||||
|
@ -597,7 +610,7 @@ int disThumb(uint32_t offset, char* dest, int flags)
|
|||
*dest++ = '$';
|
||||
dest = addHex(dest, 32, value);
|
||||
const char* s = elfGetAddressSymbol(value);
|
||||
if (*s) {
|
||||
if (*s && (dest + strlen(s) + 1) < end) {
|
||||
*dest++ = ' ';
|
||||
dest = addStr(dest, s);
|
||||
}
|
||||
|
@ -607,7 +620,7 @@ int disThumb(uint32_t offset, char* dest, int flags)
|
|||
*dest++ = '$';
|
||||
dest = addHex(dest, 32, value);
|
||||
const char* s = elfGetAddressSymbol(value);
|
||||
if (*s) {
|
||||
if (*s && (dest + strlen(s) + 1) < end) {
|
||||
*dest++ = ' ';
|
||||
dest = addStr(dest, s);
|
||||
}
|
||||
|
@ -694,7 +707,7 @@ int disThumb(uint32_t offset, char* dest, int flags)
|
|||
*dest++ = '$';
|
||||
dest = addHex(dest, 32, offset + 4 + add);
|
||||
const char* s = elfGetAddressSymbol(offset + 4 + add);
|
||||
if (*s) {
|
||||
if (*s && (dest + strlen(s) + 3) < end) {
|
||||
*dest++ = ' ';
|
||||
*dest++ = '(';
|
||||
dest = addStr(dest, s);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#define DIS_VIEW_ADDRESS 1
|
||||
#define DIS_VIEW_CODE 2
|
||||
|
||||
int disThumb(uint32_t offset, char* dest, int flags);
|
||||
int disArm(uint32_t offset, char* dest, int flags);
|
||||
int disThumb(uint32_t offset, char* dest, unsigned dest_sz, int flags);
|
||||
int disArm(uint32_t offset, char* dest, unsigned dest_sz, int flags);
|
||||
|
||||
#endif // __ARMDIS_H__
|
||||
|
|
|
@ -852,7 +852,7 @@ void BIOS_RegisterRamReset(uint32_t flags)
|
|||
if (flags) {
|
||||
if (flags & 0x01) {
|
||||
// clear work RAM
|
||||
memset(workRAM, 0, 0x40000);
|
||||
memset(workRAM, 0, WORK_RAM_SIZE);
|
||||
}
|
||||
if (flags & 0x02) {
|
||||
// clear internal RAM
|
||||
|
|
|
@ -843,6 +843,9 @@ uint8_t* elfReadSection(uint8_t* data, ELFSectionHeader* sh)
|
|||
|
||||
ELFSectionHeader* elfGetSectionByName(const char* name)
|
||||
{
|
||||
if (elfSectionHeadersStringTable == NULL)
|
||||
return NULL;
|
||||
|
||||
for (int i = 0; i < elfSectionHeadersCount; i++) {
|
||||
if (strcmp(name,
|
||||
&elfSectionHeadersStringTable[READ32LE(&elfSectionHeaders[i]->name)])
|
||||
|
@ -2538,7 +2541,7 @@ void elfReadSymtab(uint8_t* data)
|
|||
// free(symtab);
|
||||
}
|
||||
|
||||
bool elfReadProgram(ELFHeader* eh, uint8_t* data, int& size, bool parseDebug)
|
||||
bool elfReadProgram(ELFHeader* eh, uint8_t* data, unsigned long data_size, int& size, bool parseDebug)
|
||||
{
|
||||
int count = READ16LE(&eh->e_phnum);
|
||||
int i;
|
||||
|
@ -2559,32 +2562,54 @@ bool elfReadProgram(ELFHeader* eh, uint8_t* data, int& size, bool parseDebug)
|
|||
// printf("PH %d %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
||||
// i, ph->type, ph->offset, ph->vaddr, ph->paddr,
|
||||
// ph->filesz, ph->memsz, ph->flags, ph->align);
|
||||
|
||||
unsigned address = READ32LE(&ph->paddr);
|
||||
unsigned offset = READ32LE(&ph->offset);
|
||||
unsigned section_size = READ32LE(&ph->filesz);
|
||||
|
||||
if (offset > data_size || section_size > data_size || offset + section_size > data_size)
|
||||
continue;
|
||||
|
||||
uint8_t* source = data + offset;
|
||||
|
||||
if (cpuIsMultiBoot) {
|
||||
if (READ32LE(&ph->paddr) >= 0x2000000 && READ32LE(&ph->paddr) <= 0x203ffff) {
|
||||
memcpy(&workRAM[READ32LE(&ph->paddr) & 0x3ffff],
|
||||
data + READ32LE(&ph->offset),
|
||||
READ32LE(&ph->filesz));
|
||||
size += READ32LE(&ph->filesz);
|
||||
unsigned effective_address = address - 0x2000000;
|
||||
|
||||
if (effective_address + section_size < WORK_RAM_SIZE) {
|
||||
memcpy(&workRAM[effective_address], source, section_size);
|
||||
size += section_size;
|
||||
}
|
||||
} else {
|
||||
if (READ32LE(&ph->paddr) >= 0x8000000 && READ32LE(&ph->paddr) <= 0x9ffffff) {
|
||||
memcpy(&rom[READ32LE(&ph->paddr) & 0x1ffffff],
|
||||
data + READ32LE(&ph->offset),
|
||||
READ32LE(&ph->filesz));
|
||||
size += READ32LE(&ph->filesz);
|
||||
unsigned effective_address = address - 0x8000000;
|
||||
|
||||
if (effective_address + section_size < ROM_SIZE) {
|
||||
memcpy(&rom[effective_address], source, section_size);
|
||||
size += section_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char* stringTable = NULL;
|
||||
// these must be pre-declared or clang barfs on the goto statement
|
||||
ELFSectionHeader** sh = NULL;
|
||||
char* stringTable = NULL;
|
||||
|
||||
// read section headers (if string table is good)
|
||||
if (READ16LE(&eh->e_shstrndx) == 0)
|
||||
goto end;
|
||||
|
||||
// read section headers
|
||||
p = data + READ32LE(&eh->e_shoff);
|
||||
|
||||
count = READ16LE(&eh->e_shnum);
|
||||
|
||||
ELFSectionHeader** sh = (ELFSectionHeader**)
|
||||
sh = (ELFSectionHeader**)
|
||||
malloc(sizeof(ELFSectionHeader*) * count);
|
||||
|
||||
stringTable = (char*)elfReadSection(data, sh[READ16LE(&eh->e_shstrndx)]);
|
||||
|
||||
elfSectionHeaders = sh;
|
||||
elfSectionHeadersStringTable = stringTable;
|
||||
elfSectionHeadersCount = count;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
sh[i] = (ELFSectionHeader*)p;
|
||||
p += sizeof(ELFSectionHeader);
|
||||
|
@ -2592,15 +2617,6 @@ bool elfReadProgram(ELFHeader* eh, uint8_t* data, int& size, bool parseDebug)
|
|||
p += READ16LE(&eh->e_shentsize) - sizeof(ELFSectionHeader);
|
||||
}
|
||||
|
||||
if (READ16LE(&eh->e_shstrndx) != 0) {
|
||||
stringTable = (char*)elfReadSection(data,
|
||||
sh[READ16LE(&eh->e_shstrndx)]);
|
||||
}
|
||||
|
||||
elfSectionHeaders = sh;
|
||||
elfSectionHeadersStringTable = stringTable;
|
||||
elfSectionHeadersCount = count;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
// printf("SH %d %-20s %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
||||
// i, &stringTable[sh[i]->name], sh[i]->name, sh[i]->type,
|
||||
|
@ -2703,7 +2719,7 @@ extern bool parseDebug;
|
|||
bool elfRead(const char* name, int& siz, FILE* f)
|
||||
{
|
||||
fseek(f, 0, SEEK_END);
|
||||
long size = ftell(f);
|
||||
unsigned long size = ftell(f);
|
||||
elfFileData = (uint8_t*)malloc(size);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
int res = fread(elfFileData, 1, size, f);
|
||||
|
@ -2724,7 +2740,7 @@ bool elfRead(const char* name, int& siz, FILE* f)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!elfReadProgram(header, elfFileData, siz, parseDebug)) {
|
||||
if (!elfReadProgram(header, elfFileData, size, siz, parseDebug)) {
|
||||
free(elfFileData);
|
||||
elfFileData = NULL;
|
||||
return false;
|
||||
|
|
|
@ -1355,7 +1355,7 @@ static void debuggerBreakChange(int n, char** args)
|
|||
|
||||
static void debuggerDisassembleArm(FILE* f, uint32_t pc, int count)
|
||||
{
|
||||
char buffer[80];
|
||||
char buffer[4096];
|
||||
int i = 0;
|
||||
uint32_t len = 0;
|
||||
char format[30];
|
||||
|
@ -1367,14 +1367,14 @@ static void debuggerDisassembleArm(FILE* f, uint32_t pc, int count)
|
|||
sprintf(format, "%%08x %%-%ds %%s\n", len);
|
||||
for (i = 0; i < count; i++) {
|
||||
uint32_t addr = pc;
|
||||
pc += disArm(pc, buffer, 2);
|
||||
pc += disArm(pc, buffer, 4096, 2);
|
||||
fprintf(f, format, addr, elfGetAddressSymbol(addr), buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static void debuggerDisassembleThumb(FILE* f, uint32_t pc, int count)
|
||||
{
|
||||
char buffer[80];
|
||||
char buffer[4096];
|
||||
int i = 0;
|
||||
uint32_t len = 0;
|
||||
char format[30];
|
||||
|
@ -1387,7 +1387,7 @@ static void debuggerDisassembleThumb(FILE* f, uint32_t pc, int count)
|
|||
|
||||
for (i = 0; i < count; i++) {
|
||||
uint32_t addr = pc;
|
||||
pc += disThumb(pc, buffer, 2);
|
||||
pc += disThumb(pc, buffer, 4096, 2);
|
||||
fprintf(f, format, addr, elfGetAddressSymbol(addr), buffer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -146,7 +146,7 @@ public:
|
|||
// what an unsafe calling convention
|
||||
// examination of disArm shows that max len is 69 chars
|
||||
// (e.g. 0x081cb6db), and I assume disThumb is shorter
|
||||
char buf[80];
|
||||
char buf[4096];
|
||||
dis->strings.clear();
|
||||
dis->addrs.clear();
|
||||
uint32_t addr = dis->topaddr;
|
||||
|
@ -157,9 +157,9 @@ public:
|
|||
dis->addrs.push_back(addr);
|
||||
|
||||
if (arm)
|
||||
addr += disArm(addr, buf, DIS_VIEW_CODE | DIS_VIEW_ADDRESS);
|
||||
addr += disArm(addr, buf, 4096, DIS_VIEW_CODE | DIS_VIEW_ADDRESS);
|
||||
else
|
||||
addr += disThumb(addr, buf, DIS_VIEW_CODE | DIS_VIEW_ADDRESS);
|
||||
addr += disThumb(addr, buf, 4096, DIS_VIEW_CODE | DIS_VIEW_ADDRESS);
|
||||
|
||||
dis->strings.push_back(wxString(buf, wxConvLibc));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue