diff --git a/elf.h b/elf.h index 2000959..088cee7 100644 --- a/elf.h +++ b/elf.h @@ -46,8 +46,8 @@ typedef struct { typedef struct { u32 p_type; u32 p_offset; - void *p_vaddr; - void *p_paddr; + u32 p_vaddr; + u32 p_paddr; u32 p_filesz; u32 p_memsz; u32 p_flags; diff --git a/powerpc_elf.c b/powerpc_elf.c index aa5feff..c655686 100644 --- a/powerpc_elf.c +++ b/powerpc_elf.c @@ -32,8 +32,39 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "memory.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 +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_Phdr phdrs[PHDR_MAX]; @@ -44,61 +75,74 @@ int powerpc_boot_file(const char *path) FRESULT fres; fres = f_open(&fd, path, FA_READ); - if(fres != FR_OK) + if (fres != FR_OK) return -fres; fres = f_read(&fd, &elfhdr, sizeof(elfhdr), &read); - if(fres != FR_OK) + if (fres != FR_OK) return -fres; - if(read != sizeof(elfhdr)) + + if (read != sizeof(elfhdr)) 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]); 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"); - 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); - return -102; + return -104; } - + fres = f_lseek(&fd, elfhdr.e_phoff); - if(fres != FR_OK) + if (fres != FR_OK) return -fres; fres = f_read(&fd, phdrs, sizeof(phdrs[0])*elfhdr.e_phnum, &read); - if(fres != FR_OK) + if (fres != FR_OK) 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; powerpc_hang(); - while(count--) - { - if(phdr->p_type != PT_LOAD) { - gecko_printf("Skipping PHDR of type %d\n",phdr->p_type); + while (count--) { + if (phdr->p_type != PT_LOAD) { + gecko_printf("Skipping PHDR of type %d\n", phdr->p_type); } 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); - if(fres != FR_OK) + if (fres != FR_OK) return -fres; fres = f_read(&fd, dst, phdr->p_filesz, &read); - if(fres != FR_OK) + if (fres != FR_OK) return -fres; - if(read != phdr->p_filesz) - return -104; + if (read != phdr->p_filesz) + return -107; } phdr++; } @@ -127,25 +171,29 @@ int powerpc_boot_mem(const u8 *addr, u32 len) 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) { gecko_printf("ELF has no program headers!\n"); - return -102; + return -103; } if (ehdr->e_phnum > PHDR_MAX) { gecko_printf("ELF has too many (%d) program headers!\n", 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)) - return -103; + return -105; Elf32_Phdr *phdr = (Elf32_Phdr *) &addr[ehdr->e_phoff]; // TODO: add more checks here - // - phdrs out of bounds? // - loaded ELF overwrites itself? powerpc_hang(); @@ -154,7 +202,13 @@ int powerpc_boot_mem(const u8 *addr, u32 len) if (phdr->p_type != PT_LOAD) { gecko_printf("Skipping PHDR of type %d\n", phdr->p_type); } 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], phdr->p_filesz); }