OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2011 The Native Client Authors. All rights reserved. | 2 * Copyright (c) 2011 The Native Client Authors. All rights reserved. |
3 * Use of this source code is governed by a BSD-style license that can be | 3 * Use of this source code is governed by a BSD-style license that can be |
4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
5 */ | 5 */ |
6 | 6 |
7 /* | 7 /* |
8 * NaCl helper functions to deal with elf images | 8 * NaCl helper functions to deal with elf images |
9 */ | 9 */ |
10 | 10 |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
148 | 148 |
149 | 149 |
150 NaClErrorCode NaClElfImageValidateElfHeader(struct NaClElfImage *image) { | 150 NaClErrorCode NaClElfImageValidateElfHeader(struct NaClElfImage *image) { |
151 const Elf_Ehdr *hdr = &image->ehdr; | 151 const Elf_Ehdr *hdr = &image->ehdr; |
152 | 152 |
153 if (memcmp(hdr->e_ident, ELFMAG, SELFMAG)) { | 153 if (memcmp(hdr->e_ident, ELFMAG, SELFMAG)) { |
154 NaClLog(LOG_ERROR, "bad elf magic\n"); | 154 NaClLog(LOG_ERROR, "bad elf magic\n"); |
155 return LOAD_BAD_ELF_MAGIC; | 155 return LOAD_BAD_ELF_MAGIC; |
156 } | 156 } |
157 | 157 |
158 #if NACL_TARGET_SUBARCH == 64 | |
159 if (ELFCLASS64 != hdr->e_ident[EI_CLASS]) { | |
160 NaClLog(LOG_ERROR, "bad elf class\n"); | |
161 return LOAD_NOT_64_BIT; | |
162 } | |
163 #else | |
164 if (ELFCLASS32 != hdr->e_ident[EI_CLASS]) { | 158 if (ELFCLASS32 != hdr->e_ident[EI_CLASS]) { |
165 NaClLog(LOG_ERROR, "bad elf class\n"); | 159 NaClLog(LOG_ERROR, "bad elf class\n"); |
166 return LOAD_NOT_32_BIT; | 160 return LOAD_NOT_32_BIT; |
167 } | 161 } |
168 #endif | |
169 | 162 |
170 if (ET_EXEC != hdr->e_type) { | 163 if (ET_EXEC != hdr->e_type) { |
171 NaClLog(LOG_ERROR, "non executable\n"); | 164 NaClLog(LOG_ERROR, "non executable\n"); |
172 return LOAD_NOT_EXEC; | 165 return LOAD_NOT_EXEC; |
173 } | 166 } |
174 | 167 |
175 if (EM_EXPECTED_BY_NACL != hdr->e_machine) { | 168 if (EM_EXPECTED_BY_NACL != hdr->e_machine) { |
176 NaClLog(LOG_ERROR, "bad machine: %"NACL_PRIxElf_Half"\n", hdr->e_machine); | 169 NaClLog(LOG_ERROR, "bad machine: %"NACL_PRIxElf_Half"\n", hdr->e_machine); |
177 return LOAD_BAD_MACHINE; | 170 return LOAD_BAD_MACHINE; |
178 } | 171 } |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
274 return LOAD_SEGMENT_BAD_LOC; | 267 return LOAD_SEGMENT_BAD_LOC; |
275 } | 268 } |
276 if (php->p_vaddr < NACL_TRAMPOLINE_END) { | 269 if (php->p_vaddr < NACL_TRAMPOLINE_END) { |
277 NaClLog(2, | 270 NaClLog(2, |
278 ("Segment %d: virtual address (0x%08"NACL_PRIxElf_Addr | 271 ("Segment %d: virtual address (0x%08"NACL_PRIxElf_Addr |
279 ") too low\n"), | 272 ") too low\n"), |
280 segnum, | 273 segnum, |
281 php->p_vaddr); | 274 php->p_vaddr); |
282 return LOAD_SEGMENT_OUTSIDE_ADDRSPACE; | 275 return LOAD_SEGMENT_OUTSIDE_ADDRSPACE; |
283 } | 276 } |
284 /* | 277 if (php->p_vaddr >= ((uint64_t) 1U << addr_bits) || |
285 * integer overflow? Elf_Addr and Elf_Word are uint32_t or | 278 ((uint64_t) 1U << addr_bits) - php->p_vaddr < php->p_memsz) { |
286 * uint64_t, so the addition/comparison is well defined. | 279 if (php->p_vaddr + php->p_memsz < php->p_vaddr) { |
287 */ | 280 NaClLog(2, |
288 if (php->p_vaddr + php->p_memsz < php->p_vaddr) { | 281 "Segment %d: p_memsz caused integer overflow\n", |
289 NaClLog(2, | 282 segnum); |
290 "Segment %d: p_memsz caused integer overflow\n", | 283 } else { |
291 segnum); | 284 NaClLog(2, |
292 return LOAD_SEGMENT_OUTSIDE_ADDRSPACE; | 285 "Segment %d: too large, ends at 0x%08"NACL_PRIxElf_Addr"\n", |
293 } | 286 segnum, |
294 if (php->p_vaddr + php->p_memsz >= ((Elf_Addr) 1U << addr_bits)) { | 287 php->p_vaddr + php->p_memsz); |
295 NaClLog(2, | 288 } |
296 "Segment %d: too large, ends at 0x%08"NACL_PRIxElf_Addr"\n", | |
297 segnum, | |
298 php->p_vaddr + php->p_memsz); | |
299 return LOAD_SEGMENT_OUTSIDE_ADDRSPACE; | 289 return LOAD_SEGMENT_OUTSIDE_ADDRSPACE; |
300 } | 290 } |
301 if (php->p_filesz > php->p_memsz) { | 291 if (php->p_filesz > php->p_memsz) { |
302 NaClLog(2, | 292 NaClLog(2, |
303 ("Segment %d: file size 0x%08"NACL_PRIxElf_Xword" larger" | 293 ("Segment %d: file size 0x%08"NACL_PRIxElf_Xword" larger" |
304 " than memory size 0x%08"NACL_PRIxElf_Xword"\n"), | 294 " than memory size 0x%08"NACL_PRIxElf_Xword"\n"), |
305 segnum, | 295 segnum, |
306 php->p_filesz, | 296 php->p_filesz, |
307 php->p_memsz); | 297 php->p_memsz); |
308 return LOAD_SEGMENT_BAD_PARAM; | 298 return LOAD_SEGMENT_BAD_PARAM; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
356 */ | 346 */ |
357 | 347 |
358 return LOAD_OK; | 348 return LOAD_OK; |
359 } | 349 } |
360 | 350 |
361 | 351 |
362 struct NaClElfImage *NaClElfImageNew(struct Gio *gp, | 352 struct NaClElfImage *NaClElfImageNew(struct Gio *gp, |
363 NaClErrorCode *err_code) { | 353 NaClErrorCode *err_code) { |
364 struct NaClElfImage *result; | 354 struct NaClElfImage *result; |
365 struct NaClElfImage image; | 355 struct NaClElfImage image; |
356 union { | |
357 Elf32_Ehdr ehdr32; | |
358 #if NACL_TARGET_SUBARCH == 64 | |
359 Elf64_Ehdr ehdr64; | |
360 #endif | |
361 } ehdr; | |
366 int cur_ph; | 362 int cur_ph; |
367 | 363 |
368 memset(image.loadable, 0, sizeof image.loadable); | 364 memset(image.loadable, 0, sizeof image.loadable); |
369 if (-1 == (*gp->vtbl->Seek)(gp, 0, 0)) { | 365 if (-1 == (*gp->vtbl->Seek)(gp, 0, 0)) { |
370 NaClLog(2, "could not seek to beginning of Gio object containing nexe\n"); | 366 NaClLog(2, "could not seek to beginning of Gio object containing nexe\n"); |
371 if (NULL != err_code) { | 367 if (NULL != err_code) { |
372 *err_code = LOAD_READ_ERROR; | 368 *err_code = LOAD_READ_ERROR; |
373 } | 369 } |
374 return 0; | 370 return 0; |
375 } | 371 } |
372 | |
373 /* | |
374 * We read the larger size of an ELFCLASS64 header even if it turns out | |
375 * we're reading an ELFCLASS32 file. No usable ELFCLASS32 binary could | |
376 * be so small that it's not larger than Elf64_Ehdr anyway. | |
377 */ | |
376 if ((*gp->vtbl->Read)(gp, | 378 if ((*gp->vtbl->Read)(gp, |
377 &image.ehdr, | 379 &ehdr, |
378 sizeof image.ehdr) | 380 sizeof ehdr) |
379 != sizeof image.ehdr) { | 381 != sizeof ehdr) { |
380 if (NULL != err_code) { | 382 if (NULL != err_code) { |
381 *err_code = LOAD_READ_ERROR; | 383 *err_code = LOAD_READ_ERROR; |
382 } | 384 } |
383 NaClLog(2, "could not load elf headers\n"); | 385 NaClLog(2, "could not load elf headers\n"); |
384 return 0; | 386 return 0; |
385 } | 387 } |
386 | 388 |
389 #if NACL_TARGET_SUBARCH == 64 | |
390 if (ELFCLASS64 == ehdr.ehdr64.e_ident[EI_CLASS]) { | |
391 /* | |
392 * Convert ELFCLASS64 format to ELFCLASS32 format. | |
393 * The initial four fields are the same in both classes. | |
394 */ | |
395 memcpy(image.ehdr.e_ident, ehdr.ehdr64.e_ident, EI_NIDENT); | |
396 image.ehdr.e_ident[EI_CLASS] = ELFCLASS32; | |
397 image.ehdr.e_type = ehdr.ehdr64.e_type; | |
398 image.ehdr.e_machine = ehdr.ehdr64.e_machine; | |
399 image.ehdr.e_version = ehdr.ehdr64.e_version; | |
400 if (ehdr.ehdr64.e_entry > 0xffffffffU || | |
401 ehdr.ehdr64.e_phoff > 0xffffffffU || | |
402 ehdr.ehdr64.e_shoff > 0xffffffffU) { | |
403 if (NULL != err_code) { | |
404 *err_code = LOAD_EHDR_OVERFLOW; | |
405 } | |
406 NaClLog(2, "ELFCLASS64 file header fields overflow 32 bits\n"); | |
407 return 0; | |
408 } | |
409 image.ehdr.e_entry = (Elf32_Addr) ehdr.ehdr64.e_entry; | |
410 image.ehdr.e_phoff = (Elf32_Off) ehdr.ehdr64.e_phoff; | |
411 image.ehdr.e_shoff = (Elf32_Off) ehdr.ehdr64.e_shoff; | |
412 image.ehdr.e_flags = ehdr.ehdr64.e_flags; | |
413 if (ehdr.ehdr64.e_ehsize < sizeof(ehdr.ehdr64)) { | |
414 if (NULL != err_code) { | |
415 *err_code = LOAD_BAD_EHSIZE; | |
416 } | |
417 NaClLog(2, "ELFCLASS64 file e_ehsize != %d\n", (int) sizeof(ehdr.ehdr64)); | |
418 return 0; | |
419 } | |
420 image.ehdr.e_ehsize = sizeof(image.ehdr); | |
421 image.ehdr.e_phentsize = sizeof(image.phdrs[0]); | |
422 image.ehdr.e_phnum = ehdr.ehdr64.e_phnum; | |
423 image.ehdr.e_shentsize = ehdr.ehdr64.e_shentsize; | |
424 image.ehdr.e_shnum = ehdr.ehdr64.e_shnum; | |
425 image.ehdr.e_shstrndx = ehdr.ehdr64.e_shstrndx; | |
426 } else | |
427 #endif | |
428 { | |
429 image.ehdr = ehdr.ehdr32; | |
430 } | |
431 | |
387 NaClDumpElfHeader(2, &image.ehdr); | 432 NaClDumpElfHeader(2, &image.ehdr); |
388 | 433 |
389 /* read program headers */ | 434 /* read program headers */ |
390 if (image.ehdr.e_phnum > NACL_MAX_PROGRAM_HEADERS) { | 435 if (image.ehdr.e_phnum > NACL_MAX_PROGRAM_HEADERS) { |
391 if (NULL != err_code) | 436 if (NULL != err_code) |
392 *err_code = LOAD_TOO_MANY_PROG_HDRS; | 437 *err_code = LOAD_TOO_MANY_PROG_HDRS; |
393 NaClLog(2, "too many prog headers\n"); | 438 NaClLog(2, "too many prog headers\n"); |
394 return 0; | 439 return 0; |
395 } | 440 } |
396 | 441 |
397 if (image.ehdr.e_phentsize < sizeof image.phdrs[0]) { | |
398 if (NULL != err_code) { | |
399 *err_code = LOAD_PROG_HDR_SIZE_TOO_SMALL; | |
400 } | |
401 NaClLog(2, "bad prog headers size\n"); | |
402 NaClLog(2, " image.ehdr.e_phentsize = 0x%"NACL_PRIxElf_Half"\n", | |
403 image.ehdr.e_phentsize); | |
404 NaClLog(2, " sizeof image.phdrs[0] = 0x%"NACL_PRIxS"\n", | |
405 sizeof image.phdrs[0]); | |
406 return 0; | |
407 } | |
408 | |
409 /* | |
410 * NB: cast from e_phoff to off_t may not be valid, since off_t can be | |
411 * smaller than Elf64_off, but since invalid values will be rejected | |
412 * by Seek() the cast is safe (cf bsy) | |
413 */ | |
414 if ((*gp->vtbl->Seek)(gp, | 442 if ((*gp->vtbl->Seek)(gp, |
415 (off_t) image.ehdr.e_phoff, | 443 (off_t) image.ehdr.e_phoff, |
416 SEEK_SET) == (off_t) -1) { | 444 SEEK_SET) == (off_t) -1) { |
417 if (NULL != err_code) { | 445 if (NULL != err_code) { |
418 *err_code = LOAD_READ_ERROR; | 446 *err_code = LOAD_READ_ERROR; |
419 } | 447 } |
420 NaClLog(2, "cannot seek tp prog headers\n"); | 448 NaClLog(2, "cannot seek tp prog headers\n"); |
421 return 0; | 449 return 0; |
422 } | 450 } |
423 | 451 |
424 if ((size_t) (*gp->vtbl->Read)(gp, | 452 #if NACL_TARGET_SUBARCH == 64 |
425 &image.phdrs[0], | 453 if (ELFCLASS64 == ehdr.ehdr64.e_ident[EI_CLASS]) { |
426 image.ehdr.e_phnum * sizeof image.phdrs[0]) | 454 /* |
427 != (image.ehdr.e_phnum * sizeof image.phdrs[0])) { | 455 * We'll load the 64-bit phdrs and convert them to 32-bit format. |
428 if (NULL != err_code) { | 456 */ |
429 *err_code = LOAD_READ_ERROR; | 457 Elf64_Phdr phdr64[NACL_MAX_PROGRAM_HEADERS]; |
458 | |
459 if (ehdr.ehdr64.e_phentsize < sizeof(Elf64_Phdr)) { | |
bsy
2011/10/12 00:01:50
s/</!=/
bsy
2011/10/12 20:12:38
i meant clicking on the comment text and then clic
| |
460 if (NULL != err_code) { | |
461 *err_code = LOAD_PROG_HDR_SIZE_TOO_SMALL; | |
462 } | |
463 NaClLog(2, "bad prog headers size\n"); | |
464 NaClLog(2, " ehdr64.e_phentsize = 0x%"NACL_PRIxElf_Half"\n", | |
465 ehdr.ehdr64.e_phentsize); | |
466 NaClLog(2, " sizeof(Elf64_Phdr) = 0x%"NACL_PRIxS"\n", | |
467 sizeof(Elf64_Phdr)); | |
468 return 0; | |
430 } | 469 } |
431 NaClLog(2, "cannot load tp prog headers\n"); | 470 |
432 return 0; | 471 /* |
472 * We know the multiplication won't overflow since we rejected | |
473 * e_phnum values larger than the small constant NACL_MAX_PROGRAM_HEADERS. | |
474 */ | |
475 if ((size_t) (*gp->vtbl->Read)(gp, | |
476 &phdr64[0], | |
477 image.ehdr.e_phnum * sizeof phdr64[0]) | |
478 != (image.ehdr.e_phnum * sizeof phdr64[0])) { | |
479 if (NULL != err_code) { | |
480 *err_code = LOAD_READ_ERROR; | |
481 } | |
482 NaClLog(2, "cannot load tp prog headers\n"); | |
483 return 0; | |
484 } | |
485 | |
486 for (cur_ph = 0; cur_ph < image.ehdr.e_phnum; ++cur_ph) { | |
487 if (phdr64[cur_ph].p_offset > 0xffffffffU || | |
488 phdr64[cur_ph].p_vaddr > 0xffffffffU || | |
489 phdr64[cur_ph].p_paddr > 0xffffffffU || | |
490 phdr64[cur_ph].p_filesz > 0xffffffffU || | |
491 phdr64[cur_ph].p_memsz > 0xffffffffU || | |
492 phdr64[cur_ph].p_align > 0xffffffffU) { | |
493 if (NULL != err_code) { | |
494 *err_code = LOAD_PHDR_OVERFLOW; | |
495 } | |
496 NaClLog(2, "ELFCLASS64 program header fields overflow 32 bits\n"); | |
497 return 0; | |
498 } | |
499 image.phdrs[cur_ph].p_type = phdr64[cur_ph].p_type; | |
500 image.phdrs[cur_ph].p_offset = (Elf32_Off) phdr64[cur_ph].p_offset; | |
501 image.phdrs[cur_ph].p_vaddr = (Elf32_Addr) phdr64[cur_ph].p_vaddr; | |
502 image.phdrs[cur_ph].p_paddr = (Elf32_Addr) phdr64[cur_ph].p_paddr; | |
503 image.phdrs[cur_ph].p_filesz = (Elf32_Word) phdr64[cur_ph].p_filesz; | |
504 image.phdrs[cur_ph].p_memsz = (Elf32_Word) phdr64[cur_ph].p_memsz; | |
505 image.phdrs[cur_ph].p_flags = phdr64[cur_ph].p_flags; | |
506 image.phdrs[cur_ph].p_align = (Elf32_Word) phdr64[cur_ph].p_align; | |
507 } | |
508 } else | |
509 #endif | |
510 { | |
511 if (image.ehdr.e_phentsize < sizeof image.phdrs[0]) { | |
bsy
2011/10/12 00:01:50
s/</!=/ if we don't loop over seek/read
| |
512 if (NULL != err_code) { | |
513 *err_code = LOAD_PROG_HDR_SIZE_TOO_SMALL; | |
514 } | |
515 NaClLog(2, "bad prog headers size\n"); | |
516 NaClLog(2, " image.ehdr.e_phentsize = 0x%"NACL_PRIxElf_Half"\n", | |
517 image.ehdr.e_phentsize); | |
518 NaClLog(2, " sizeof image.phdrs[0] = 0x%"NACL_PRIxS"\n", | |
519 sizeof image.phdrs[0]); | |
520 return 0; | |
521 } | |
522 | |
523 if ((size_t) (*gp->vtbl->Read)(gp, | |
524 &image.phdrs[0], | |
525 image.ehdr.e_phnum * sizeof image.phdrs[0]) | |
526 != (image.ehdr.e_phnum * sizeof image.phdrs[0])) { | |
527 if (NULL != err_code) { | |
528 *err_code = LOAD_READ_ERROR; | |
529 } | |
530 NaClLog(2, "cannot load tp prog headers\n"); | |
531 return 0; | |
532 } | |
433 } | 533 } |
434 | 534 |
435 NaClLog(2, "=================================================\n"); | 535 NaClLog(2, "=================================================\n"); |
436 NaClLog(2, "Elf Program headers\n"); | 536 NaClLog(2, "Elf Program headers\n"); |
437 NaClLog(2, "==================================================\n"); | 537 NaClLog(2, "==================================================\n"); |
438 for (cur_ph = 0; cur_ph < image.ehdr.e_phnum; ++cur_ph) { | 538 for (cur_ph = 0; cur_ph < image.ehdr.e_phnum; ++cur_ph) { |
439 NaClDumpElfProgramHeader(2, &image.phdrs[cur_ph]); | 539 NaClDumpElfProgramHeader(2, &image.phdrs[cur_ph]); |
440 } | 540 } |
441 | 541 |
442 /* we delay allocating till the end to avoid cleanup code */ | 542 /* we delay allocating till the end to avoid cleanup code */ |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
601 size_t mapping_size = NaClRoundAllocPage(php->p_memsz); | 701 size_t mapping_size = NaClRoundAllocPage(php->p_memsz); |
602 /* | 702 /* |
603 * Note that we do not used NACL_ABI_MAP_FIXED because we do not | 703 * Note that we do not used NACL_ABI_MAP_FIXED because we do not |
604 * want to silently overwrite any existing mappings, such as the | 704 * want to silently overwrite any existing mappings, such as the |
605 * user app's data segment or the stack. We detect overmapping | 705 * user app's data segment or the stack. We detect overmapping |
606 * when mmap chooses not to use the preferred address we supply. | 706 * when mmap chooses not to use the preferred address we supply. |
607 * (Ideally mmap would provide a MAP_EXCL option for this | 707 * (Ideally mmap would provide a MAP_EXCL option for this |
608 * instead.) | 708 * instead.) |
609 */ | 709 */ |
610 result = NaClCommonSysMmapIntern( | 710 result = NaClCommonSysMmapIntern( |
611 nap, (void *) php->p_vaddr, mapping_size, | 711 nap, (void *) (uintptr_t) php->p_vaddr, mapping_size, |
612 NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE, | 712 NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE, |
613 NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE, | 713 NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE, |
614 -1, 0); | 714 -1, 0); |
615 if ((int32_t) php->p_vaddr != result) { | 715 if ((int32_t) php->p_vaddr != result) { |
616 NaClLog(1, "NaClElfImageLoadDynamically: failed to map data segment\n"); | 716 NaClLog(1, "NaClElfImageLoadDynamically: failed to map data segment\n"); |
617 return LOAD_UNLOADABLE; | 717 return LOAD_UNLOADABLE; |
618 } | 718 } |
619 if ((Elf_Word) (*gfile->vtbl->Read)(gfile, paddr, php->p_filesz) | 719 if ((Elf_Word) (*gfile->vtbl->Read)(gfile, paddr, php->p_filesz) |
620 != php->p_filesz) { | 720 != php->p_filesz) { |
621 NaClLog(1, "NaClElfImageLoadDynamically: " | 721 NaClLog(1, "NaClElfImageLoadDynamically: " |
(...skipping 30 matching lines...) Expand all Loading... | |
652 | 752 |
653 | 753 |
654 void NaClElfImageDelete(struct NaClElfImage *image) { | 754 void NaClElfImageDelete(struct NaClElfImage *image) { |
655 free(image); | 755 free(image); |
656 } | 756 } |
657 | 757 |
658 | 758 |
659 uintptr_t NaClElfImageGetEntryPoint(struct NaClElfImage *image) { | 759 uintptr_t NaClElfImageGetEntryPoint(struct NaClElfImage *image) { |
660 return image->ehdr.e_entry; | 760 return image->ehdr.e_entry; |
661 } | 761 } |
OLD | NEW |