Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /* | |
| 2 * Copyright 2013 The Chromium Authors. All rights reserved. | |
| 3 * Use of this source code is governed by a BSD-style license that can be | |
| 4 * found in the LICENSE file. | |
| 5 */ | |
| 6 | |
| 7 #include "components/nacl/loader/bare_metal/elf_util.h" | |
| 8 | |
| 9 #include <string.h> | |
| 10 #include <sys/mman.h> | |
| 11 | |
| 12 #define NACL_LOG_MODULE_NAME "elf_util" | |
| 13 | |
| 14 #include "native_client/src/include/elf.h" | |
| 15 #include "native_client/src/include/portability.h" | |
| 16 #include "native_client/src/shared/platform/nacl_host_desc.h" | |
| 17 #include "native_client/src/shared/platform/nacl_log.h" | |
| 18 #include "native_client/src/trusted/desc/nacl_desc_base.h" | |
| 19 #include "native_client/src/trusted/desc/nacl_desc_effector_trusted_mem.h" | |
| 20 | |
| 21 /* Limit of elf program headers allowed. */ | |
| 22 #define NACL_BARE_METAL_MAX_PROGRAM_HEADERS 128 | |
| 23 | |
| 24 /* Copied from native_client/src/trusted/service_runtime/nacl_config.h */ | |
| 25 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 | |
| 26 # if NACL_BUILD_SUBARCH == 32 | |
| 27 # define NACL_ELF_E_MACHINE EM_386 | |
| 28 # elif NACL_BUILD_SUBARCH == 64 | |
| 29 # define NACL_ELF_E_MACHINE EM_X86_64 | |
| 30 # else /* NACL_BUILD_SUBARCH */ | |
| 31 # error Unknown platform! | |
| 32 # endif /* NACL_BUILD_SUBARCH */ | |
| 33 #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm | |
| 34 # define NACL_ELF_E_MACHINE EM_ARM | |
| 35 #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips | |
| 36 # define NACL_ELF_E_MACHINE EM_MIPS | |
| 37 #else /* NACL_ARCH(NACL_BUILD_ARCH) */ | |
| 38 # error Unknown platform! | |
| 39 #endif /* NACL_ARCH(NACL_BUILD_ARCH) */ | |
| 40 | |
| 41 /* Copied from native_client/src/trusted/service_runtime/include/bits/mman.h */ | |
| 42 #define NACL_ABI_PROT_READ 0x1 /* Page can be read. */ | |
| 43 #define NACL_ABI_PROT_WRITE 0x2 /* Page can be written. */ | |
| 44 #define NACL_ABI_PROT_EXEC 0x4 /* Page can be executed. */ | |
| 45 #define NACL_ABI_PROT_NONE 0x0 /* Page can not be accessed. */ | |
| 46 #define NACL_ABI_MAP_PRIVATE 0x02 /* Changes are private. */ | |
| 47 #define NACL_ABI_MAP_FIXED 0x10 /* Interpret addr exactly. */ | |
| 48 | |
| 49 /* Page size for Bare Metal Mode. */ | |
| 50 #define BARE_METAL_PAGE_SIZE 4096 | |
| 51 #define BARE_METAL_PAGE_MASK (BARE_METAL_PAGE_SIZE-1) | |
| 52 | |
| 53 /* private */ | |
| 54 struct NaClBareMetalElfImage { | |
| 55 Elf_Ehdr ehdr; | |
| 56 Elf_Phdr phdrs[NACL_BARE_METAL_MAX_PROGRAM_HEADERS]; | |
| 57 }; | |
| 58 | |
| 59 /* Copied from native_client/src/trusted/service_runtime/elf_util.c */ | |
| 60 static void NaClDumpElfHeader(int loglevel, Elf_Ehdr *elf_hdr) { | |
| 61 | |
| 62 #define DUMP(m,f) do { NaClLog(loglevel, \ | |
| 63 #m " = %" f "\n", \ | |
| 64 elf_hdr->m); } while (0) | |
| 65 | |
| 66 NaClLog(loglevel, "=================================================\n"); | |
| 67 NaClLog(loglevel, "Elf header\n"); | |
| 68 NaClLog(loglevel, "==================================================\n"); | |
| 69 | |
| 70 DUMP(e_ident+1, ".3s"); | |
| 71 DUMP(e_type, "#x"); | |
| 72 DUMP(e_machine, "#x"); | |
| 73 DUMP(e_version, "#x"); | |
| 74 DUMP(e_entry, "#"NACL_PRIxElf_Addr); | |
| 75 DUMP(e_phoff, "#"NACL_PRIxElf_Off); | |
| 76 DUMP(e_shoff, "#"NACL_PRIxElf_Off); | |
| 77 DUMP(e_flags, "#"NACL_PRIxElf_Word); | |
| 78 DUMP(e_ehsize, "#"NACL_PRIxElf_Half); | |
| 79 DUMP(e_phentsize, "#"NACL_PRIxElf_Half); | |
| 80 DUMP(e_phnum, "#"NACL_PRIxElf_Half); | |
| 81 DUMP(e_shentsize, "#"NACL_PRIxElf_Half); | |
| 82 DUMP(e_shnum, "#"NACL_PRIxElf_Half); | |
| 83 DUMP(e_shstrndx, "#"NACL_PRIxElf_Half); | |
| 84 #undef DUMP | |
| 85 NaClLog(loglevel, "sizeof(Elf32_Ehdr) = 0x%x\n", (int) sizeof *elf_hdr); | |
| 86 } | |
| 87 | |
| 88 /* Copied from native_client/src/trusted/service_runtime/elf_util.c */ | |
| 89 static void NaClDumpElfProgramHeader(int loglevel, | |
| 90 Elf_Phdr *phdr) { | |
| 91 #define DUMP(mem, f) do { \ | |
| 92 NaClLog(loglevel, "%s: %" f "\n", #mem, phdr->mem); \ | |
| 93 } while (0) | |
| 94 | |
| 95 DUMP(p_type, NACL_PRIxElf_Word); | |
| 96 DUMP(p_offset, NACL_PRIxElf_Off); | |
| 97 DUMP(p_vaddr, NACL_PRIxElf_Addr); | |
| 98 DUMP(p_paddr, NACL_PRIxElf_Addr); | |
| 99 DUMP(p_filesz, NACL_PRIxElf_Xword); | |
| 100 DUMP(p_memsz, NACL_PRIxElf_Xword); | |
| 101 DUMP(p_flags, NACL_PRIxElf_Word); | |
| 102 NaClLog(2, " (%s %s %s)\n", | |
| 103 (phdr->p_flags & PF_R) ? "PF_R" : "", | |
| 104 (phdr->p_flags & PF_W) ? "PF_W" : "", | |
| 105 (phdr->p_flags & PF_X) ? "PF_X" : ""); | |
| 106 DUMP(p_align, NACL_PRIxElf_Xword); | |
| 107 #undef DUMP | |
| 108 NaClLog(loglevel, "\n"); | |
| 109 } | |
| 110 | |
| 111 /* Copied from native_client/src/trusted/service_runtime/elf_util.c */ | |
| 112 static NaClBareMetalErrorCode NaClBareMetalElfImageValidateElfHeader( | |
| 113 struct NaClBareMetalElfImage *image) { | |
| 114 const Elf_Ehdr *hdr = &image->ehdr; | |
| 115 | |
| 116 if (memcmp(hdr->e_ident, ELFMAG, SELFMAG)) { | |
| 117 NaClLog(LOG_ERROR, "bad elf magic\n"); | |
| 118 return BARE_METAL_LOAD_BAD_ELF_MAGIC; | |
| 119 } | |
| 120 | |
| 121 if (ELFCLASS32 != hdr->e_ident[EI_CLASS]) { | |
| 122 NaClLog(LOG_ERROR, "bad elf class\n"); | |
| 123 return BARE_METAL_LOAD_NOT_32_BIT; | |
| 124 } | |
| 125 | |
| 126 if (ET_EXEC != hdr->e_type) { | |
|
Mark Seaborn
2013/12/06 03:21:16
This should require ET_DYN -- see my other comment
hidehiko
2013/12/06 17:40:02
Done.
| |
| 127 NaClLog(LOG_ERROR, "non executable\n"); | |
| 128 return BARE_METAL_LOAD_NOT_EXEC; | |
| 129 } | |
| 130 | |
| 131 if (NACL_ELF_E_MACHINE != hdr->e_machine) { | |
| 132 NaClLog(LOG_ERROR, "bad machine: %"NACL_PRIxElf_Half"\n", hdr->e_machine); | |
| 133 return BARE_METAL_LOAD_BAD_MACHINE; | |
| 134 } | |
| 135 | |
| 136 if (EV_CURRENT != hdr->e_version) { | |
| 137 NaClLog(LOG_ERROR, "bad elf version: %"NACL_PRIxElf_Word"\n", | |
| 138 hdr->e_version); | |
| 139 return BARE_METAL_LOAD_BAD_ELF_VERS; | |
| 140 } | |
| 141 | |
| 142 return BARE_METAL_LOAD_OK; | |
| 143 } | |
| 144 | |
| 145 /* Copied from native_client/src/trusted/service_runtime/elf_util.c */ | |
| 146 struct NaClBareMetalElfImage *NaClBareMetalElfImageNew( | |
| 147 struct NaClDesc *ndp, | |
| 148 NaClBareMetalErrorCode *err_code) { | |
| 149 ssize_t read_ret; | |
| 150 struct NaClBareMetalElfImage *result; | |
| 151 struct NaClBareMetalElfImage image; | |
| 152 union { | |
| 153 Elf32_Ehdr ehdr32; | |
| 154 #if NACL_TARGET_SUBARCH == 64 | |
| 155 Elf64_Ehdr ehdr64; | |
| 156 #endif | |
| 157 } ehdr; | |
| 158 int cur_ph; | |
| 159 | |
| 160 /* | |
| 161 * We read the larger size of an ELFCLASS64 header even if it turns out | |
| 162 * we're reading an ELFCLASS32 file. No usable ELFCLASS32 binary could | |
| 163 * be so small that it's not larger than Elf64_Ehdr anyway. | |
| 164 */ | |
| 165 read_ret = (*NACL_VTBL(NaClDesc, ndp)->PRead)(ndp, &ehdr, sizeof ehdr, 0); | |
| 166 if (NaClSSizeIsNegErrno(&read_ret) || (size_t) read_ret != sizeof ehdr) { | |
| 167 *err_code = BARE_METAL_LOAD_READ_ERROR; | |
| 168 NaClLog(2, "could not load elf headers\n"); | |
| 169 return 0; | |
| 170 } | |
| 171 | |
| 172 #if NACL_TARGET_SUBARCH == 64 | |
| 173 if (ELFCLASS64 == ehdr.ehdr64.e_ident[EI_CLASS]) { | |
| 174 /* | |
| 175 * Convert ELFCLASS64 format to ELFCLASS32 format. | |
| 176 * The initial four fields are the same in both classes. | |
| 177 */ | |
| 178 memcpy(image.ehdr.e_ident, ehdr.ehdr64.e_ident, EI_NIDENT); | |
| 179 image.ehdr.e_ident[EI_CLASS] = ELFCLASS32; | |
| 180 image.ehdr.e_type = ehdr.ehdr64.e_type; | |
| 181 image.ehdr.e_machine = ehdr.ehdr64.e_machine; | |
| 182 image.ehdr.e_version = ehdr.ehdr64.e_version; | |
| 183 if (ehdr.ehdr64.e_entry > 0xffffffffU || | |
| 184 ehdr.ehdr64.e_phoff > 0xffffffffU || | |
| 185 ehdr.ehdr64.e_shoff > 0xffffffffU) { | |
| 186 *err_code = BARE_METAL_LOAD_EHDR_OVERFLOW; | |
| 187 NaClLog(2, "ELFCLASS64 file header fields overflow 32 bits\n"); | |
| 188 return 0; | |
| 189 } | |
| 190 image.ehdr.e_entry = (Elf32_Addr) ehdr.ehdr64.e_entry; | |
| 191 image.ehdr.e_phoff = (Elf32_Off) ehdr.ehdr64.e_phoff; | |
| 192 image.ehdr.e_shoff = (Elf32_Off) ehdr.ehdr64.e_shoff; | |
| 193 image.ehdr.e_flags = ehdr.ehdr64.e_flags; | |
| 194 if (ehdr.ehdr64.e_ehsize != sizeof(ehdr.ehdr64)) { | |
| 195 *err_code = BARE_METAL_LOAD_BAD_EHSIZE; | |
| 196 NaClLog(2, "ELFCLASS64 file e_ehsize != %d\n", (int) sizeof(ehdr.ehdr64)); | |
| 197 return 0; | |
| 198 } | |
| 199 image.ehdr.e_ehsize = sizeof(image.ehdr); | |
| 200 image.ehdr.e_phentsize = sizeof(image.phdrs[0]); | |
| 201 image.ehdr.e_phnum = ehdr.ehdr64.e_phnum; | |
| 202 image.ehdr.e_shentsize = ehdr.ehdr64.e_shentsize; | |
| 203 image.ehdr.e_shnum = ehdr.ehdr64.e_shnum; | |
| 204 image.ehdr.e_shstrndx = ehdr.ehdr64.e_shstrndx; | |
| 205 } else | |
| 206 #endif | |
| 207 { | |
| 208 image.ehdr = ehdr.ehdr32; | |
| 209 } | |
| 210 | |
| 211 NaClDumpElfHeader(2, &image.ehdr); | |
| 212 | |
| 213 *err_code = NaClBareMetalElfImageValidateElfHeader(&image); | |
| 214 if (BARE_METAL_LOAD_OK != *err_code) { | |
| 215 return 0; | |
| 216 } | |
| 217 | |
| 218 /* read program headers */ | |
| 219 if (image.ehdr.e_phnum > NACL_BARE_METAL_MAX_PROGRAM_HEADERS) { | |
| 220 *err_code = BARE_METAL_LOAD_TOO_MANY_PROG_HDRS; | |
| 221 NaClLog(2, "too many prog headers\n"); | |
| 222 return 0; | |
| 223 } | |
| 224 | |
| 225 #if NACL_TARGET_SUBARCH == 64 | |
| 226 if (ELFCLASS64 == ehdr.ehdr64.e_ident[EI_CLASS]) { | |
| 227 /* | |
| 228 * We'll load the 64-bit phdrs and convert them to 32-bit format. | |
| 229 */ | |
| 230 Elf64_Phdr phdr64[NACL_BARE_METAL_MAX_PROGRAM_HEADERS]; | |
| 231 | |
| 232 if (ehdr.ehdr64.e_phentsize != sizeof(Elf64_Phdr)) { | |
| 233 *err_code = BARE_METAL_LOAD_BAD_PHENTSIZE; | |
| 234 NaClLog(2, "bad prog headers size\n"); | |
| 235 NaClLog(2, " ehdr64.e_phentsize = 0x%"NACL_PRIxElf_Half"\n", | |
| 236 ehdr.ehdr64.e_phentsize); | |
| 237 NaClLog(2, " sizeof(Elf64_Phdr) = 0x%"NACL_PRIxS"\n", | |
| 238 sizeof(Elf64_Phdr)); | |
| 239 return 0; | |
| 240 } | |
| 241 | |
| 242 /* | |
| 243 * We know the multiplication won't overflow since we rejected | |
| 244 * e_phnum values larger than the small constant NACL_MAX_PROGRAM_HEADERS. | |
| 245 */ | |
| 246 read_ret = (*NACL_VTBL(NaClDesc, ndp)-> | |
| 247 PRead)(ndp, | |
| 248 &phdr64[0], | |
| 249 image.ehdr.e_phnum * sizeof phdr64[0], | |
| 250 (nacl_off64_t) image.ehdr.e_phoff); | |
| 251 if (NaClSSizeIsNegErrno(&read_ret) || | |
| 252 (size_t) read_ret != image.ehdr.e_phnum * sizeof phdr64[0]) { | |
| 253 *err_code = BARE_METAL_LOAD_READ_ERROR; | |
| 254 NaClLog(2, "cannot load tp prog headers\n"); | |
| 255 return 0; | |
| 256 } | |
| 257 | |
| 258 for (cur_ph = 0; cur_ph < image.ehdr.e_phnum; ++cur_ph) { | |
| 259 if (phdr64[cur_ph].p_offset > 0xffffffffU || | |
| 260 phdr64[cur_ph].p_vaddr > 0xffffffffU || | |
| 261 phdr64[cur_ph].p_paddr > 0xffffffffU || | |
| 262 phdr64[cur_ph].p_filesz > 0xffffffffU || | |
| 263 phdr64[cur_ph].p_memsz > 0xffffffffU || | |
| 264 phdr64[cur_ph].p_align > 0xffffffffU) { | |
| 265 *err_code = BARE_METAL_LOAD_PHDR_OVERFLOW; | |
| 266 NaClLog(2, "ELFCLASS64 program header fields overflow 32 bits\n"); | |
| 267 return 0; | |
| 268 } | |
| 269 image.phdrs[cur_ph].p_type = phdr64[cur_ph].p_type; | |
| 270 image.phdrs[cur_ph].p_offset = (Elf32_Off) phdr64[cur_ph].p_offset; | |
| 271 image.phdrs[cur_ph].p_vaddr = (Elf32_Addr) phdr64[cur_ph].p_vaddr; | |
| 272 image.phdrs[cur_ph].p_paddr = (Elf32_Addr) phdr64[cur_ph].p_paddr; | |
| 273 image.phdrs[cur_ph].p_filesz = (Elf32_Word) phdr64[cur_ph].p_filesz; | |
| 274 image.phdrs[cur_ph].p_memsz = (Elf32_Word) phdr64[cur_ph].p_memsz; | |
| 275 image.phdrs[cur_ph].p_flags = phdr64[cur_ph].p_flags; | |
| 276 image.phdrs[cur_ph].p_align = (Elf32_Word) phdr64[cur_ph].p_align; | |
| 277 } | |
| 278 } else | |
| 279 #endif | |
| 280 { | |
| 281 if (image.ehdr.e_phentsize != sizeof image.phdrs[0]) { | |
| 282 *err_code = BARE_METAL_LOAD_BAD_PHENTSIZE; | |
| 283 NaClLog(2, "bad prog headers size\n"); | |
| 284 NaClLog(2, " image.ehdr.e_phentsize = 0x%"NACL_PRIxElf_Half"\n", | |
| 285 image.ehdr.e_phentsize); | |
| 286 NaClLog(2, " sizeof image.phdrs[0] = 0x%"NACL_PRIxS"\n", | |
| 287 sizeof image.phdrs[0]); | |
| 288 return 0; | |
| 289 } | |
| 290 | |
| 291 read_ret = (*NACL_VTBL(NaClDesc, ndp)-> | |
| 292 PRead)(ndp, | |
| 293 &image.phdrs[0], | |
| 294 image.ehdr.e_phnum * sizeof image.phdrs[0], | |
| 295 (nacl_off64_t) image.ehdr.e_phoff); | |
| 296 if (NaClSSizeIsNegErrno(&read_ret) || | |
| 297 (size_t) read_ret != image.ehdr.e_phnum * sizeof image.phdrs[0]) { | |
| 298 *err_code = BARE_METAL_LOAD_READ_ERROR; | |
| 299 NaClLog(2, "cannot load tp prog headers\n"); | |
| 300 return 0; | |
| 301 } | |
| 302 } | |
| 303 | |
| 304 NaClLog(2, "=================================================\n"); | |
| 305 NaClLog(2, "Elf Program headers\n"); | |
| 306 NaClLog(2, "==================================================\n"); | |
| 307 for (cur_ph = 0; cur_ph < image.ehdr.e_phnum; ++cur_ph) { | |
| 308 NaClDumpElfProgramHeader(2, &image.phdrs[cur_ph]); | |
| 309 } | |
| 310 | |
| 311 /* we delay allocating till the end to avoid cleanup code */ | |
| 312 result = malloc(sizeof image); | |
| 313 if (result == 0) { | |
| 314 *err_code = BARE_METAL_LOAD_NO_MEMORY; | |
| 315 NaClLog(LOG_FATAL, "no enough memory for image meta data\n"); | |
| 316 return 0; | |
| 317 } | |
| 318 memcpy(result, &image, sizeof image); | |
| 319 *err_code = BARE_METAL_LOAD_OK; | |
| 320 return result; | |
| 321 } | |
| 322 | |
| 323 /* Copied from native_client/src/trusted/service_runtime/elf_util.c */ | |
| 324 void NaClBareMetalElfImageDelete(struct NaClBareMetalElfImage *image) { | |
| 325 free(image); | |
| 326 } | |
| 327 | |
| 328 /* Copied from native_client/src/trusted/service_runtime/elf_util.c */ | |
| 329 uintptr_t NaClBareMetalElfImageGetEntryPoint( | |
| 330 struct NaClBareMetalElfImage *image) { | |
| 331 return image->ehdr.e_entry; | |
| 332 } | |
| 333 | |
| 334 /* | |
| 335 * Returns the address of the page starting at address 'addr' for bare metal | |
| 336 * mode. | |
| 337 */ | |
| 338 static Elf32_Addr NaClBareMetalGetPageStart(Elf32_Addr addr) { | |
| 339 return addr & ~BARE_METAL_PAGE_MASK; | |
| 340 } | |
| 341 | |
| 342 /* | |
| 343 * Returns the offset of address 'addr' in its memory page. In other words, | |
| 344 * this equals to 'addr' - NaClBareMetalGetPageStart(addr). | |
| 345 */ | |
| 346 static Elf32_Addr NaClBareMetalGetPageOffset(Elf32_Addr addr) { | |
| 347 return addr & BARE_METAL_PAGE_MASK; | |
| 348 } | |
| 349 | |
| 350 /* | |
| 351 * Returns the address of the next page after address 'addr', unless 'addr' is | |
| 352 * at the start of a page. This equals to: | |
| 353 * addr == NaClBareMetalGetPageStart(addr) ? | |
| 354 * addr : | |
| 355 * NaClBareMetalGetPageStart(addr) + BARE_METAL_PAGE_SIZE; | |
| 356 */ | |
| 357 static Elf32_Addr NaClBareMetalGetPageEnd(Elf32_Addr addr) { | |
| 358 return NaClBareMetalGetPageStart(addr + BARE_METAL_PAGE_SIZE - 1); | |
| 359 } | |
| 360 | |
| 361 /* | |
| 362 * Converts the pflags (in phdr) to mmap's prot flags. | |
| 363 */ | |
| 364 static int PFlagsToProt(int pflags) { | |
| 365 return ((pflags & PF_X) ? PROT_EXEC : 0) | | |
| 366 ((pflags & PF_R) ? PROT_READ : 0) | | |
| 367 ((pflags & PF_W) ? PROT_WRITE : 0); | |
| 368 } | |
| 369 | |
| 370 /* | |
| 371 * Converts the pflags (in phdr) to NaCl ABI's prot flags. | |
| 372 */ | |
| 373 static int PFlagsToNaClProt(int pflags) { | |
| 374 return ((pflags & PF_X) ? NACL_ABI_PROT_EXEC : 0) | | |
| 375 ((pflags & PF_R) ? NACL_ABI_PROT_READ : 0) | | |
| 376 ((pflags & PF_W) ? NACL_ABI_PROT_WRITE : 0); | |
| 377 } | |
| 378 | |
| 379 /* | |
| 380 * Returns the load size for the given phdrs, or 0 on error. | |
| 381 */ | |
| 382 static Elf32_Addr NaClBareMetalGetLoadSize( | |
| 383 const Elf32_Phdr* phdrs, | |
| 384 int phnum) { | |
| 385 int i; | |
| 386 Elf32_Addr begin = 0xFFFFFFFFU; | |
| 387 Elf32_Addr end = 0; | |
| 388 const Elf32_Phdr *phdr; | |
| 389 Elf32_Addr vaddr_end; | |
| 390 | |
| 391 NaClLog(4, "NaClBareMetalGetLoadSize: phnum=%d\n", phnum); | |
| 392 for (i = 0; i < phnum; ++i) { | |
| 393 phdr = &phdrs[i]; | |
| 394 if (phdr->p_type != PT_LOAD) { | |
| 395 /* Do nothing for non PT_LOAD header. */ | |
| 396 continue; | |
| 397 } | |
| 398 | |
| 399 if (begin > phdr->p_vaddr) { | |
| 400 begin = phdr->p_vaddr; | |
| 401 } | |
| 402 | |
| 403 vaddr_end = phdr->p_vaddr + phdr->p_memsz; | |
| 404 if (end < vaddr_end) { | |
| 405 end = vaddr_end; | |
| 406 } | |
| 407 } | |
| 408 | |
| 409 if (begin > end) { | |
| 410 /* The end address looks overflowing. */ | |
| 411 return 0; | |
| 412 } | |
| 413 | |
| 414 begin = NaClBareMetalGetPageStart(begin); | |
| 415 end = NaClBareMetalGetPageEnd(end); | |
| 416 return end - begin; | |
| 417 } | |
| 418 | |
| 419 /* | |
| 420 * Reserves the memory for the given phdrs, and stores the memory address, | |
| 421 * its size and bias to the load_start, load_size and load_bias. | |
| 422 */ | |
| 423 static NaClBareMetalErrorCode NaClBareMetalReserveMemory( | |
| 424 const Elf32_Phdr *phdrs, | |
| 425 int phnum, | |
| 426 Elf32_Addr *load_bias) { | |
| 427 NaClLog(4, "NaClBareMetalReserveMemory\n"); | |
| 428 int i; | |
| 429 void *first_loadable_segment = NULL; | |
| 430 int mmap_flags; | |
| 431 void *start; | |
| 432 | |
| 433 Elf32_Addr size = NaClBareMetalGetLoadSize(phdrs, phnum); | |
| 434 if (size == 0) { | |
| 435 NaClLog(4, | |
| 436 "NaClBareMetalReserveMemory failed to calculate size\n"); | |
| 437 return BARE_METAL_LOAD_UNLOADABLE; | |
| 438 } | |
| 439 NaClLog(4, "NaClBareMetalReserveMemory: size=%d\n", size); | |
| 440 | |
| 441 for (i = 0; i < phnum; ++i) { | |
| 442 if (phdrs[i].p_type == PT_LOAD) { | |
| 443 first_loadable_segment = (void *)(phdrs[i].p_vaddr); | |
| 444 break; | |
| 445 } | |
| 446 } | |
| 447 | |
| 448 mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS; | |
| 449 if (first_loadable_segment != 0) { | |
| 450 /* Here, the binary requires to be loaded onto fixed addressed memory. */ | |
| 451 mmap_flags |= MAP_FIXED; | |
|
Mark Seaborn
2013/12/06 03:21:16
For the initial versions of Bare Metal Mode, this
hidehiko
2013/12/06 17:40:02
Done.
| |
| 452 } | |
| 453 start = mmap(first_loadable_segment, size, PROT_NONE, mmap_flags, -1, 0); | |
| 454 if (start == MAP_FAILED) { | |
| 455 NaClLog(4, "NaClBareMetalReserveMemory: failed to mmap\n"); | |
| 456 return BARE_METAL_LOAD_NO_MEMORY; | |
| 457 } | |
| 458 | |
| 459 *load_bias = (Elf32_Addr)( | |
| 460 first_loadable_segment == 0 ? 0 : | |
| 461 start - NaClBareMetalGetPageStart((Elf32_Addr)first_loadable_segment)); | |
| 462 NaClLog(4, "NaClBareMetalReserveMemory: success\n"); | |
| 463 return BARE_METAL_LOAD_OK; | |
| 464 } | |
| 465 | |
| 466 static NaClBareMetalErrorCode NaClBareMetalLoadSegments( | |
| 467 const Elf32_Phdr *phdrs, | |
| 468 int phnum, | |
| 469 Elf32_Addr load_bias, | |
| 470 struct NaClDesc *ndp) { | |
| 471 int i; | |
| 472 const Elf32_Phdr *phdr; | |
| 473 Elf32_Addr seg_start; | |
| 474 Elf32_Addr seg_end; | |
| 475 Elf32_Addr seg_page_start; | |
| 476 Elf32_Addr seg_page_end; | |
| 477 Elf32_Addr seg_file_end; | |
| 478 Elf32_Addr file_start; | |
| 479 Elf32_Addr file_end; | |
| 480 Elf32_Addr file_page_start; | |
| 481 Elf32_Addr seg_file_end_offset; | |
| 482 uintptr_t seg_addr; | |
| 483 void *zeromap; | |
| 484 | |
| 485 for (i = 0; i < phnum; ++i) { | |
| 486 phdr = &phdrs[i]; | |
| 487 if (phdr->p_type != PT_LOAD) { | |
| 488 NaClLog(4, "NaClBareMetalLoadSegments[%d]: Skipped\n", i); | |
| 489 /* Not a load target. */ | |
| 490 continue; | |
| 491 } | |
| 492 | |
| 493 NaClLog(4, "NaClBareMetalLoadSegments[%d]: Loading...\n", i); | |
| 494 | |
| 495 seg_start = phdr->p_vaddr + load_bias; | |
| 496 seg_end = seg_start + phdr->p_memsz; | |
| 497 seg_page_start = NaClBareMetalGetPageStart(seg_start); | |
| 498 seg_page_end = NaClBareMetalGetPageEnd(seg_end); | |
| 499 seg_file_end = seg_start + phdr->p_filesz; | |
| 500 | |
| 501 file_start = phdr->p_offset; | |
| 502 file_end = file_start + phdr->p_filesz; | |
| 503 file_page_start = NaClBareMetalGetPageStart(file_start); | |
| 504 | |
| 505 seg_addr = (*NACL_VTBL(NaClDesc, ndp)->Map)( | |
| 506 ndp, | |
| 507 NaClDescEffectorTrustedMem(), | |
| 508 (void *) seg_page_start, | |
| 509 file_end - file_page_start, | |
| 510 PFlagsToNaClProt(phdr->p_flags), | |
| 511 NACL_ABI_MAP_PRIVATE | NACL_ABI_MAP_FIXED, | |
| 512 file_page_start); | |
| 513 if (NaClPtrIsNegErrno(&seg_addr)) { | |
| 514 NaClLog( | |
| 515 4, | |
| 516 "NaClBareMetalLoadSegments[%d]: mmap failed, %"NACL_PRIdPTR".\n", | |
| 517 i, seg_addr); | |
| 518 return BARE_METAL_LOAD_NO_MEMORY; | |
| 519 } | |
| 520 | |
| 521 /* Fill Zero between the segment end and the page boundary if necessary | |
| 522 (i.e. if the segment doesn't end on a page boundary) */ | |
| 523 seg_file_end_offset = NaClBareMetalGetPageOffset(seg_file_end); | |
| 524 if ((phdr->p_flags & PF_W) && seg_file_end_offset > 0) { | |
| 525 memset((void *) seg_file_end, 0, | |
| 526 BARE_METAL_PAGE_SIZE - seg_file_end_offset); | |
| 527 } | |
| 528 | |
| 529 /* seg_file_end is now the first page address after the file | |
| 530 * content. If seg_end is larger, we need to zero anything | |
| 531 * between them. This is done by using a private anonymous | |
| 532 * map for all extra pages. | |
| 533 */ | |
| 534 seg_file_end = NaClBareMetalGetPageEnd(seg_file_end); | |
| 535 if (seg_page_end > seg_file_end) { | |
| 536 zeromap = mmap((void *) seg_file_end, | |
| 537 seg_page_end - seg_file_end, | |
| 538 PFlagsToProt(phdr->p_flags), | |
| 539 MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, | |
| 540 -1, | |
| 541 0); | |
| 542 if (zeromap == MAP_FAILED) { | |
| 543 NaClLog(4, "NaClBareMetalLoadSegments[%d]: Failed to zeromap.", i); | |
| 544 return BARE_METAL_LOAD_NO_MEMORY; | |
| 545 } | |
| 546 } | |
| 547 } | |
| 548 return BARE_METAL_LOAD_OK; | |
| 549 } | |
| 550 | |
| 551 NaClBareMetalErrorCode NaClBareMetalElfImageLoad( | |
| 552 struct NaClBareMetalElfImage *image, | |
| 553 struct NaClDesc *ndp) { | |
| 554 NaClLog(3, "NaClBareMetalElfImageLoad\n"); | |
| 555 | |
| 556 Elf32_Addr load_bias = 0; | |
| 557 NaClBareMetalErrorCode error = NaClBareMetalReserveMemory( | |
| 558 image->phdrs, image->ehdr.e_phnum, &load_bias); | |
| 559 if (error != BARE_METAL_LOAD_OK) { | |
| 560 NaClLog(4, "NaClBareMetalElfImageLoad: failed to allocate memory.\n"); | |
| 561 return error; | |
| 562 } | |
| 563 NaClLog(4, | |
| 564 "NaClBareMetalElfImageLoad: Loader maps the program to 0x%X", | |
| 565 load_bias); | |
| 566 | |
| 567 error = NaClBareMetalLoadSegments( | |
| 568 image->phdrs, image->ehdr.e_phnum, load_bias, ndp); | |
| 569 if (error != BARE_METAL_LOAD_OK) { | |
| 570 NaClLog(4, | |
| 571 "NaClBareMetalElfImageLoad: Failed to load segments\n"); | |
| 572 return error; | |
| 573 } | |
| 574 | |
| 575 return BARE_METAL_LOAD_OK; | |
| 576 } | |
| OLD | NEW |