Project sane ELFs: mini's ELF loader cleanup.

Entry points and phdr load ranges are now validated before relocation.
This commit is contained in:
dhewg 2009-04-16 23:50:12 +02:00 committed by bushing
parent 75958b2508
commit f28f26c791
2 changed files with 86 additions and 32 deletions

4
elf.h
View File

@ -46,8 +46,8 @@ typedef struct {
typedef struct { typedef struct {
u32 p_type; u32 p_type;
u32 p_offset; u32 p_offset;
void *p_vaddr; u32 p_vaddr;
void *p_paddr; u32 p_paddr;
u32 p_filesz; u32 p_filesz;
u32 p_memsz; u32 p_memsz;
u32 p_flags; u32 p_flags;

View File

@ -32,8 +32,39 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "memory.h" #include "memory.h"
#include "string.h" #include "string.h"
extern u8 __mem2_area_start;
#define PPC_MEM1_END (0x017fffff)
#define PPC_MEM2_START (0x10000000)
#define PPC_MEM2_END ((u32) &__mem2_area_start)
#define PHDR_MAX 10 #define PHDR_MAX 10
static int _check_physaddr(u32 addr) {
if ((addr >= PPC_MEM2_START) && (addr <= PPC_MEM2_END))
return 2;
if (addr < PPC_MEM1_END)
return 1;
return -1;
}
static int _check_physrange(u32 addr, u32 len) {
switch (_check_physaddr(addr)) {
case 1:
if ((addr + len) < PPC_MEM1_END)
return 1;
break;
case 2:
if ((addr + len) < PPC_MEM2_END)
return 2;
break;
}
return -1;
}
static Elf32_Ehdr elfhdr; static Elf32_Ehdr elfhdr;
static Elf32_Phdr phdrs[PHDR_MAX]; static Elf32_Phdr phdrs[PHDR_MAX];
@ -44,61 +75,74 @@ int powerpc_boot_file(const char *path)
FRESULT fres; FRESULT fres;
fres = f_open(&fd, path, FA_READ); fres = f_open(&fd, path, FA_READ);
if(fres != FR_OK) if (fres != FR_OK)
return -fres; return -fres;
fres = f_read(&fd, &elfhdr, sizeof(elfhdr), &read); fres = f_read(&fd, &elfhdr, sizeof(elfhdr), &read);
if(fres != FR_OK) if (fres != FR_OK)
return -fres; return -fres;
if(read != sizeof(elfhdr))
if (read != sizeof(elfhdr))
return -100; return -100;
if(memcmp("\x7F" "ELF\x01\x02\x01\x00\x00",elfhdr.e_ident,9)) { if (memcmp("\x7F" "ELF\x01\x02\x01\x00\x00",elfhdr.e_ident,9)) {
gecko_printf("Invalid ELF header! 0x%02x 0x%02x 0x%02x 0x%02x\n",elfhdr.e_ident[0], elfhdr.e_ident[1], elfhdr.e_ident[2], elfhdr.e_ident[3]); gecko_printf("Invalid ELF header! 0x%02x 0x%02x 0x%02x 0x%02x\n",elfhdr.e_ident[0], elfhdr.e_ident[1], elfhdr.e_ident[2], elfhdr.e_ident[3]);
return -101; return -101;
} }
if(elfhdr.e_phoff == 0 || elfhdr.e_phnum == 0) { if (_check_physaddr(elfhdr.e_entry) < 0) {
gecko_printf("Invalid entry point! 0x%08x\n", elfhdr.e_entry);
return -102;
}
if (elfhdr.e_phoff == 0 || elfhdr.e_phnum == 0) {
gecko_printf("ELF has no program headers!\n"); gecko_printf("ELF has no program headers!\n");
return -102; return -103;
} }
if(elfhdr.e_phnum > PHDR_MAX) {
if (elfhdr.e_phnum > PHDR_MAX) {
gecko_printf("ELF has too many (%d) program headers!\n", elfhdr.e_phnum); gecko_printf("ELF has too many (%d) program headers!\n", elfhdr.e_phnum);
return -102; return -104;
} }
fres = f_lseek(&fd, elfhdr.e_phoff); fres = f_lseek(&fd, elfhdr.e_phoff);
if(fres != FR_OK) if (fres != FR_OK)
return -fres; return -fres;
fres = f_read(&fd, phdrs, sizeof(phdrs[0])*elfhdr.e_phnum, &read); fres = f_read(&fd, phdrs, sizeof(phdrs[0])*elfhdr.e_phnum, &read);
if(fres != FR_OK) if (fres != FR_OK)
return -fres; return -fres;
if(read != sizeof(phdrs[0])*elfhdr.e_phnum)
return -103;
int count = elfhdr.e_phnum; if (read != sizeof(phdrs[0])*elfhdr.e_phnum)
return -105;
u16 count = elfhdr.e_phnum;
Elf32_Phdr *phdr = phdrs; Elf32_Phdr *phdr = phdrs;
powerpc_hang(); powerpc_hang();
while(count--) while (count--) {
{ if (phdr->p_type != PT_LOAD) {
if(phdr->p_type != PT_LOAD) { gecko_printf("Skipping PHDR of type %d\n", phdr->p_type);
gecko_printf("Skipping PHDR of type %d\n",phdr->p_type);
} else { } else {
void *dst = phdr->p_paddr; if (_check_physrange(phdr->p_paddr, phdr->p_memsz) < 0) {
gecko_printf("PHDR out of bounds [0x%08x...0x%08x]\n",
phdr->p_paddr, phdr->p_paddr + phdr->p_memsz);
return -106;
}
gecko_printf("LOAD 0x%x -> %p [0x%x]\n", phdr->p_offset, phdr->p_paddr, phdr->p_filesz); void *dst = (void *) phdr->p_paddr;
gecko_printf("LOAD 0x%x @0x%08x [0x%x]\n", phdr->p_offset, phdr->p_paddr, phdr->p_filesz);
fres = f_lseek(&fd, phdr->p_offset); fres = f_lseek(&fd, phdr->p_offset);
if(fres != FR_OK) if (fres != FR_OK)
return -fres; return -fres;
fres = f_read(&fd, dst, phdr->p_filesz, &read); fres = f_read(&fd, dst, phdr->p_filesz, &read);
if(fres != FR_OK) if (fres != FR_OK)
return -fres; return -fres;
if(read != phdr->p_filesz) if (read != phdr->p_filesz)
return -104; return -107;
} }
phdr++; phdr++;
} }
@ -127,25 +171,29 @@ int powerpc_boot_mem(const u8 *addr, u32 len)
return -101; return -101;
} }
if (_check_physaddr(ehdr->e_entry) < 0) {
gecko_printf("Invalid entry point! 0x%08x\n", ehdr->e_entry);
return -102;
}
if (ehdr->e_phoff == 0 || ehdr->e_phnum == 0) { if (ehdr->e_phoff == 0 || ehdr->e_phnum == 0) {
gecko_printf("ELF has no program headers!\n"); gecko_printf("ELF has no program headers!\n");
return -102; return -103;
} }
if (ehdr->e_phnum > PHDR_MAX) { if (ehdr->e_phnum > PHDR_MAX) {
gecko_printf("ELF has too many (%d) program headers!\n", gecko_printf("ELF has too many (%d) program headers!\n",
ehdr->e_phnum); ehdr->e_phnum);
return -102; return -104;
} }
int count = ehdr->e_phnum; u16 count = ehdr->e_phnum;
if (len < ehdr->e_phoff + count * sizeof(Elf32_Phdr)) if (len < ehdr->e_phoff + count * sizeof(Elf32_Phdr))
return -103; return -105;
Elf32_Phdr *phdr = (Elf32_Phdr *) &addr[ehdr->e_phoff]; Elf32_Phdr *phdr = (Elf32_Phdr *) &addr[ehdr->e_phoff];
// TODO: add more checks here // TODO: add more checks here
// - phdrs out of bounds?
// - loaded ELF overwrites itself? // - loaded ELF overwrites itself?
powerpc_hang(); powerpc_hang();
@ -154,7 +202,13 @@ int powerpc_boot_mem(const u8 *addr, u32 len)
if (phdr->p_type != PT_LOAD) { if (phdr->p_type != PT_LOAD) {
gecko_printf("Skipping PHDR of type %d\n", phdr->p_type); gecko_printf("Skipping PHDR of type %d\n", phdr->p_type);
} else { } else {
gecko_printf("LOAD 0x%x -> %p [0x%x]\n", phdr->p_offset, phdr->p_paddr, phdr->p_filesz); if (_check_physrange(phdr->p_paddr, phdr->p_memsz) < 0) {
gecko_printf("PHDR out of bounds [0x%08x...0x%08x]\n",
phdr->p_paddr, phdr->p_paddr + phdr->p_memsz);
return -106;
}
gecko_printf("LOAD 0x%x @0x%08x [0x%x]\n", phdr->p_offset, phdr->p_paddr, phdr->p_filesz);
memcpy((void *) phdr->p_paddr, &addr[phdr->p_offset], memcpy((void *) phdr->p_paddr, &addr[phdr->p_offset],
phdr->p_filesz); phdr->p_filesz);
} }