Index: src/trusted/validator/ncfileutil.c |
diff --git a/src/trusted/validator/ncfileutil.c b/src/trusted/validator/ncfileutil.c |
index bb7e6279fe31ab0e95d20dd704176651c1394afb..1814eb3e66c8715a672ace74ed86c3e91074e05d 100644 |
--- a/src/trusted/validator/ncfileutil.c |
+++ b/src/trusted/validator/ncfileutil.c |
@@ -83,8 +83,16 @@ static const char* GetEiClassName(unsigned char c) { |
} |
static int nc_load(ncfile *ncf, int fd) { |
- |
- Elf_Ehdr h; |
+ union { |
+ Elf32_Ehdr h32; |
+#if NACL_TARGET_SUBARCH == 64 |
+ Elf64_Ehdr h64; |
+#endif |
+ } h; |
+ Elf_Half phnum; |
+ Elf_Half shnum; |
+ Elf_Off phoff; |
+ Elf_Off shoff; |
ssize_t nread; |
Elf_Addr vmemlo, vmemhi; |
size_t shsize, phsize; |
@@ -98,42 +106,100 @@ static int nc_load(ncfile *ncf, int fd) { |
} |
/* do a bunch of sanity checks */ |
- if (strncmp((char *)h.e_ident, ELFMAG, strlen(ELFMAG))) { |
+ if (memcmp(h.h32.e_ident, ELFMAG, SELFMAG)) { |
ncf->error_fn("nc_load(%s): bad magic number", ncf->fname); |
return -1; |
} |
- if (h.e_ident[EI_CLASS] != NACL_ELF_CLASS) { |
- ncf->error_fn("nc_load(%s): bad EI CLASS %d %s\n", ncf->fname, |
- h.e_ident[EI_CLASS], GetEiClassName(h.e_ident[EI_CLASS])); |
+#if NACL_TARGET_SUBARCH == 64 |
+ if (h.h32.e_ident[EI_CLASS] == ELFCLASS64) { |
+ if (h.h64.e_phoff > 0xffffffffU) { |
+ ncf->error_fn("nc_load(%s): e_phoff overflows 32 bits\n", ncf->fname); |
+ return -1; |
+ } |
+ if (h.h64.e_shoff > 0xffffffffU) { |
+ ncf->error_fn("nc_load(%s): e_shoff overflows 32 bits\n", ncf->fname); |
+ return -1; |
+ } |
+ phoff = (Elf32_Off) h.h64.e_phoff; |
+ shoff = (Elf32_Off) h.h64.e_shoff; |
+ phnum = h.h64.e_phnum; |
+ shnum = h.h64.e_shnum; |
+ } else |
+#endif |
+ { |
+ if (h.h32.e_ident[EI_CLASS] == ELFCLASS32) { |
+ phoff = h.h32.e_phoff; |
+ shoff = h.h32.e_shoff; |
+ phnum = h.h32.e_phnum; |
+ shnum = h.h32.e_shnum; |
+ } else { |
+ ncf->error_fn("nc_load(%s): bad EI CLASS %d %s\n", ncf->fname, |
+ h.h32.e_ident[EI_CLASS], |
+ GetEiClassName(h.h32.e_ident[EI_CLASS])); |
+ return -1; |
+ } |
} |
/* We now support only 32-byte bundle alignment. */ |
ncf->ncalign = 32; |
/* Read the program header table */ |
- if (h.e_phnum <= 0 || h.e_phnum > kMaxPhnum) { |
- ncf->error_fn("nc_load(%s): h.e_phnum %d > kMaxPhnum %d\n", |
- ncf->fname, h.e_phnum, kMaxPhnum); |
+ if (phnum <= 0 || phnum > kMaxPhnum) { |
+ ncf->error_fn("nc_load(%s): e_phnum %d > kMaxPhnum %d\n", |
+ ncf->fname, phnum, kMaxPhnum); |
return -1; |
} |
- ncf->phnum = h.e_phnum; |
- ncf->pheaders = (Elf_Phdr *)calloc(h.e_phnum, sizeof(Elf_Phdr)); |
+ ncf->phnum = phnum; |
+ ncf->pheaders = (Elf_Phdr *)calloc(phnum, sizeof(Elf_Phdr)); |
if (NULL == ncf->pheaders) { |
ncf->error_fn("nc_load(%s): calloc(%d, %"NACL_PRIdS") failed\n", |
- ncf->fname, h.e_phnum, sizeof(Elf_Phdr)); |
+ ncf->fname, phnum, sizeof(Elf_Phdr)); |
return -1; |
} |
- phsize = h.e_phnum * sizeof(*ncf->pheaders); |
- /* TODO(karl) Remove the cast to size_t, or verify size. */ |
- nread = readat(ncf, fd, ncf->pheaders, (off_t) phsize, (off_t) h.e_phoff); |
- if (nread < 0 || (size_t) nread < phsize) return -1; |
+ phsize = phnum * sizeof(*ncf->pheaders); |
+#if NACL_TARGET_SUBARCH == 64 |
+ if (h.h32.e_ident[EI_CLASS] == ELFCLASS64) { |
+ /* |
+ * Read 64-bit program headers and convert them. |
+ */ |
+ Elf64_Phdr phdr64[kMaxPhnum]; |
+ nread = readat(ncf, fd, phdr64, (off_t) (phnum * sizeof(phdr64[0])), |
+ (off_t) phoff); |
+ if (nread < 0 || (size_t) nread < phsize) return -1; |
+ for (i = 0; i < phnum; ++i) { |
+ if (phdr64[i].p_offset > 0xffffffffU || |
+ phdr64[i].p_vaddr > 0xffffffffU || |
+ phdr64[i].p_paddr > 0xffffffffU || |
+ phdr64[i].p_filesz > 0xffffffffU || |
+ phdr64[i].p_memsz > 0xffffffffU || |
+ phdr64[i].p_align > 0xffffffffU) { |
+ ncf->error_fn("nc_load(%s): phdr[%d] fields overflow 32 bits\n", |
+ ncf->fname, i); |
+ return -1; |
+ } |
+ ncf->pheaders[i].p_type = phdr64[i].p_type; |
+ ncf->pheaders[i].p_flags = phdr64[i].p_flags; |
+ ncf->pheaders[i].p_offset = (Elf32_Off) phdr64[i].p_offset; |
+ ncf->pheaders[i].p_vaddr = (Elf32_Addr) phdr64[i].p_vaddr; |
+ ncf->pheaders[i].p_paddr = (Elf32_Addr) phdr64[i].p_paddr; |
+ ncf->pheaders[i].p_filesz = (Elf32_Word) phdr64[i].p_filesz; |
+ ncf->pheaders[i].p_memsz = (Elf32_Word) phdr64[i].p_memsz; |
+ ncf->pheaders[i].p_align = (Elf32_Word) phdr64[i].p_align; |
+ } |
+ } else |
+#endif |
+ { |
+ /* TODO(karl) Remove the cast to size_t, or verify size. */ |
+ nread = readat(ncf, fd, ncf->pheaders, (off_t) phsize, (off_t) phoff); |
+ if (nread < 0 || (size_t) nread < phsize) return -1; |
+ } |
/* Iterate through the program headers to find the virtual */ |
/* size of loaded text. */ |
vmemlo = MAX_ELF_ADDR; |
vmemhi = MIN_ELF_ADDR; |
- for (i = 0; i < h.e_phnum; i++) { |
+ for (i = 0; i < phnum; i++) { |
if (ncf->pheaders[i].p_type != PT_LOAD) continue; |
if (0 == (ncf->pheaders[i].p_flags & PF_X)) continue; |
/* This is executable text. Check low and high addrs */ |
@@ -153,7 +219,7 @@ static int nc_load(ncfile *ncf, int fd) { |
} |
/* Load program text segments */ |
- for (i = 0; i < h.e_phnum; i++) { |
+ for (i = 0; i < phnum; i++) { |
const Elf_Phdr *p = &ncf->pheaders[i]; |
if (p->p_type != PT_LOAD) continue; |
if (0 == (ncf->pheaders[i].p_flags & PF_X)) continue; |
@@ -169,8 +235,9 @@ static int nc_load(ncfile *ncf, int fd) { |
return -1; |
} |
} |
+ |
/* load the section headers */ |
- ncf->shnum = h.e_shnum; |
+ ncf->shnum = shnum; |
shsize = ncf->shnum * sizeof(*ncf->sheaders); |
ncf->sheaders = (Elf_Shdr *)calloc(1, shsize); |
if (NULL == ncf->sheaders) { |
@@ -178,12 +245,56 @@ static int nc_load(ncfile *ncf, int fd) { |
ncf->fname, shsize); |
return -1; |
} |
- /* TODO(karl) Remove the cast to size_t, or verify value in range. */ |
- nread = readat(ncf, fd, ncf->sheaders, (off_t) shsize, (off_t) h.e_shoff); |
- if (nread < 0 || (size_t) nread < shsize) { |
- ncf->error_fn("nc_load(%s): could not read section headers\n", |
- ncf->fname); |
- return -1; |
+#if NACL_TARGET_SUBARCH == 64 |
+ if (h.h32.e_ident[EI_CLASS] == ELFCLASS64) { |
+ /* |
+ * Read 64-bit section headers and convert them. |
+ */ |
+ Elf64_Shdr *shdr64 = (Elf64_Shdr *)calloc(shnum, sizeof(shdr64[0])); |
+ if (NULL == shdr64) { |
+ ncf->error_fn( |
+ "nc_load(%s): calloc(%"NACL_PRIdS", %"NACL_PRIdS") failed\n", |
+ ncf->fname, (size_t) shnum, sizeof(shdr64[0])); |
+ return -1; |
+ } |
+ shsize = ncf->shnum * sizeof(shdr64[0]); |
+ nread = readat(ncf, fd, shdr64, (off_t) shsize, (off_t) shoff); |
+ if (nread < 0 || (size_t) nread < shsize) { |
+ ncf->error_fn("nc_load(%s): could not read section headers\n", |
+ ncf->fname); |
+ return -1; |
+ } |
+ for (i = 0; i < shnum; ++i) { |
+ if (shdr64[i].sh_flags > 0xffffffffU || |
+ shdr64[i].sh_size > 0xffffffffU || |
+ shdr64[i].sh_addralign > 0xffffffffU || |
+ shdr64[i].sh_entsize > 0xffffffffU) { |
+ ncf->error_fn("nc_load(%s): shdr[%d] fields overflow 32 bits\n", |
+ ncf->fname, i); |
+ return -1; |
+ } |
+ ncf->sheaders[i].sh_name = shdr64[i].sh_name; |
+ ncf->sheaders[i].sh_type = shdr64[i].sh_type; |
+ ncf->sheaders[i].sh_flags = (Elf32_Word) shdr64[i].sh_flags; |
+ ncf->sheaders[i].sh_addr = (Elf32_Addr) shdr64[i].sh_addr; |
+ ncf->sheaders[i].sh_offset = (Elf32_Off) shdr64[i].sh_offset; |
+ ncf->sheaders[i].sh_size = (Elf32_Word) shdr64[i].sh_size; |
+ ncf->sheaders[i].sh_link = shdr64[i].sh_link; |
+ ncf->sheaders[i].sh_info = shdr64[i].sh_info; |
+ ncf->sheaders[i].sh_addralign = (Elf32_Word) shdr64[i].sh_addralign; |
+ ncf->sheaders[i].sh_entsize = (Elf32_Word) shdr64[i].sh_entsize; |
+ } |
+ free(shdr64); |
+ } else |
+#endif |
+ { |
+ /* TODO(karl) Remove the cast to size_t, or verify value in range. */ |
+ nread = readat(ncf, fd, ncf->sheaders, (off_t) shsize, (off_t) shoff); |
+ if (nread < 0 || (size_t) nread < shsize) { |
+ ncf->error_fn("nc_load(%s): could not read section headers\n", |
+ ncf->fname); |
+ return -1; |
+ } |
} |
/* success! */ |