- Timestamp:
- Oct 15, 2018 12:51:52 PM (6 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
-
include/iprt/formats/mach-o.h (modified) (10 diffs)
-
src/VBox/Runtime/common/ldr/ldrMachO.cpp (modified) (62 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/iprt/formats/mach-o.h
r74638 r74844 29 29 30 30 #include <iprt/types.h> 31 #include <iprt/assertcompile.h> 31 32 32 33 #ifndef CPU_ARCH_MASK … … 381 382 uint32_t nreloc; 382 383 uint32_t flags; 384 /** For S_LAZY_SYMBOL_POINTERS, S_NON_LAZY_SYMBOL_POINTERS and S_SYMBOL_STUBS 385 * this is the index into the indirect symbol table. */ 383 386 uint32_t reserved1; 387 /** For S_SYMBOL_STUBS this is the entry size. */ 384 388 uint32_t reserved2; 385 389 } section_32_t; … … 396 400 uint32_t nreloc; 397 401 uint32_t flags; 402 /** For S_LAZY_SYMBOL_POINTERS, S_NON_LAZY_SYMBOL_POINTERS and S_SYMBOL_STUBS 403 * this is the index into the indirect symbol table. */ 398 404 uint32_t reserved1; 399 405 uint32_t reserved2; … … 402 408 403 409 /* section flags */ 404 #define SECTION_TYPE UINT32_C(0x000000ff) 405 #define S_REGULAR 0x0 406 #define S_ZEROFILL 0x1 407 #define S_CSTRING_LITERALS 0x2 408 #define S_4BYTE_LITERALS 0x3 409 #define S_8BYTE_LITERALS 0x4 410 #define S_LITERAL_POINTERS 0x5 411 #define S_NON_LAZY_SYMBOL_POINTERS 0x6 412 #define S_LAZY_SYMBOL_POINTERS 0x7 413 #define S_SYMBOL_STUBS 0x8 414 #define S_MOD_INIT_FUNC_POINTERS 0x9 415 #define S_MOD_TERM_FUNC_POINTERS 0xa 416 #define S_COALESCED 0xb 417 #define S_GB_ZEROFILL 0xc 418 #define S_INTERPOSING 0xd 419 #define S_16BYTE_LITERALS 0xe 420 #define S_DTRACE_DOF 0xf 421 #define S_LAZY_DYLIB_SYMBOL_POINTERS 0x10 410 #define SECTION_TYPE UINT32_C(0xff) 411 #define S_REGULAR UINT32_C(0x00) 412 #define S_ZEROFILL UINT32_C(0x01) 413 #define S_CSTRING_LITERALS UINT32_C(0x02) 414 #define S_4BYTE_LITERALS UINT32_C(0x03) 415 #define S_8BYTE_LITERALS UINT32_C(0x04) 416 #define S_LITERAL_POINTERS UINT32_C(0x05) 417 #define S_NON_LAZY_SYMBOL_POINTERS UINT32_C(0x06) 418 #define S_LAZY_SYMBOL_POINTERS UINT32_C(0x07) 419 #define S_SYMBOL_STUBS UINT32_C(0x08) 420 #define S_MOD_INIT_FUNC_POINTERS UINT32_C(0x09) 421 #define S_MOD_TERM_FUNC_POINTERS UINT32_C(0x0a) 422 #define S_COALESCED UINT32_C(0x0b) 423 #define S_GB_ZEROFILL UINT32_C(0x0c) 424 #define S_INTERPOSING UINT32_C(0x0d) 425 #define S_16BYTE_LITERALS UINT32_C(0x0e) 426 #define S_DTRACE_DOF UINT32_C(0x0f) 427 #define S_LAZY_DYLIB_SYMBOL_POINTERS UINT32_C(0x10) 428 #define S_THREAD_LOCAL_REGULAR UINT32_C(0x11) 429 #define S_THREAD_LOCAL_ZEROFILL UINT32_C(0x12) 430 #define S_THREAD_LOCAL_VARIABLES UINT32_C(0x13) 431 #define S_THREAD_LOCAL_VARIABLE_POINTERS UINT32_C(0x14) 432 #define S_THREAD_LOCAL_INIT_FUNCTION_POINTERS UINT32_C(0x15) 433 434 435 422 436 423 437 #define SECTION_ATTRIBUTES UINT32_C(0xffffff00) … … 473 487 } symtab_command_t; 474 488 489 typedef struct dysymtab_command 490 { 491 uint32_t cmd; 492 uint32_t cmdsize; 493 /** @name Symbol groupings. 494 * @{ */ 495 uint32_t ilocalsym; /**< Index into the symbol table of the first local symbol. */ 496 uint32_t nlocalsym; /**< Number of local symbols. */ 497 uint32_t iextdefsym; /**< Index into the symbol table of the first externally defined symbol. */ 498 uint32_t nextdefsym; /**< Number of externally defined symbols. */ 499 uint32_t iundefsym; /**< Index into the symbol table of the first undefined symbol. */ 500 uint32_t nundefsym; /**< Number of undefined symbols. */ 501 /** @} */ 502 uint32_t tocoff; /**< Table of content file offset. (usually empty) */ 503 uint32_t ntoc; /**< Number of entries in TOC. */ 504 uint32_t modtaboff; /** The module table file offset. (usually empty) */ 505 uint32_t nmodtab; /**< Number of entries in the module table. */ 506 /** @name Dynamic symbol tables. 507 * @{ */ 508 uint32_t extrefsymoff; /**< Externally referenceable symbol table file offset. @sa dylib_reference_t */ 509 uint32_t nextrefsym; /**< Number externally referenceable symbols. */ 510 uint32_t indirectsymboff; /**< Indirect symbol table (32-bit symtab indexes) for thunks and offset tables. */ 511 uint32_t nindirectsymb; /**< Number of indirect symbol table entries. */ 512 /** @} */ 513 /** @name Relocations. 514 * @{ */ 515 uint32_t extreloff; /**< External relocations (r_address is relative to first segment (i.e. RVA)). */ 516 uint32_t nextrel; /**< Number of external relocations. */ 517 uint32_t locreloff; /**< Local relocations (r_address is relative to first segment (i.e. RVA)). */ 518 uint32_t nlocrel; /**< Number of local relocations. */ 519 /** @} */ 520 } dysymtab_command_t; 521 AssertCompileSize(dysymtab_command_t, 80); 522 523 /** Special indirect symbol table entry value, stripped local symbol. */ 524 #define INDIRECT_SYMBOL_LOCAL UINT32_C(0x80000000) 525 /** Special indirect symbol table entry value, stripped absolute symbol. */ 526 #define INDIRECT_SYMBOL_ABS UINT32_C(0x40000000) 527 528 typedef struct dylib_reference 529 { 530 uint32_t isym : 24; /**< Symbol table index. */ 531 uint32_t flags : 8; /**< REFERENCE_FLAG_XXX? */ 532 } dylib_reference_t; 533 AssertCompileSize(dylib_reference_t, 4); 534 535 536 typedef struct dylib_table_of_contents 537 { 538 uint32_t symbol_index; /**< External symbol table entry. */ 539 uint32_t module_index; /**< The module table index of the module defining it. */ 540 } dylib_table_of_contents_t; 541 AssertCompileSize(dylib_table_of_contents_t, 8); 542 543 544 /** 32-bit module table entry. */ 545 typedef struct dylib_module 546 { 547 uint32_t module_name; 548 uint32_t iextdefsym; 549 uint32_t nextdefsym; 550 uint32_t irefsym; 551 uint32_t nrefsym; 552 uint32_t ilocalsym; 553 uint32_t nlocalsym; 554 uint32_t iextrel; 555 uint32_t nextrel; 556 uint32_t iinit_iterm; 557 uint32_t ninit_nterm; 558 uint32_t objc_module_info_addr; 559 uint32_t objc_module_info_size; 560 } dylib_module_32_t; 561 AssertCompileSize(dylib_module_32_t, 13*4); 562 563 /* a 64-bit module table entry */ 564 typedef struct dylib_module_64 565 { 566 uint32_t module_name; 567 uint32_t iextdefsym; 568 uint32_t nextdefsym; 569 uint32_t irefsym; 570 uint32_t nrefsym; 571 uint32_t ilocalsym; 572 uint32_t nlocalsym; 573 uint32_t iextrel; 574 uint32_t nextrel; 575 uint32_t iinit_iterm; 576 uint32_t ninit_nterm; 577 uint32_t objc_module_info_size; 578 uint64_t objc_module_info_addr; 579 } dylib_module_64_t; 580 AssertCompileSize(dylib_module_64_t, 12*4+8); 581 475 582 typedef struct uuid_command 476 583 { … … 479 586 uint8_t uuid[16]; 480 587 } uuid_command_t; 588 AssertCompileSize(uuid_command_t, 24); 481 589 482 590 typedef struct linkedit_data_command … … 487 595 uint32_t datasize; /**< The size of the data. */ 488 596 } linkedit_data_command_t; 597 AssertCompileSize(linkedit_data_command_t, 16); 489 598 490 599 typedef struct version_min_command … … 495 604 uint32_t reserved; /**< MBZ. */ 496 605 } version_min_command_t; 606 AssertCompileSize(version_min_command_t, 16); 497 607 498 608 typedef struct macho_nlist_32 … … 602 712 uint32_t r_type : 4; 603 713 } macho_relocation_info_t; 714 AssertCompileSize(macho_relocation_info_t, 8); 604 715 605 716 #define R_ABS 0 … … 625 736 int32_t r_value; 626 737 } scattered_relocation_info_t; 738 AssertCompileSize(scattered_relocation_info_t, 8); 739 740 typedef union 741 { 742 macho_relocation_info_t r; 743 scattered_relocation_info_t s; 744 } macho_relocation_union_t; 745 AssertCompileSize(macho_relocation_union_t, 8); 627 746 628 747 typedef enum reloc_type_generic -
trunk/src/VBox/Runtime/common/ldr/ldrMachO.cpp
r74760 r74844 81 81 * Define RTLDRMODMACHO_STRICT to enabled strict checks in RTLDRMODMACHO. */ 82 82 #define RTLDRMODMACHO_STRICT 1 83 #define RTLDRMODMACHO_STRICT2 83 84 84 85 /** @def RTLDRMODMACHO_ASSERT … … 98 99 # define RTLDRMODMACHO_CHECK_RETURN(expr, rc) AssertReturn(expr, rc) 99 100 #else 100 # define RTLDRMODMACHO_CHECK_RETURN(expr, rc) do { if ( !(expr)) { return (rc); }} while (0)101 # define RTLDRMODMACHO_CHECK_RETURN(expr, rc) do { if (RT_LIKELY(expr)) {/* likely */ } else return (rc); } while (0) 101 102 #endif 102 103 … … 132 133 uint32_t cFixups; 133 134 /** The array of fixups. (lazy loaded) */ 134 macho_relocation_info_t *paFixups; 135 macho_relocation_union_t *paFixups; 136 /** Array of virgin data running parallel to paFixups */ 137 PRTUINT64U pauFixupVirginData; 135 138 /** The file offset of the fixups for this section. 136 139 * This is -1 if the section doesn't have any fixups. */ … … 224 227 /** Pointer to the loaded string table. */ 225 228 char *pchStrings; 229 /** Pointer to the dynamic symbol table command if present. */ 230 dysymtab_command_t *pDySymTab; 231 /** The indirect symbol table (size given by pDySymTab->nindirectsymb). 232 * @remarks Host endian. */ 233 uint32_t *paidxIndirectSymbols; 234 /** Dynamic relocations, first pDySymTab->nextrel external relocs followed by 235 * pDySymTab->nlocrel local ones. */ 236 macho_relocation_union_t *paRelocations; 237 /** Array of virgin data running parallel to paRelocations */ 238 PRTUINT64U pauRelocationsVirginData; 226 239 227 240 /** The image UUID, all zeros if not found. */ … … 320 333 321 334 static int kldrModMachOLoadObjSymTab(PRTLDRMODMACHO pThis); 322 static int kldrModMachOLoadFixups(PRTLDRMODMACHO pThis, RTFOFF offFixups, uint32_t cFixups, macho_relocation_info_t **ppaFixups); 323 static int kldrModMachOMapVirginBits(PRTLDRMODMACHO pThis); 335 static int kldrModMachOLoadFixups(PRTLDRMODMACHO pThis, RTFOFF offFixups, uint32_t cFixups, macho_relocation_union_t **ppaFixups); 324 336 325 337 static int kldrModMachODoQuerySymbol32Bit(PRTLDRMODMACHO pThis, const macho_nlist_32_t *paSyms, uint32_t cSyms, const char *pchStrings, … … 337 349 static int kldrModMachOObjDoImports(PRTLDRMODMACHO pThis, RTLDRADDR BaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser); 338 350 static int kldrModMachOObjDoFixups(PRTLDRMODMACHO pThis, void *pvMapping, RTLDRADDR NewBaseAddress); 339 static int kldrModMachOFixupSectionGeneric32Bit(PRTLDRMODMACHO pThis, uint8_t *pbSectBits, PRTLDRMODMACHOSECT pFixupSect, 340 macho_nlist_32_t *paSyms, uint32_t cSyms, RTLDRADDR NewBaseAddress); 341 static int kldrModMachOFixupSectionAMD64(PRTLDRMODMACHO pThis, uint8_t *pbSectBits, PRTLDRMODMACHOSECT pFixupSect, 342 macho_nlist_64_t *paSyms, uint32_t cSyms, RTLDRADDR NewBaseAddress); 351 static int kldrModMachOApplyFixupsGeneric32Bit(PRTLDRMODMACHO pThis, uint8_t *pbSectBits, size_t cbSectBits, RTLDRADDR uBitsRva, 352 RTLDRADDR uBitsLinkAddr, const macho_relocation_union_t *paFixups, 353 const uint32_t cFixups, PCRTUINT64U const pauVirginData, 354 macho_nlist_32_t *paSyms, uint32_t cSyms, RTLDRADDR NewBaseAddress); 355 static int kldrModMachOApplyFixupsAMD64(PRTLDRMODMACHO pThis, uint8_t *pbSectBits, size_t cbSectBits, RTLDRADDR uBitsRva, 356 const macho_relocation_union_t *paFixups, 357 const uint32_t cFixups, PCRTUINT64U const pauVirginData, 358 macho_nlist_64_t *paSyms, uint32_t cSyms, RTLDRADDR NewBaseAddress); 343 359 344 360 static int kldrModMachOMakeGOT(PRTLDRMODMACHO pThis, void *pvBits, RTLDRADDR NewBaseAddress); … … 549 565 pThis->cSymbols = 0; 550 566 pThis->pvaSymbols = NULL; 567 pThis->pDySymTab = NULL; 568 pThis->paRelocations = NULL; 569 pThis->pauRelocationsVirginData = NULL; 570 pThis->paidxIndirectSymbols = NULL; 551 571 pThis->offStrings = 0; 552 572 pThis->cchStrings = 0; … … 621 641 thread_command_t *pThread; 622 642 symtab_command_t *pSymTab; 643 dysymtab_command_t *pDySymTab; 623 644 uuid_command_t *pUuid; 624 645 } u; 625 const uint64_t cbFile = pRdr->pfnSize(pRdr) - offImage; 646 const uint64_t cbFile = pRdr->pfnSize(pRdr) - offImage; 647 int const fConvertEndian = pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE 648 || pHdr->magic == IMAGE_MACHO64_SIGNATURE_OE; 626 649 uint32_t cSegments = 0; 627 650 uint32_t cSections = 0; … … 632 655 int cSegmentCommands = 0; 633 656 int cSymbolTabs = 0; 634 int fConvertEndian = pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE 635 || pHdr->magic == IMAGE_MACHO64_SIGNATURE_OE; 657 uint32_t cSymbols = 0; /* Copy of u.pSymTab->nsyms. */ 658 uint32_t cDySymbolTabs = 0; 659 bool fDySymbolTabWithRelocs = false; 660 uint32_t cSectionsWithRelocs = 0; 636 661 uint8_t uEffFileType = *puEffFileType = pHdr->filetype; 637 662 … … 658 683 cbLeft -= u.pLoadCmd->cmdsize; 659 684 pb += u.pLoadCmd->cmdsize; 685 686 /* 687 * Segment macros for avoiding code duplication. 688 */ 689 /* Validation code shared with the 64-bit variant. */ 690 #define VALIDATE_AND_ADD_SEGMENT(a_cBits) \ 691 do { \ 692 bool fSkipSeg = !strcmp(pSrcSeg->segname, "__DWARF") /* Note: Not for non-object files. */ \ 693 || ( !strcmp(pSrcSeg->segname, "__CTF") /* Their CTF tool did/does weird things, */ \ 694 && pSrcSeg->vmsize == 0) /* overlapping vmaddr and zero vmsize. */ \ 695 || (cSectionsLeft > 0 && (pFirstSect->flags & S_ATTR_DEBUG)); \ 696 \ 697 /* MH_DSYM files for MH_OBJECT files must have MH_OBJECT segment translation. */ \ 698 if ( uEffFileType == MH_DSYM \ 699 && cSegmentCommands == 0 \ 700 && pSrcSeg->segname[0] == '\0') \ 701 *puEffFileType = uEffFileType = MH_OBJECT; \ 702 \ 703 RTLDRMODMACHO_CHECK_RETURN( pSrcSeg->filesize == 0 \ 704 || ( pSrcSeg->fileoff <= cbFile \ 705 && (uint64_t)pSrcSeg->fileoff + pSrcSeg->filesize <= cbFile), \ 706 VERR_LDRMACHO_BAD_LOAD_COMMAND); \ 707 RTLDRMODMACHO_CHECK_RETURN( pSrcSeg->filesize <= pSrcSeg->vmsize \ 708 || (fSkipSeg && !strcmp(pSrcSeg->segname, "__CTF") /* see above */), \ 709 VERR_LDRMACHO_BAD_LOAD_COMMAND); \ 710 RTLDRMODMACHO_CHECK_RETURN(!(~pSrcSeg->maxprot & pSrcSeg->initprot), \ 711 VERR_LDRMACHO_BAD_LOAD_COMMAND); \ 712 RTLDRMODMACHO_CHECK_RETURN(!(pSrcSeg->flags & ~(SG_HIGHVM | SG_FVMLIB | SG_NORELOC | SG_PROTECTED_VERSION_1)), \ 713 VERR_LDRMACHO_BAD_LOAD_COMMAND); \ 714 RTLDRMODMACHO_CHECK_RETURN( pSrcSeg->nsects * sizeof(section_##a_cBits##_t) \ 715 <= u.pLoadCmd->cmdsize - sizeof(segment_command_##a_cBits##_t), \ 716 VERR_LDRMACHO_BAD_LOAD_COMMAND); \ 717 RTLDRMODMACHO_CHECK_RETURN( uEffFileType != MH_OBJECT \ 718 || cSegmentCommands == 0 \ 719 || ( cSegmentCommands == 1 \ 720 && uEffFileType == MH_OBJECT \ 721 && pHdr->filetype == MH_DSYM \ 722 && fSkipSeg), \ 723 VERR_LDRMACHO_BAD_OBJECT_FILE); \ 724 cSegmentCommands++; \ 725 \ 726 /* Add the segment, if not object file. */ \ 727 if (!fSkipSeg && uEffFileType != MH_OBJECT) \ 728 { \ 729 cbStringPool += RTStrNLen(&pSrcSeg->segname[0], sizeof(pSrcSeg->segname)) + 1; \ 730 cSegments++; \ 731 if (cSegments == 1) /* The link address is set by the first segment. */ \ 732 *pLinkAddress = pSrcSeg->vmaddr; \ 733 } \ 734 } while (0) 735 736 737 /* Validation code shared with the 64-bit variant. */ 738 #define VALIDATE_AND_ADD_SECTION(a_cBits) \ 739 do { \ 740 int fFileBits; \ 741 \ 742 /* validate */ \ 743 if (uEffFileType != MH_OBJECT) \ 744 RTLDRMODMACHO_CHECK_RETURN(!strcmp(pSect->segname, pSrcSeg->segname),\ 745 VERR_LDRMACHO_BAD_SECTION); \ 746 \ 747 switch (pSect->flags & SECTION_TYPE) \ 748 { \ 749 case S_ZEROFILL: \ 750 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, VERR_LDRMACHO_BAD_SECTION); \ 751 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, VERR_LDRMACHO_BAD_SECTION); \ 752 fFileBits = 0; \ 753 break; \ 754 case S_REGULAR: \ 755 case S_CSTRING_LITERALS: \ 756 case S_COALESCED: \ 757 case S_4BYTE_LITERALS: \ 758 case S_8BYTE_LITERALS: \ 759 case S_16BYTE_LITERALS: \ 760 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, VERR_LDRMACHO_BAD_SECTION); \ 761 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, VERR_LDRMACHO_BAD_SECTION); \ 762 fFileBits = 1; \ 763 break; \ 764 \ 765 case S_SYMBOL_STUBS: \ 766 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, VERR_LDRMACHO_BAD_SECTION); \ 767 /* reserved2 == stub size. 0 has been seen (corecrypto.kext) */ \ 768 RTLDRMODMACHO_CHECK_RETURN(pSect->reserved2 < 64, VERR_LDRMACHO_BAD_SECTION); \ 769 fFileBits = 1; \ 770 break; \ 771 \ 772 case S_NON_LAZY_SYMBOL_POINTERS: \ 773 case S_LAZY_SYMBOL_POINTERS: \ 774 case S_LAZY_DYLIB_SYMBOL_POINTERS: \ 775 /* (reserved 1 = is indirect symbol table index) */ \ 776 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, VERR_LDRMACHO_BAD_SECTION); \ 777 Log(("ldrMachO: Can't load because of section flags: %#x\n", pSect->flags & SECTION_TYPE)); \ 778 *pfCanLoad = false; \ 779 fFileBits = -1; /* __DATA.__got in the 64-bit mach_kernel has bits, any things without bits? */ \ 780 break; \ 781 \ 782 case S_MOD_INIT_FUNC_POINTERS: \ 783 /** @todo this requires a query API or flag... (e.g. C++ constructors) */ \ 784 RTLDRMODMACHO_CHECK_RETURN(fOpenFlags & RTLDR_O_FOR_DEBUG, \ 785 VERR_LDRMACHO_UNSUPPORTED_INIT_SECTION); \ 786 RT_FALL_THRU(); \ 787 case S_MOD_TERM_FUNC_POINTERS: \ 788 /** @todo this requires a query API or flag... (e.g. C++ destructors) */ \ 789 RTLDRMODMACHO_CHECK_RETURN(fOpenFlags & RTLDR_O_FOR_DEBUG, \ 790 VERR_LDRMACHO_UNSUPPORTED_TERM_SECTION); \ 791 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, VERR_LDRMACHO_BAD_SECTION); \ 792 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, VERR_LDRMACHO_BAD_SECTION); \ 793 fFileBits = 1; \ 794 break; /* ignored */ \ 795 \ 796 case S_LITERAL_POINTERS: \ 797 case S_DTRACE_DOF: \ 798 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, VERR_LDRMACHO_BAD_SECTION); \ 799 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, VERR_LDRMACHO_BAD_SECTION); \ 800 fFileBits = 1; \ 801 break; \ 802 \ 803 case S_INTERPOSING: \ 804 case S_GB_ZEROFILL: \ 805 RTLDRMODMACHO_FAILED_RETURN(VERR_LDRMACHO_UNSUPPORTED_SECTION); \ 806 \ 807 default: \ 808 RTLDRMODMACHO_FAILED_RETURN(VERR_LDRMACHO_UNKNOWN_SECTION); \ 809 } \ 810 RTLDRMODMACHO_CHECK_RETURN(!(pSect->flags & ~( S_ATTR_PURE_INSTRUCTIONS | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS \ 811 | S_ATTR_NO_DEAD_STRIP | S_ATTR_LIVE_SUPPORT | S_ATTR_SELF_MODIFYING_CODE \ 812 | S_ATTR_DEBUG | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_EXT_RELOC \ 813 | S_ATTR_LOC_RELOC | SECTION_TYPE)), \ 814 VERR_LDRMACHO_BAD_SECTION); \ 815 RTLDRMODMACHO_CHECK_RETURN((pSect->flags & S_ATTR_DEBUG) == (pFirstSect->flags & S_ATTR_DEBUG), \ 816 VERR_LDRMACHO_MIXED_DEBUG_SECTION_FLAGS); \ 817 \ 818 RTLDRMODMACHO_CHECK_RETURN(pSect->addr - pSrcSeg->vmaddr <= pSrcSeg->vmsize, \ 819 VERR_LDRMACHO_BAD_SECTION); \ 820 RTLDRMODMACHO_CHECK_RETURN( pSect->addr - pSrcSeg->vmaddr + pSect->size <= pSrcSeg->vmsize \ 821 || !strcmp(pSrcSeg->segname, "__CTF") /* see above */, \ 822 VERR_LDRMACHO_BAD_SECTION); \ 823 RTLDRMODMACHO_CHECK_RETURN(pSect->align < 31, \ 824 VERR_LDRMACHO_BAD_SECTION); \ 825 /* Workaround for buggy ld64 (or as, llvm, ++) that produces a misaligned __TEXT.__unwind_info. */ \ 826 /* Seen: pSect->align = 4, pSect->addr = 0x5ebe14. Just adjust the alignment down. */ \ 827 if ( ((RT_BIT_32(pSect->align) - UINT32_C(1)) & pSect->addr) \ 828 && pSect->align == 4 \ 829 && strcmp(pSect->sectname, "__unwind_info") == 0) \ 830 pSect->align = 2; \ 831 RTLDRMODMACHO_CHECK_RETURN(!((RT_BIT_32(pSect->align) - UINT32_C(1)) & pSect->addr), \ 832 VERR_LDRMACHO_BAD_SECTION); \ 833 RTLDRMODMACHO_CHECK_RETURN(!((RT_BIT_32(pSect->align) - UINT32_C(1)) & pSrcSeg->vmaddr), \ 834 VERR_LDRMACHO_BAD_SECTION); \ 835 \ 836 /* Adjust the section offset before we check file offset. */ \ 837 offSect = (offSect + RT_BIT_64(pSect->align) - UINT64_C(1)) & ~(RT_BIT_64(pSect->align) - UINT64_C(1)); \ 838 if (pSect->addr) \ 839 { \ 840 RTLDRMODMACHO_CHECK_RETURN(offSect <= pSect->addr - pSrcSeg->vmaddr, VERR_LDRMACHO_BAD_SECTION); \ 841 if (offSect < pSect->addr - pSrcSeg->vmaddr) \ 842 offSect = pSect->addr - pSrcSeg->vmaddr; \ 843 } \ 844 \ 845 if (fFileBits && pSect->offset == 0 && pSrcSeg->fileoff == 0 && pHdr->filetype == MH_DSYM) \ 846 fFileBits = 0; \ 847 if (fFileBits) \ 848 { \ 849 if (uEffFileType != MH_OBJECT) \ 850 { \ 851 RTLDRMODMACHO_CHECK_RETURN(pSect->offset == pSrcSeg->fileoff + offSect, \ 852 VERR_LDRMACHO_NON_CONT_SEG_BITS); \ 853 RTLDRMODMACHO_CHECK_RETURN(pSect->offset - pSrcSeg->fileoff <= pSrcSeg->filesize, \ 854 VERR_LDRMACHO_BAD_SECTION); \ 855 } \ 856 RTLDRMODMACHO_CHECK_RETURN(pSect->offset <= cbFile, \ 857 VERR_LDRMACHO_BAD_SECTION); \ 858 RTLDRMODMACHO_CHECK_RETURN((uint64_t)pSect->offset + pSect->size <= cbFile, \ 859 VERR_LDRMACHO_BAD_SECTION); \ 860 } \ 861 else \ 862 RTLDRMODMACHO_CHECK_RETURN(pSect->offset == 0, VERR_LDRMACHO_BAD_SECTION); \ 863 \ 864 if (!pSect->nreloc) \ 865 RTLDRMODMACHO_CHECK_RETURN(!pSect->reloff, \ 866 VERR_LDRMACHO_BAD_SECTION); \ 867 else \ 868 { \ 869 RTLDRMODMACHO_CHECK_RETURN(pSect->reloff <= cbFile, \ 870 VERR_LDRMACHO_BAD_SECTION); \ 871 RTLDRMODMACHO_CHECK_RETURN( (uint64_t)pSect->reloff \ 872 + (RTFOFF)pSect->nreloc * sizeof(macho_relocation_info_t) \ 873 <= cbFile, \ 874 VERR_LDRMACHO_BAD_SECTION); \ 875 cSectionsWithRelocs++; \ 876 } \ 877 \ 878 /* Validate against file type (pointless?) and count the section, for object files add segment. */ \ 879 switch (uEffFileType) \ 880 { \ 881 case MH_OBJECT: \ 882 if ( !(pSect->flags & S_ATTR_DEBUG) \ 883 && strcmp(pSect->segname, "__DWARF")) \ 884 { \ 885 cbStringPool += RTStrNLen(&pSect->segname[0], sizeof(pSect->segname)) + 1; \ 886 cbStringPool += RTStrNLen(&pSect->sectname[0], sizeof(pSect->sectname)) + 1; \ 887 cSegments++; \ 888 if (cSegments == 1) /* The link address is set by the first segment. */ \ 889 *pLinkAddress = pSect->addr; \ 890 } \ 891 RT_FALL_THRU(); \ 892 case MH_EXECUTE: \ 893 case MH_DYLIB: \ 894 case MH_BUNDLE: \ 895 case MH_DSYM: \ 896 case MH_KEXT_BUNDLE: \ 897 cSections++; \ 898 break; \ 899 default: \ 900 RTLDRMODMACHO_FAILED_RETURN(VERR_INVALID_PARAMETER); \ 901 } \ 902 \ 903 /* Advance the section offset, since we're also aligning it. */ \ 904 offSect += pSect->size; \ 905 } while (0) /* VALIDATE_AND_ADD_SECTION */ 660 906 661 907 /* … … 675 921 RTLDRMODMACHO_CHECK_RETURN(u.pLoadCmd->cmdsize >= sizeof(segment_command_32_t), VERR_LDRMACHO_BAD_LOAD_COMMAND); 676 922 RTLDRMODMACHO_CHECK_RETURN( pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE 677 || pHdr->magic == IMAGE_MACHO32_SIGNATURE, VERR_LDRMACHO_BIT_MIX);923 || pHdr->magic == IMAGE_MACHO32_SIGNATURE, VERR_LDRMACHO_BIT_MIX); 678 924 if (fConvertEndian) 679 925 { … … 688 934 } 689 935 690 /* Validation code shared with the 64-bit variant. */691 #define VALIDATE_AND_ADD_SEGMENT(a_cBits) \692 do { \693 bool fSkipSeg = !strcmp(pSrcSeg->segname, "__DWARF") /* Note: Not for non-object files. */ \694 || ( !strcmp(pSrcSeg->segname, "__CTF") /* Their CTF tool did/does weird things, */ \695 && pSrcSeg->vmsize == 0) /* overlapping vmaddr and zero vmsize. */ \696 || (cSectionsLeft > 0 && (pFirstSect->flags & S_ATTR_DEBUG)); \697 \698 /* MH_DSYM files for MH_OBJECT files must have MH_OBJECT segment translation. */ \699 if ( uEffFileType == MH_DSYM \700 && cSegmentCommands == 0 \701 && pSrcSeg->segname[0] == '\0') \702 *puEffFileType = uEffFileType = MH_OBJECT; \703 \704 RTLDRMODMACHO_CHECK_RETURN( pSrcSeg->filesize == 0 \705 || ( pSrcSeg->fileoff <= cbFile \706 && (uint64_t)pSrcSeg->fileoff + pSrcSeg->filesize <= cbFile), \707 VERR_LDRMACHO_BAD_LOAD_COMMAND); \708 RTLDRMODMACHO_CHECK_RETURN( pSrcSeg->filesize <= pSrcSeg->vmsize \709 || (fSkipSeg && !strcmp(pSrcSeg->segname, "__CTF") /* see above */), \710 VERR_LDRMACHO_BAD_LOAD_COMMAND); \711 RTLDRMODMACHO_CHECK_RETURN(!(~pSrcSeg->maxprot & pSrcSeg->initprot), \712 VERR_LDRMACHO_BAD_LOAD_COMMAND); \713 RTLDRMODMACHO_CHECK_RETURN(!(pSrcSeg->flags & ~(SG_HIGHVM | SG_FVMLIB | SG_NORELOC | SG_PROTECTED_VERSION_1)), \714 VERR_LDRMACHO_BAD_LOAD_COMMAND); \715 RTLDRMODMACHO_CHECK_RETURN( pSrcSeg->nsects * sizeof(section_##a_cBits##_t) \716 <= u.pLoadCmd->cmdsize - sizeof(segment_command_##a_cBits##_t), \717 VERR_LDRMACHO_BAD_LOAD_COMMAND); \718 RTLDRMODMACHO_CHECK_RETURN( uEffFileType != MH_OBJECT \719 || cSegmentCommands == 0 \720 || ( cSegmentCommands == 1 \721 && uEffFileType == MH_OBJECT \722 && pHdr->filetype == MH_DSYM \723 && fSkipSeg), \724 VERR_LDRMACHO_BAD_OBJECT_FILE); \725 cSegmentCommands++; \726 \727 /* Add the segment, if not object file. */ \728 if (!fSkipSeg && uEffFileType != MH_OBJECT) \729 { \730 cbStringPool += RTStrNLen(&pSrcSeg->segname[0], sizeof(pSrcSeg->segname)) + 1; \731 cSegments++; \732 if (cSegments == 1) /* The link address is set by the first segment. */ \733 *pLinkAddress = pSrcSeg->vmaddr; \734 } \735 } while (0)736 737 936 VALIDATE_AND_ADD_SEGMENT(32); 937 738 938 739 939 /* … … 757 957 } 758 958 759 /* Validation code shared with the 64-bit variant. */760 #define VALIDATE_AND_ADD_SECTION(a_cBits) \761 do { \762 int fFileBits; \763 \764 /* validate */ \765 if (uEffFileType != MH_OBJECT) \766 RTLDRMODMACHO_CHECK_RETURN(!strcmp(pSect->segname, pSrcSeg->segname),\767 VERR_LDRMACHO_BAD_SECTION); \768 \769 switch (pSect->flags & SECTION_TYPE) \770 { \771 case S_ZEROFILL: \772 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, VERR_LDRMACHO_BAD_SECTION); \773 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, VERR_LDRMACHO_BAD_SECTION); \774 fFileBits = 0; \775 break; \776 case S_REGULAR: \777 case S_CSTRING_LITERALS: \778 case S_COALESCED: \779 case S_4BYTE_LITERALS: \780 case S_8BYTE_LITERALS: \781 case S_16BYTE_LITERALS: \782 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, VERR_LDRMACHO_BAD_SECTION); \783 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, VERR_LDRMACHO_BAD_SECTION); \784 fFileBits = 1; \785 break; \786 \787 case S_SYMBOL_STUBS: \788 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, VERR_LDRMACHO_BAD_SECTION); \789 /* reserved2 == stub size. 0 has been seen (corecrypto.kext) */ \790 RTLDRMODMACHO_CHECK_RETURN(pSect->reserved2 < 64, VERR_LDRMACHO_BAD_SECTION); \791 fFileBits = 1; \792 break; \793 \794 case S_NON_LAZY_SYMBOL_POINTERS: \795 case S_LAZY_SYMBOL_POINTERS: \796 case S_LAZY_DYLIB_SYMBOL_POINTERS: \797 /* (reserved 1 = is indirect symbol table index) */ \798 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, VERR_LDRMACHO_BAD_SECTION); \799 *pfCanLoad = false; \800 fFileBits = -1; /* __DATA.__got in the 64-bit mach_kernel has bits, any things without bits? */ \801 break; \802 \803 case S_MOD_INIT_FUNC_POINTERS: \804 /** @todo this requires a query API or flag... (e.g. C++ constructors) */ \805 RTLDRMODMACHO_CHECK_RETURN(fOpenFlags & RTLDR_O_FOR_DEBUG, \806 VERR_LDRMACHO_UNSUPPORTED_INIT_SECTION); \807 RT_FALL_THRU(); \808 case S_MOD_TERM_FUNC_POINTERS: \809 /** @todo this requires a query API or flag... (e.g. C++ destructors) */ \810 RTLDRMODMACHO_CHECK_RETURN(fOpenFlags & RTLDR_O_FOR_DEBUG, \811 VERR_LDRMACHO_UNSUPPORTED_TERM_SECTION); \812 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, VERR_LDRMACHO_BAD_SECTION); \813 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, VERR_LDRMACHO_BAD_SECTION); \814 fFileBits = 1; \815 break; /* ignored */ \816 \817 case S_LITERAL_POINTERS: \818 case S_DTRACE_DOF: \819 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, VERR_LDRMACHO_BAD_SECTION); \820 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, VERR_LDRMACHO_BAD_SECTION); \821 fFileBits = 1; \822 break; \823 \824 case S_INTERPOSING: \825 case S_GB_ZEROFILL: \826 RTLDRMODMACHO_FAILED_RETURN(VERR_LDRMACHO_UNSUPPORTED_SECTION); \827 \828 default: \829 RTLDRMODMACHO_FAILED_RETURN(VERR_LDRMACHO_UNKNOWN_SECTION); \830 } \831 RTLDRMODMACHO_CHECK_RETURN(!(pSect->flags & ~( S_ATTR_PURE_INSTRUCTIONS | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS \832 | S_ATTR_NO_DEAD_STRIP | S_ATTR_LIVE_SUPPORT | S_ATTR_SELF_MODIFYING_CODE \833 | S_ATTR_DEBUG | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_EXT_RELOC \834 | S_ATTR_LOC_RELOC | SECTION_TYPE)), \835 VERR_LDRMACHO_BAD_SECTION); \836 RTLDRMODMACHO_CHECK_RETURN((pSect->flags & S_ATTR_DEBUG) == (pFirstSect->flags & S_ATTR_DEBUG), \837 VERR_LDRMACHO_MIXED_DEBUG_SECTION_FLAGS); \838 \839 RTLDRMODMACHO_CHECK_RETURN(pSect->addr - pSrcSeg->vmaddr <= pSrcSeg->vmsize, \840 VERR_LDRMACHO_BAD_SECTION); \841 RTLDRMODMACHO_CHECK_RETURN( pSect->addr - pSrcSeg->vmaddr + pSect->size <= pSrcSeg->vmsize \842 || !strcmp(pSrcSeg->segname, "__CTF") /* see above */, \843 VERR_LDRMACHO_BAD_SECTION); \844 RTLDRMODMACHO_CHECK_RETURN(pSect->align < 31, \845 VERR_LDRMACHO_BAD_SECTION); \846 /* Workaround for buggy ld64 (or as, llvm, ++) that produces a misaligned __TEXT.__unwind_info. */ \847 /* Seen: pSect->align = 4, pSect->addr = 0x5ebe14. Just adjust the alignment down. */ \848 if ( ((RT_BIT_32(pSect->align) - UINT32_C(1)) & pSect->addr) \849 && pSect->align == 4 \850 && strcmp(pSect->sectname, "__unwind_info") == 0) \851 pSect->align = 2; \852 RTLDRMODMACHO_CHECK_RETURN(!((RT_BIT_32(pSect->align) - UINT32_C(1)) & pSect->addr), \853 VERR_LDRMACHO_BAD_SECTION); \854 RTLDRMODMACHO_CHECK_RETURN(!((RT_BIT_32(pSect->align) - UINT32_C(1)) & pSrcSeg->vmaddr), \855 VERR_LDRMACHO_BAD_SECTION); \856 \857 /* Adjust the section offset before we check file offset. */ \858 offSect = (offSect + RT_BIT_64(pSect->align) - UINT64_C(1)) & ~(RT_BIT_64(pSect->align) - UINT64_C(1)); \859 if (pSect->addr) \860 { \861 RTLDRMODMACHO_CHECK_RETURN(offSect <= pSect->addr - pSrcSeg->vmaddr, VERR_LDRMACHO_BAD_SECTION); \862 if (offSect < pSect->addr - pSrcSeg->vmaddr) \863 offSect = pSect->addr - pSrcSeg->vmaddr; \864 } \865 \866 if (fFileBits && pSect->offset == 0 && pSrcSeg->fileoff == 0 && pHdr->filetype == MH_DSYM) \867 fFileBits = 0; \868 if (fFileBits) \869 { \870 if (uEffFileType != MH_OBJECT) \871 { \872 RTLDRMODMACHO_CHECK_RETURN(pSect->offset == pSrcSeg->fileoff + offSect, \873 VERR_LDRMACHO_NON_CONT_SEG_BITS); \874 RTLDRMODMACHO_CHECK_RETURN(pSect->offset - pSrcSeg->fileoff <= pSrcSeg->filesize, \875 VERR_LDRMACHO_BAD_SECTION); \876 } \877 RTLDRMODMACHO_CHECK_RETURN(pSect->offset <= cbFile, \878 VERR_LDRMACHO_BAD_SECTION); \879 RTLDRMODMACHO_CHECK_RETURN((uint64_t)pSect->offset + pSect->size <= cbFile, \880 VERR_LDRMACHO_BAD_SECTION); \881 } \882 else \883 RTLDRMODMACHO_CHECK_RETURN(pSect->offset == 0, VERR_LDRMACHO_BAD_SECTION); \884 \885 if (!pSect->nreloc) \886 RTLDRMODMACHO_CHECK_RETURN(!pSect->reloff, \887 VERR_LDRMACHO_BAD_SECTION); \888 else \889 { \890 RTLDRMODMACHO_CHECK_RETURN(pSect->reloff <= cbFile, \891 VERR_LDRMACHO_BAD_SECTION); \892 RTLDRMODMACHO_CHECK_RETURN( (uint64_t)pSect->reloff \893 + (RTFOFF)pSect->nreloc * sizeof(macho_relocation_info_t) \894 <= cbFile, \895 VERR_LDRMACHO_BAD_SECTION); \896 } \897 \898 /* Validate against file type (pointless?) and count the section, for object files add segment. */ \899 switch (uEffFileType) \900 { \901 case MH_OBJECT: \902 if ( !(pSect->flags & S_ATTR_DEBUG) \903 && strcmp(pSect->segname, "__DWARF")) \904 { \905 cbStringPool += RTStrNLen(&pSect->segname[0], sizeof(pSect->segname)) + 1; \906 cbStringPool += RTStrNLen(&pSect->sectname[0], sizeof(pSect->sectname)) + 1; \907 cSegments++; \908 if (cSegments == 1) /* The link address is set by the first segment. */ \909 *pLinkAddress = pSect->addr; \910 } \911 RT_FALL_THRU(); \912 case MH_EXECUTE: \913 case MH_DYLIB: \914 case MH_BUNDLE: \915 case MH_DSYM: \916 case MH_KEXT_BUNDLE: \917 cSections++; \918 break; \919 default: \920 RTLDRMODMACHO_FAILED_RETURN(VERR_INVALID_PARAMETER); \921 } \922 \923 /* Advance the section offset, since we're also aligning it. */ \924 offSect += pSect->size; \925 } while (0) /* VALIDATE_AND_ADD_SECTION */926 927 959 VALIDATE_AND_ADD_SECTION(32); 928 960 … … 944 976 RTLDRMODMACHO_CHECK_RETURN(u.pLoadCmd->cmdsize >= sizeof(segment_command_64_t), VERR_LDRMACHO_BAD_LOAD_COMMAND); 945 977 RTLDRMODMACHO_CHECK_RETURN( pHdr->magic == IMAGE_MACHO64_SIGNATURE_OE 946 || pHdr->magic == IMAGE_MACHO64_SIGNATURE, VERR_LDRMACHO_BIT_MIX);978 || pHdr->magic == IMAGE_MACHO64_SIGNATURE, VERR_LDRMACHO_BIT_MIX); 947 979 if (fConvertEndian) 948 980 { … … 1009 1041 RTLDRMODMACHO_FAILED_RETURN(VERR_LDRMACHO_BAD_LOAD_COMMAND); 1010 1042 1011 /* only one string in objects, please. */1043 /* Only one object table, please. */ 1012 1044 cSymbolTabs++; 1013 if ( uEffFileType == MH_OBJECT 1014 && cSymbolTabs != 1) 1045 if (cSymbolTabs != 1) 1015 1046 RTLDRMODMACHO_FAILED_RETURN(VERR_LDRMACHO_BAD_OBJECT_FILE); 1047 1048 cSymbols = u.pSymTab->nsyms; 1016 1049 break; 1017 1050 } 1018 1051 1019 1052 case LC_DYSYMTAB: 1020 /** @todo deal with this! */ 1053 { 1054 if (pHdr->filetype == MH_OBJECT) 1055 RTLDRMODMACHO_FAILED_RETURN(RTErrInfoSet(pErrInfo, VERR_LDRMACHO_BAD_OBJECT_FILE, 1056 "Not expecting LC_DYSYMTAB in MH_OBJECT")); 1057 if (fConvertEndian) 1058 { 1059 u.pDySymTab->ilocalsym = RT_BSWAP_U32(u.pDySymTab->ilocalsym); 1060 u.pDySymTab->nlocalsym = RT_BSWAP_U32(u.pDySymTab->nlocalsym); 1061 u.pDySymTab->iextdefsym = RT_BSWAP_U32(u.pDySymTab->iextdefsym); 1062 u.pDySymTab->nextdefsym = RT_BSWAP_U32(u.pDySymTab->nextdefsym); 1063 u.pDySymTab->iundefsym = RT_BSWAP_U32(u.pDySymTab->iundefsym); 1064 u.pDySymTab->nundefsym = RT_BSWAP_U32(u.pDySymTab->nundefsym); 1065 u.pDySymTab->tocoff = RT_BSWAP_U32(u.pDySymTab->tocoff); 1066 u.pDySymTab->ntoc = RT_BSWAP_U32(u.pDySymTab->ntoc); 1067 u.pDySymTab->modtaboff = RT_BSWAP_U32(u.pDySymTab->modtaboff); 1068 u.pDySymTab->nmodtab = RT_BSWAP_U32(u.pDySymTab->nmodtab); 1069 u.pDySymTab->extrefsymoff = RT_BSWAP_U32(u.pDySymTab->extrefsymoff); 1070 u.pDySymTab->nextrefsym = RT_BSWAP_U32(u.pDySymTab->nextrefsym); 1071 u.pDySymTab->indirectsymboff = RT_BSWAP_U32(u.pDySymTab->indirectsymboff); 1072 u.pDySymTab->nindirectsymb = RT_BSWAP_U32(u.pDySymTab->nindirectsymb); 1073 u.pDySymTab->extreloff = RT_BSWAP_U32(u.pDySymTab->extreloff); 1074 u.pDySymTab->nextrel = RT_BSWAP_U32(u.pDySymTab->nextrel); 1075 u.pDySymTab->locreloff = RT_BSWAP_U32(u.pDySymTab->locreloff); 1076 u.pDySymTab->nlocrel = RT_BSWAP_U32(u.pDySymTab->nlocrel); 1077 } 1078 1079 /* verify */ 1080 RTLDRMODMACHO_CHECK_RETURN((uint64_t)u.pDySymTab->ilocalsym + u.pDySymTab->nlocalsym <= cSymbols, 1081 RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND, 1082 "ilocalsym=%#x + nlocalsym=%#x vs cSymbols=%#x", 1083 u.pDySymTab->ilocalsym, u.pDySymTab->nlocalsym, cSymbols)); 1084 RTLDRMODMACHO_CHECK_RETURN((uint64_t)u.pDySymTab->iextdefsym + u.pDySymTab->nextdefsym <= cSymbols, 1085 RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND, 1086 "iextdefsym=%#x + nextdefsym=%#x vs cSymbols=%#x", 1087 u.pDySymTab->iextdefsym, u.pDySymTab->nextdefsym, cSymbols)); 1088 RTLDRMODMACHO_CHECK_RETURN((uint64_t)u.pDySymTab->iundefsym + u.pDySymTab->nundefsym <= cSymbols, 1089 RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND, 1090 "iundefsym=%#x + nundefsym=%#x vs cSymbols=%#x", 1091 u.pDySymTab->iundefsym, u.pDySymTab->nundefsym, cSymbols)); 1092 RTLDRMODMACHO_CHECK_RETURN( (uint64_t)u.pDySymTab->tocoff + u.pDySymTab->ntoc * sizeof(dylib_table_of_contents_t) 1093 <= cbFile, 1094 RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND, 1095 "tocoff=%#x + ntoc=%#x vs cbFile=%#RX64", 1096 u.pDySymTab->tocoff, u.pDySymTab->ntoc, cbFile)); 1097 const uint32_t cbModTabEntry = pHdr->magic == IMAGE_MACHO32_SIGNATURE 1098 || pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE 1099 ? sizeof(dylib_module_32_t) : sizeof(dylib_module_64_t); 1100 RTLDRMODMACHO_CHECK_RETURN((uint64_t)u.pDySymTab->modtaboff + u.pDySymTab->nmodtab * cbModTabEntry <= cbFile, 1101 RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND, 1102 "modtaboff=%#x + nmodtab=%#x cbModTabEntry=%#x vs cbFile=%#RX64", 1103 u.pDySymTab->modtaboff, u.pDySymTab->nmodtab, cbModTabEntry, cbFile)); 1104 RTLDRMODMACHO_CHECK_RETURN( (uint64_t)u.pDySymTab->extrefsymoff + u.pDySymTab->nextrefsym * sizeof(dylib_reference_t) 1105 <= cbFile, 1106 RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND, 1107 "extrefsymoff=%#x + nextrefsym=%#x vs cbFile=%#RX64", 1108 u.pDySymTab->extrefsymoff, u.pDySymTab->nextrefsym, cbFile)); 1109 RTLDRMODMACHO_CHECK_RETURN( (uint64_t)u.pDySymTab->indirectsymboff + u.pDySymTab->nindirectsymb * sizeof(uint32_t) 1110 <= cbFile, 1111 RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND, 1112 "indirectsymboff=%#x + nindirectsymb=%#x vs cbFile=%#RX64", 1113 u.pDySymTab->indirectsymboff, u.pDySymTab->nindirectsymb, cbFile)); 1114 RTLDRMODMACHO_CHECK_RETURN((uint64_t)u.pDySymTab->extreloff + u.pDySymTab->nextrel * sizeof(macho_relocation_info_t) <= cbFile, 1115 RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND, 1116 "extreloff=%#x + nextrel=%#x vs cbFile=%#RX64", 1117 u.pDySymTab->extreloff, u.pDySymTab->nextrel, cbFile)); 1118 RTLDRMODMACHO_CHECK_RETURN((uint64_t)u.pDySymTab->locreloff + u.pDySymTab->nlocrel * sizeof(macho_relocation_info_t) <= cbFile, 1119 RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND, 1120 "locreloff=%#x + nlocrel=%#x vs cbFile=%#RX64", 1121 u.pDySymTab->locreloff, u.pDySymTab->nlocrel, cbFile)); 1122 cDySymbolTabs++; 1123 fDySymbolTabWithRelocs |= (u.pDySymTab->nlocrel + u.pDySymTab->nextrel) != 0; 1021 1124 break; 1125 } 1022 1126 1023 1127 case LC_THREAD: … … 1098 1202 RTLDRMODMACHO_FAILED_RETURN(RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_UNSUPPORTED_LOAD_COMMAND, 1099 1203 "cmd=%#x", u.pLoadCmd->cmd)); 1204 Log(("ldrMachO: Can't load because of load command: %#x\n", u.pLoadCmd->cmd)); 1100 1205 *pfCanLoad = false; 1101 1206 break; … … 1128 1233 RTLDRMODMACHO_FAILED_RETURN(VERR_LDRMACHO_BAD_LOAD_COMMAND); 1129 1234 1235 RTLDRMODMACHO_CHECK_RETURN(cDySymbolTabs <= 1, 1236 RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND, 1237 "More than one LC_DYSYMTAB command: %u", cDySymbolTabs)); 1238 RTLDRMODMACHO_CHECK_RETURN(!fDySymbolTabWithRelocs || cSectionsWithRelocs == 0, 1239 RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND, 1240 "Have relocations both in sections and LC_DYSYMTAB")); 1241 if (!cSegments) 1242 RTLDRMODMACHO_FAILED_RETURN(VERR_LDRMACHO_BAD_OBJECT_FILE); 1243 1130 1244 switch (uEffFileType) 1131 1245 { 1132 1246 case MH_OBJECT: 1133 1247 case MH_EXECUTE: 1248 RTLDRMODMACHO_CHECK_RETURN(!fDySymbolTabWithRelocs, 1249 RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND, 1250 "Did not expect relocations in LC_DYSYMTAB (file type %u)", uEffFileType)); 1251 break; 1252 1134 1253 case MH_DYLIB: 1135 1254 case MH_BUNDLE: 1255 case MH_KEXT_BUNDLE: 1256 RTLDRMODMACHO_CHECK_RETURN(cDySymbolTabs > 0, 1257 RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND, 1258 "No LC_DYSYMTAB command (file type %u)", uEffFileType)); 1259 RTLDRMODMACHO_CHECK_RETURN(fDySymbolTabWithRelocs || cSectionsWithRelocs == 0, 1260 RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND, 1261 "Expected relocations in LC_DYSYMTAB (file type %u)", uEffFileType)); 1262 break; 1263 1136 1264 case MH_DSYM: 1137 case MH_KEXT_BUNDLE:1138 if (!cSegments)1139 RTLDRMODMACHO_FAILED_RETURN(VERR_LDRMACHO_BAD_OBJECT_FILE);1140 1265 break; 1141 1266 } 1142 1267 1268 /* 1269 * Set return values and return. 1270 */ 1143 1271 *pcSegments = cSegments; 1144 1272 *pcSections = cSections; … … 1201 1329 /* Adds a segment, used by the macro below and thus shared with the 64-bit segment variant. */ 1202 1330 #define NEW_SEGMENT(a_cBits, a_achName1, a_fObjFile, a_achName2, a_SegAddr, a_cbSeg, a_fFileBits, a_offFile, a_cbFile) \ 1203 do { \1204 pDstSeg->SegInfo.pszName = pbStringPool; \1205 pDstSeg->SegInfo.cchName = (uint32_t)RTStrNLen(a_achName1, sizeof(a_achName1)); \1206 memcpy(pbStringPool, a_achName1, pDstSeg->SegInfo.cchName); \1207 pbStringPool += pDstSeg->SegInfo.cchName; \1208 if (a_fObjFile) \1209 { /* MH_OBJECT: Add '.sectname' - sections aren't sorted by segments. */ \1210 size_t cchName2 = RTStrNLen(a_achName2, sizeof(a_achName2)); \1211 *pbStringPool++ = '.'; \1212 memcpy(pbStringPool, a_achName2, cchName2); \1213 pbStringPool += cchName2; \1214 pDstSeg->SegInfo.cchName += (uint32_t)cchName2; \1215 } \1216 *pbStringPool++ = '\0'; \1217 pDstSeg->SegInfo.SelFlat = 0; \1218 pDstSeg->SegInfo.Sel16bit = 0; \1219 pDstSeg->SegInfo.fFlags = 0; \1220 pDstSeg->SegInfo.fProt = RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC; /** @todo fixme! */ \1221 pDstSeg->SegInfo.cb = (a_cbSeg); \1222 pDstSeg->SegInfo.Alignment = 1; /* updated while parsing sections. */ \1223 pDstSeg->SegInfo.LinkAddress = (a_SegAddr); \1224 if (a_fFileBits) \1225 { \1226 pDstSeg->SegInfo.offFile = (RTFOFF)((a_offFile) + pThis->offImage); \1227 pDstSeg->SegInfo.cbFile = (RTFOFF)(a_cbFile); \1228 } \1229 else \1230 { \1231 pDstSeg->SegInfo.offFile = -1; \1232 pDstSeg->SegInfo.cbFile = -1; \1233 } \1234 pDstSeg->SegInfo.RVA = (a_SegAddr) - pThis->LinkAddress; \1235 pDstSeg->SegInfo.cbMapped = 0; \1236 \1237 pDstSeg->iOrgSegNo = (uint32_t)(pDstSeg - &pThis->aSegments[0]); \1238 pDstSeg->cSections = 0; \1239 pDstSeg->paSections = pSectExtra; \1240 } while (0)1241 1242 /* Closes the new segment - part of NEW_SEGMENT. */1331 do { \ 1332 pDstSeg->SegInfo.pszName = pbStringPool; \ 1333 pDstSeg->SegInfo.cchName = (uint32_t)RTStrNLen(a_achName1, sizeof(a_achName1)); \ 1334 memcpy(pbStringPool, a_achName1, pDstSeg->SegInfo.cchName); \ 1335 pbStringPool += pDstSeg->SegInfo.cchName; \ 1336 if (a_fObjFile) \ 1337 { /* MH_OBJECT: Add '.sectname' - sections aren't sorted by segments. */ \ 1338 size_t cchName2 = RTStrNLen(a_achName2, sizeof(a_achName2)); \ 1339 *pbStringPool++ = '.'; \ 1340 memcpy(pbStringPool, a_achName2, cchName2); \ 1341 pbStringPool += cchName2; \ 1342 pDstSeg->SegInfo.cchName += (uint32_t)cchName2; \ 1343 } \ 1344 *pbStringPool++ = '\0'; \ 1345 pDstSeg->SegInfo.SelFlat = 0; \ 1346 pDstSeg->SegInfo.Sel16bit = 0; \ 1347 pDstSeg->SegInfo.fFlags = 0; \ 1348 pDstSeg->SegInfo.fProt = RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC; /** @todo fixme! */ \ 1349 pDstSeg->SegInfo.cb = (a_cbSeg); \ 1350 pDstSeg->SegInfo.Alignment = 1; /* updated while parsing sections. */ \ 1351 pDstSeg->SegInfo.LinkAddress = (a_SegAddr); \ 1352 if (a_fFileBits) \ 1353 { \ 1354 pDstSeg->SegInfo.offFile = (RTFOFF)((a_offFile) + pThis->offImage); \ 1355 pDstSeg->SegInfo.cbFile = (RTFOFF)(a_cbFile); \ 1356 } \ 1357 else \ 1358 { \ 1359 pDstSeg->SegInfo.offFile = -1; \ 1360 pDstSeg->SegInfo.cbFile = -1; \ 1361 } \ 1362 pDstSeg->SegInfo.RVA = (a_SegAddr) - pThis->LinkAddress; \ 1363 pDstSeg->SegInfo.cbMapped = 0; \ 1364 \ 1365 pDstSeg->iOrgSegNo = (uint32_t)(pDstSeg - &pThis->aSegments[0]); \ 1366 pDstSeg->cSections = 0; \ 1367 pDstSeg->paSections = pSectExtra; \ 1368 } while (0) 1369 1370 /* Closes the new segment - part of NEW_SEGMENT. */ 1243 1371 #define CLOSE_SEGMENT() \ 1244 do { \1245 pDstSeg->cSections = (uint32_t)(pSectExtra - pDstSeg->paSections); \1246 pDstSeg++; \1247 } while (0)1248 1249 1250 /* Shared with the 64-bit variant. */1372 do { \ 1373 pDstSeg->cSections = (uint32_t)(pSectExtra - pDstSeg->paSections); \ 1374 pDstSeg++; \ 1375 } while (0) 1376 1377 1378 /* Shared with the 64-bit variant. */ 1251 1379 #define ADD_SEGMENT_AND_ITS_SECTIONS(a_cBits) \ 1252 do { \ 1253 bool fAddSegOuter = false; \ 1254 \ 1255 /* \ 1256 * Check that the segment name is unique. We couldn't do that \ 1257 * in the preparsing stage. \ 1258 */ \ 1259 if (pThis->uEffFileType != MH_OBJECT) \ 1260 for (pSegItr = &pThis->aSegments[0]; pSegItr != pDstSeg; pSegItr++) \ 1261 if (!strncmp(pSegItr->SegInfo.pszName, pSrcSeg->segname, sizeof(pSrcSeg->segname))) \ 1262 RTLDRMODMACHO_FAILED_RETURN(VERR_LDR_DUPLICATE_SEGMENT_NAME); \ 1263 \ 1264 /* \ 1265 * Create a new segment, unless we're supposed to skip this one. \ 1266 */ \ 1267 if ( pThis->uEffFileType != MH_OBJECT \ 1268 && (cSectionsLeft == 0 || !(pFirstSect->flags & S_ATTR_DEBUG)) \ 1269 && strcmp(pSrcSeg->segname, "__DWARF") \ 1270 && strcmp(pSrcSeg->segname, "__CTF") ) \ 1271 { \ 1272 NEW_SEGMENT(a_cBits, pSrcSeg->segname, false /*a_fObjFile*/, "" /*a_achName2*/, \ 1273 pSrcSeg->vmaddr, pSrcSeg->vmsize, \ 1274 pSrcSeg->filesize != 0, pSrcSeg->fileoff, pSrcSeg->filesize); \ 1275 fAddSegOuter = true; \ 1276 } \ 1277 \ 1278 /* \ 1279 * Convert and parse the sections. \ 1280 */ \ 1281 while (cSectionsLeft-- > 0) \ 1282 { \ 1283 /* New segment if object file. */ \ 1284 bool fAddSegInner = false; \ 1285 if ( pThis->uEffFileType == MH_OBJECT \ 1286 && !(pSect->flags & S_ATTR_DEBUG) \ 1287 && strcmp(pSrcSeg->segname, "__DWARF") \ 1288 && strcmp(pSrcSeg->segname, "__CTF") ) \ 1289 { \ 1290 Assert(!fAddSegOuter); \ 1291 NEW_SEGMENT(a_cBits, pSect->segname, true /*a_fObjFile*/, pSect->sectname, \ 1292 pSect->addr, pSect->size, \ 1293 pSect->offset != 0, pSect->offset, pSect->size); \ 1294 fAddSegInner = true; \ 1295 } \ 1296 \ 1297 /* Section data extract. */ \ 1298 pSectExtra->cb = pSect->size; \ 1299 pSectExtra->RVA = pSect->addr - pDstSeg->SegInfo.LinkAddress; \ 1300 pSectExtra->LinkAddress = pSect->addr; \ 1301 if (pSect->offset) \ 1302 pSectExtra->offFile = pSect->offset + pThis->offImage; \ 1303 else \ 1304 pSectExtra->offFile = -1; \ 1305 pSectExtra->cFixups = pSect->nreloc; \ 1306 pSectExtra->paFixups = NULL; \ 1307 if (pSect->nreloc) \ 1308 pSectExtra->offFixups = pSect->reloff + pThis->offImage; \ 1309 else \ 1310 pSectExtra->offFixups = -1; \ 1311 pSectExtra->fFlags = pSect->flags; \ 1312 pSectExtra->iSegment = (uint32_t)(pDstSeg - &pThis->aSegments[0]); \ 1313 pSectExtra->pvMachoSection = pSect; \ 1314 \ 1315 /* Update the segment alignment, if we're not skipping it. */ \ 1316 if ( (fAddSegOuter || fAddSegInner) \ 1317 && pDstSeg->SegInfo.Alignment < ((RTLDRADDR)1 << pSect->align)) \ 1318 pDstSeg->SegInfo.Alignment = (RTLDRADDR)1 << pSect->align; \ 1319 \ 1320 /* Next section, and if object file next segment. */ \ 1321 pSectExtra++; \ 1322 pSect++; \ 1323 if (fAddSegInner) \ 1324 CLOSE_SEGMENT(); \ 1325 } \ 1326 \ 1327 /* Close the segment and advance. */ \ 1328 if (fAddSegOuter) \ 1329 CLOSE_SEGMENT(); \ 1330 \ 1331 /* Take down 'execSeg' info for signing */ \ 1332 if (fFirstSeg) \ 1333 { \ 1334 fFirstSeg = false; \ 1335 pThis->offSeg0ForCodeSign = pSrcSeg->fileoff; \ 1336 pThis->cbSeg0ForCodeSign = pSrcSeg->filesize; /** @todo file or vm size? */ \ 1337 pThis->fSeg0ForCodeSign = pSrcSeg->flags; \ 1338 } \ 1339 } while (0) /* ADD_SEGMENT_AND_ITS_SECTIONS */ 1380 do { \ 1381 bool fAddSegOuter = false; \ 1382 \ 1383 /* \ 1384 * Check that the segment name is unique. We couldn't do that \ 1385 * in the preparsing stage. \ 1386 */ \ 1387 if (pThis->uEffFileType != MH_OBJECT) \ 1388 for (pSegItr = &pThis->aSegments[0]; pSegItr != pDstSeg; pSegItr++) \ 1389 if (!strncmp(pSegItr->SegInfo.pszName, pSrcSeg->segname, sizeof(pSrcSeg->segname))) \ 1390 RTLDRMODMACHO_FAILED_RETURN(VERR_LDR_DUPLICATE_SEGMENT_NAME); \ 1391 \ 1392 /* \ 1393 * Create a new segment, unless we're supposed to skip this one. \ 1394 */ \ 1395 if ( pThis->uEffFileType != MH_OBJECT \ 1396 && (cSectionsLeft == 0 || !(pFirstSect->flags & S_ATTR_DEBUG)) \ 1397 && strcmp(pSrcSeg->segname, "__DWARF") \ 1398 && strcmp(pSrcSeg->segname, "__CTF") ) \ 1399 { \ 1400 NEW_SEGMENT(a_cBits, pSrcSeg->segname, false /*a_fObjFile*/, "" /*a_achName2*/, \ 1401 pSrcSeg->vmaddr, pSrcSeg->vmsize, \ 1402 pSrcSeg->filesize != 0, pSrcSeg->fileoff, pSrcSeg->filesize); \ 1403 fAddSegOuter = true; \ 1404 } \ 1405 \ 1406 /* \ 1407 * Convert and parse the sections. \ 1408 */ \ 1409 while (cSectionsLeft-- > 0) \ 1410 { \ 1411 /* New segment if object file. */ \ 1412 bool fAddSegInner = false; \ 1413 if ( pThis->uEffFileType == MH_OBJECT \ 1414 && !(pSect->flags & S_ATTR_DEBUG) \ 1415 && strcmp(pSrcSeg->segname, "__DWARF") \ 1416 && strcmp(pSrcSeg->segname, "__CTF") ) \ 1417 { \ 1418 Assert(!fAddSegOuter); \ 1419 NEW_SEGMENT(a_cBits, pSect->segname, true /*a_fObjFile*/, pSect->sectname, \ 1420 pSect->addr, pSect->size, \ 1421 pSect->offset != 0, pSect->offset, pSect->size); \ 1422 fAddSegInner = true; \ 1423 } \ 1424 \ 1425 /* Section data extract. */ \ 1426 pSectExtra->cb = pSect->size; \ 1427 pSectExtra->RVA = pSect->addr - pDstSeg->SegInfo.LinkAddress; \ 1428 pSectExtra->LinkAddress = pSect->addr; \ 1429 if (pSect->offset) \ 1430 pSectExtra->offFile = pSect->offset + pThis->offImage; \ 1431 else \ 1432 pSectExtra->offFile = -1; \ 1433 pSectExtra->cFixups = pSect->nreloc; \ 1434 pSectExtra->paFixups = NULL; \ 1435 pSectExtra->pauFixupVirginData = NULL; \ 1436 if (pSect->nreloc) \ 1437 pSectExtra->offFixups = pSect->reloff + pThis->offImage; \ 1438 else \ 1439 pSectExtra->offFixups = -1; \ 1440 pSectExtra->fFlags = pSect->flags; \ 1441 pSectExtra->iSegment = (uint32_t)(pDstSeg - &pThis->aSegments[0]); \ 1442 pSectExtra->pvMachoSection = pSect; \ 1443 \ 1444 /* Update the segment alignment, if we're not skipping it. */ \ 1445 if ( (fAddSegOuter || fAddSegInner) \ 1446 && pDstSeg->SegInfo.Alignment < ((RTLDRADDR)1 << pSect->align)) \ 1447 pDstSeg->SegInfo.Alignment = (RTLDRADDR)1 << pSect->align; \ 1448 \ 1449 /* Next section, and if object file next segment. */ \ 1450 pSectExtra++; \ 1451 pSect++; \ 1452 if (fAddSegInner) \ 1453 CLOSE_SEGMENT(); \ 1454 } \ 1455 \ 1456 /* Close the segment and advance. */ \ 1457 if (fAddSegOuter) \ 1458 CLOSE_SEGMENT(); \ 1459 \ 1460 /* Take down 'execSeg' info for signing */ \ 1461 if (fFirstSeg) \ 1462 { \ 1463 fFirstSeg = false; \ 1464 pThis->offSeg0ForCodeSign = pSrcSeg->fileoff; \ 1465 pThis->cbSeg0ForCodeSign = pSrcSeg->filesize; /** @todo file or vm size? */ \ 1466 pThis->fSeg0ForCodeSign = pSrcSeg->flags; \ 1467 } \ 1468 } while (0) /* ADD_SEGMENT_AND_ITS_SECTIONS */ 1340 1469 1341 1470 ADD_SEGMENT_AND_ITS_SECTIONS(32); … … 1359 1488 case MH_OBJECT: 1360 1489 case MH_EXECUTE: 1361 case MH_DYLIB: /** @todo ??? */1362 case MH_BUNDLE: /** @todo ??? */1490 case MH_DYLIB: 1491 case MH_BUNDLE: 1363 1492 case MH_DSYM: 1364 1493 case MH_KEXT_BUNDLE: … … 1369 1498 break; 1370 1499 } 1500 break; 1501 1502 case LC_DYSYMTAB: 1503 pThis->pDySymTab = (dysymtab_command_t *)u.pb; 1371 1504 break; 1372 1505 … … 1539 1672 RTMemFree(pThis->aSegments[i].paSections[j].paFixups); 1540 1673 pThis->aSegments[i].paSections[j].paFixups = NULL; 1674 RTMemFree(pThis->aSegments[i].paSections[j].pauFixupVirginData); 1675 pThis->aSegments[i].paSections[j].pauFixupVirginData = NULL; 1541 1676 } 1542 1677 } … … 1548 1683 RTMemFree(pThis->pvaSymbols); 1549 1684 pThis->pvaSymbols = NULL; 1685 RTMemFree(pThis->paidxIndirectSymbols); 1686 pThis->paidxIndirectSymbols = NULL; 1687 RTMemFree(pThis->paRelocations); 1688 pThis->paRelocations = NULL; 1689 RTMemFree(pThis->pauRelocationsVirginData); 1690 pThis->pauRelocationsVirginData = NULL; 1550 1691 RTMemFree(pThis->PtrCodeSignature.pb); 1551 1692 pThis->PtrCodeSignature.pb = NULL; … … 2630 2771 #endif 2631 2772 2773 2774 /** 2775 * Worker for resolving an undefined 32-bit symbol table entry. 2776 * 2777 * @returns IPRT status code. 2778 * @param pThis The Mach-O module interpreter instance. 2779 * @param pSym The symbol table entry. 2780 * @param BaseAddress The module base address. 2781 * @param pfnGetImport The callback for resolving an imported symbol. 2782 * @param pvUser User argument to the callback. 2783 */ 2784 DECLINLINE(int) rtdlrModMachOHandleUndefinedSymbol32(PRTLDRMODMACHO pThis, macho_nlist_32_t *pSym, 2785 RTLDRADDR BaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser) 2786 { 2787 RTLDRADDR Value = NIL_RTLDRADDR; 2788 2789 /** @todo Implement N_REF_TO_WEAK. */ 2790 RTLDRMODMACHO_CHECK_RETURN(!(pSym->n_desc & N_REF_TO_WEAK), VERR_LDRMACHO_TODO); 2791 2792 /* Get the symbol name. */ 2793 RTLDRMODMACHO_CHECK_RETURN((uint32_t)pSym->n_un.n_strx < pThis->cchStrings, VERR_LDRMACHO_BAD_SYMBOL); 2794 const char *pszSymbol = &pThis->pchStrings[pSym->n_un.n_strx]; 2795 size_t cchSymbol = strlen(pszSymbol); 2796 2797 /* Check for linker defined symbols relating to sections and segments. */ 2798 int rc; 2799 if ( cchSymbol <= sizeof("section$end$") - 1 2800 || *pszSymbol != 's' 2801 || memchr(pszSymbol, '$', cchSymbol) == NULL) 2802 rc = VERR_SYMBOL_NOT_FOUND; 2803 else 2804 rc = kldrModMachOQueryLinkerSymbol(pThis, pszSymbol, cchSymbol, BaseAddress, &Value); 2805 2806 /* Ask the user for an address to the symbol. */ 2807 //uint32_t fKind = RTLDRSYMKIND_REQ_FLAT; 2808 /** @todo figure out a better way to deal with underscore prefixes. sigh. */ 2809 if (RT_FAILURE_NP(rc)) 2810 rc = pfnGetImport(&pThis->Core, NULL /*pszModule*/, pszSymbol + (pszSymbol[0] == '_'), 2811 UINT32_MAX, &Value/*, &fKind*/, pvUser); 2812 if (RT_SUCCESS(rc)) 2813 { /* likely */ } 2814 /* If weak reference we can continue, otherwise fail? */ 2815 else if (pSym->n_desc & N_WEAK_REF) 2816 Value = 0; 2817 else 2818 return rc; 2819 2820 /* Update the symbol. */ 2821 pSym->n_value = (uint32_t)Value; 2822 if (pSym->n_value == Value) 2823 return VINF_SUCCESS; 2824 return VERR_LDR_ADDRESS_OVERFLOW; 2825 } 2826 2827 2828 /** 2829 * Worker for resolving an undefined 64-bit symbol table entry. 2830 * 2831 * @returns IPRT status code. 2832 * @param pThis The Mach-O module interpreter instance. 2833 * @param pSym The symbol table entry. 2834 * @param BaseAddress The module base address. 2835 * @param pfnGetImport The callback for resolving an imported symbol. 2836 * @param pvUser User argument to the callback. 2837 */ 2838 DECLINLINE(int) rtdlrModMachOHandleUndefinedSymbol64(PRTLDRMODMACHO pThis, macho_nlist_64_t *pSym, 2839 RTLDRADDR BaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser) 2840 { 2841 RTLDRADDR Value = NIL_RTLDRADDR; 2842 2843 /** @todo Implement N_REF_TO_WEAK. */ 2844 RTLDRMODMACHO_CHECK_RETURN(!(pSym->n_desc & N_REF_TO_WEAK), VERR_LDRMACHO_TODO); 2845 2846 /* Get the symbol name. */ 2847 RTLDRMODMACHO_CHECK_RETURN((uint32_t)pSym->n_un.n_strx < pThis->cchStrings, VERR_LDRMACHO_BAD_SYMBOL); 2848 const char *pszSymbol = &pThis->pchStrings[pSym->n_un.n_strx]; 2849 size_t cchSymbol = strlen(pszSymbol); 2850 2851 /* Check for linker defined symbols relating to sections and segments. */ 2852 int rc; 2853 if ( cchSymbol <= sizeof("section$end$") - 1 2854 || *pszSymbol != 's' 2855 || memchr(pszSymbol, '$', cchSymbol) == NULL) 2856 rc = VERR_SYMBOL_NOT_FOUND; 2857 else 2858 rc = kldrModMachOQueryLinkerSymbol(pThis, pszSymbol, cchSymbol, BaseAddress, &Value); 2859 2860 /* Ask the user for an address to the symbol. */ 2861 //uint32_t fKind = RTLDRSYMKIND_REQ_FLAT; 2862 /** @todo figure out a better way to deal with underscore prefixes. sigh. */ 2863 if (RT_FAILURE_NP(rc)) 2864 rc = pfnGetImport(&pThis->Core, NULL /*pszModule*/, pszSymbol + (pszSymbol[0] == '_'), 2865 UINT32_MAX, &Value/*, &fKind*/, pvUser); 2866 if (RT_SUCCESS(rc)) 2867 { /* likely */ } 2868 /* If weak reference we can continue, otherwise fail? */ 2869 else if (pSym->n_desc & N_WEAK_REF) 2870 Value = 0; 2871 else 2872 return rc; 2873 2874 /* Update the symbol. */ 2875 pSym->n_value = (uint64_t)Value; 2876 if (pSym->n_value == Value) 2877 return VINF_SUCCESS; 2878 return VERR_LDR_ADDRESS_OVERFLOW; 2879 } 2880 2881 2632 2882 /** 2633 2883 * MH_OBJECT: Resolves undefined symbols (imports). … … 2641 2891 static int kldrModMachOObjDoImports(PRTLDRMODMACHO pThis, RTLDRADDR BaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser) 2642 2892 { 2643 const uint32_t cSyms = pThis->cSymbols; 2644 uint32_t iSym; 2645 2646 /* 2647 * Ensure that we've got the symbol table and section fixups handy. 2893 2894 /* 2895 * Ensure that we've got the symbol table. 2648 2896 */ 2649 2897 int rc = kldrModMachOLoadObjSymTab(pThis); … … 2655 2903 * We currently ignore REFERENCE_TYPE. 2656 2904 */ 2905 const uint32_t cSyms = pThis->cSymbols; 2657 2906 if ( pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE 2658 2907 || pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) 2659 2908 { 2660 2909 macho_nlist_32_t *paSyms = (macho_nlist_32_t *)pThis->pvaSymbols; 2661 for ( iSym = 0; iSym < cSyms; iSym++)2910 for (uint32_t iSym = 0; iSym < cSyms; iSym++) 2662 2911 { 2663 2912 /* skip stabs */ … … 2667 2916 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) 2668 2917 { 2669 const char *pszSymbol; 2670 size_t cchSymbol; 2671 //uint32_t fKind = RTLDRSYMKIND_REQ_FLAT; 2672 RTLDRADDR Value = NIL_RTLDRADDR; 2673 2674 /** @todo Implement N_REF_TO_WEAK. */ 2675 RTLDRMODMACHO_CHECK_RETURN(!(paSyms[iSym].n_desc & N_REF_TO_WEAK), VERR_LDRMACHO_TODO); 2676 2677 /* Get the symbol name. */ 2678 RTLDRMODMACHO_CHECK_RETURN((uint32_t)paSyms[iSym].n_un.n_strx < pThis->cchStrings, VERR_LDRMACHO_BAD_SYMBOL); 2679 pszSymbol = &pThis->pchStrings[paSyms[iSym].n_un.n_strx]; 2680 cchSymbol = strlen(pszSymbol); 2681 2682 /* Check for linker defined symbols relating to sections and segments. */ 2683 if ( cchSymbol > sizeof("section$end$") - 1 2684 && *pszSymbol == 's' 2685 && memchr(pszSymbol, '$', cchSymbol)) 2686 rc = kldrModMachOQueryLinkerSymbol(pThis, pszSymbol, cchSymbol, BaseAddress, &Value); 2687 else 2688 rc = VERR_SYMBOL_NOT_FOUND; 2689 2690 /* Ask the user for an address to the symbol. */ 2691 /** @todo figure out a better way to deal with underscore prefixes. sigh. */ 2692 if (RT_FAILURE_NP(rc)) 2693 rc = pfnGetImport(&pThis->Core, NULL /*pszModule*/, pszSymbol + (pszSymbol[0] == '_'), 2694 UINT32_MAX, &Value/*, &fKind*/, pvUser); 2918 rc = rtdlrModMachOHandleUndefinedSymbol32(pThis, &paSyms[iSym], BaseAddress, pfnGetImport, pvUser); 2695 2919 if (RT_FAILURE(rc)) 2696 {2697 /* weak reference? */2698 if (!(paSyms[iSym].n_desc & N_WEAK_REF))2699 break;2700 Value = 0;2701 }2702 2703 /* Update the symbol. */2704 paSyms[iSym].n_value = (uint32_t)Value;2705 if (paSyms[iSym].n_value != Value)2706 {2707 rc = VERR_LDR_ADDRESS_OVERFLOW;2708 2920 break; 2709 }2710 2921 } 2711 2922 else if (paSyms[iSym].n_desc & N_WEAK_DEF) … … 2720 2931 /* (Identical to the 32-bit code, just different paSym type. (and n_strx is unsigned)) */ 2721 2932 macho_nlist_64_t *paSyms = (macho_nlist_64_t *)pThis->pvaSymbols; 2722 for ( iSym = 0; iSym < cSyms; iSym++)2933 for (uint32_t iSym = 0; iSym < cSyms; iSym++) 2723 2934 { 2724 2935 /* skip stabs */ … … 2728 2939 if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) 2729 2940 { 2730 const char *pszSymbol; 2731 size_t cchSymbol; 2732 //uint32_t fKind = RTLDRSYMKIND_REQ_FLAT; 2733 RTLDRADDR Value = NIL_RTLDRADDR; 2734 2735 /** @todo Implement N_REF_TO_WEAK. */ 2736 RTLDRMODMACHO_CHECK_RETURN(!(paSyms[iSym].n_desc & N_REF_TO_WEAK), VERR_LDRMACHO_TODO); 2737 2738 /* Get the symbol name. */ 2739 RTLDRMODMACHO_CHECK_RETURN(paSyms[iSym].n_un.n_strx < pThis->cchStrings, VERR_LDRMACHO_BAD_SYMBOL); 2740 pszSymbol = &pThis->pchStrings[paSyms[iSym].n_un.n_strx]; 2741 cchSymbol = strlen(pszSymbol); 2742 2743 /* Check for linker defined symbols relating to sections and segments. */ 2744 if ( cchSymbol > sizeof("section$end$") - 1 2745 && *pszSymbol == 's' 2746 && memchr(pszSymbol, '$', cchSymbol)) 2747 rc = kldrModMachOQueryLinkerSymbol(pThis, pszSymbol, cchSymbol, BaseAddress, &Value); 2748 else 2749 rc = VERR_SYMBOL_NOT_FOUND; 2750 2751 /* Ask the user for an address to the symbol. */ 2752 /** @todo figure out a better way to deal with underscore prefixes. sigh. */ 2753 if (RT_FAILURE_NP(rc)) 2754 rc = pfnGetImport(&pThis->Core, NULL, pszSymbol + (*pszSymbol == '_'), 2755 UINT32_MAX, &Value, /*&fKind,*/ pvUser); 2941 rc = rtdlrModMachOHandleUndefinedSymbol64(pThis, &paSyms[iSym], BaseAddress, pfnGetImport, pvUser); 2756 2942 if (RT_FAILURE(rc)) 2757 {2758 /* weak reference? */2759 if (!(paSyms[iSym].n_desc & N_WEAK_REF))2760 break;2761 Value = 0;2762 }2763 2764 /* Update the symbol. */2765 paSyms[iSym].n_value = Value;2766 if (paSyms[iSym].n_value != Value)2767 {2768 rc = VERR_LDR_ADDRESS_OVERFLOW;2769 2943 break; 2770 }2771 2944 } 2772 2945 else if (paSyms[iSym].n_desc & N_WEAK_DEF) … … 2783 2956 2784 2957 /** 2785 * MH_OBJECT: Applies base relocations to a (unprotected) image mapping. 2958 * Dylib: Resolves undefined symbols (imports). 2959 * 2960 * This is conceptually identically to kldrModMachOObjDoImports, only 2961 * LC_DYSYMTAB helps us avoid working over the whole symbol table. 2962 * 2963 * @returns IPRT status code. 2964 * @param pThis The Mach-O module interpreter instance. 2965 * @param BaseAddress The module base address. 2966 * @param pfnGetImport The callback for resolving an imported symbol. 2967 * @param pvUser User argument to the callback. 2968 */ 2969 static int kldrModMachODylibDoImports(PRTLDRMODMACHO pThis, RTLDRADDR BaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser) 2970 { 2971 /* 2972 * There must be a LC_DYSYMTAB. 2973 * We might be lucky, though, and not have any imports. 2974 */ 2975 dysymtab_command_t const *pDySymTab = pThis->pDySymTab; 2976 AssertReturn(pDySymTab, VERR_INTERNAL_ERROR_2); 2977 if (pDySymTab->nundefsym == 0) 2978 return VINF_SUCCESS; 2979 2980 /* 2981 * Ensure that we've got the symbol table. 2982 */ 2983 int rc = kldrModMachOLoadObjSymTab(pThis); 2984 if (RT_FAILURE(rc)) 2985 return rc; 2986 2987 /* 2988 * Iterate the give symbol table section containing undefined symbols and resolve them. 2989 */ 2990 uint32_t const cSyms = pDySymTab->iundefsym + pDySymTab->nundefsym; 2991 if ( pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE 2992 || pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) 2993 { 2994 macho_nlist_32_t *paSyms = (macho_nlist_32_t *)pThis->pvaSymbols; 2995 for (uint32_t iSym = pDySymTab->iundefsym; RT_SUCCESS(rc) && iSym < cSyms; iSym++) 2996 { 2997 AssertContinue((paSyms[iSym].n_type & (MACHO_N_TYPE | MACHO_N_STAB)) == MACHO_N_UNDF); 2998 rc = rtdlrModMachOHandleUndefinedSymbol32(pThis, &paSyms[iSym], BaseAddress, pfnGetImport, pvUser); 2999 } 3000 } 3001 else 3002 { 3003 /* (Identical to the 32-bit code, just different paSym type. (and n_strx is unsigned)) */ 3004 macho_nlist_64_t *paSyms = (macho_nlist_64_t *)pThis->pvaSymbols; 3005 for (uint32_t iSym = pDySymTab->iundefsym; RT_SUCCESS(rc) && iSym < cSyms; iSym++) 3006 { 3007 AssertContinue((paSyms[iSym].n_type & (MACHO_N_TYPE | MACHO_N_STAB)) == MACHO_N_UNDF); 3008 rc = rtdlrModMachOHandleUndefinedSymbol64(pThis, &paSyms[iSym], BaseAddress, pfnGetImport, pvUser); 3009 } 3010 } 3011 3012 return rc; 3013 } 3014 3015 3016 static int kldrModMachODylibDoIndirectSymbols(PRTLDRMODMACHO pThis, void *pvBits, RTLDRADDR offDelta) 3017 { 3018 /* 3019 * There must be a LC_DYSYMTAB. 3020 * We might be lucky, though, and not have any imports. 3021 */ 3022 dysymtab_command_t const *pDySymTab = pThis->pDySymTab; 3023 AssertReturn(pDySymTab, VERR_INTERNAL_ERROR_2); 3024 uint32_t const cIndirectSymbols = pDySymTab->nindirectsymb; 3025 if (cIndirectSymbols == 0) 3026 return VINF_SUCCESS; 3027 3028 /* 3029 * Ensure that we've got the symbol table. 3030 */ 3031 int rc = kldrModMachOLoadObjSymTab(pThis); 3032 if (RT_FAILURE(rc)) 3033 return rc; 3034 3035 /* 3036 * Load the indirect symbol table. 3037 */ 3038 if (!pThis->paidxIndirectSymbols) 3039 { 3040 uint32_t *paidxIndirectSymbols = (uint32_t *)RTMemAlloc(cIndirectSymbols * sizeof(uint32_t)); 3041 if (!paidxIndirectSymbols) 3042 return VERR_NO_MEMORY; 3043 rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, paidxIndirectSymbols, cIndirectSymbols * sizeof(uint32_t), 3044 pDySymTab->indirectsymboff); 3045 if (RT_SUCCESS(rc)) 3046 pThis->paidxIndirectSymbols = paidxIndirectSymbols; 3047 else 3048 { 3049 RTMemFree(paidxIndirectSymbols); 3050 return rc; 3051 } 3052 3053 /* Byte swap if needed. */ 3054 if ( pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE 3055 || pThis->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE) 3056 for (uint32_t i = 0; i < cIndirectSymbols; i++) 3057 paidxIndirectSymbols[i] = RT_BSWAP_U32(paidxIndirectSymbols[i]); 3058 } 3059 uint32_t const *paidxIndirectSymbols = pThis->paidxIndirectSymbols; 3060 3061 /* 3062 * Process the sections using indirect symbols. 3063 */ 3064 const uint32_t cSymbols = pThis->cSymbols; 3065 if ( pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE 3066 || pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) 3067 { 3068 macho_nlist_32_t const *paSymbols = (macho_nlist_32_t *)pThis->pvaSymbols; 3069 for (uint32_t iSect = 0; iSect < pThis->cSections; iSect++) 3070 { 3071 section_32_t const *pSect = (section_32_t const *)pThis->paSections[iSect].pvMachoSection; 3072 switch (pSect->flags & SECTION_TYPE) 3073 { 3074 case S_NON_LAZY_SYMBOL_POINTERS: 3075 case S_LAZY_SYMBOL_POINTERS: 3076 { 3077 uint32_t *pauDstPtrs = (uint32_t *)((uintptr_t)pvBits + pThis->paSections[iSect].RVA); 3078 uint32_t const cDstPtrs = pThis->paSections[iSect].cb / sizeof(pauDstPtrs[0]); 3079 uint32_t const idxSrcSkip = pSect->reserved1; 3080 if ((uint64_t)idxSrcSkip + cDstPtrs > cIndirectSymbols) 3081 return VERR_BAD_EXE_FORMAT; /// @todo better error code. 3082 3083 for (uint32_t i = 0; i < cDstPtrs; i++) 3084 { 3085 uint32_t const idxSym = paidxIndirectSymbols[idxSrcSkip + i]; 3086 if (idxSym == INDIRECT_SYMBOL_LOCAL) 3087 pauDstPtrs[i] += (int32_t)offDelta; 3088 else if (idxSym != INDIRECT_SYMBOL_ABS) 3089 { 3090 AssertMsgReturn(idxSym < cSymbols, 3091 ("i=%#x idxSym=%#x cSymbols=%#x iSect=%#x\n", i, idxSym, cSymbols, iSect), 3092 VERR_BAD_EXE_FORMAT); /// @todo better error code. 3093 pauDstPtrs[i] = paSymbols[idxSym].n_value; 3094 } 3095 } 3096 break; 3097 } 3098 3099 case S_SYMBOL_STUBS: 3100 if ( pThis->Core.enmArch == RTLDRARCH_X86_32 3101 && (pSect->flags & S_ATTR_SELF_MODIFYING_CODE) 3102 && pSect->reserved2 == 5) 3103 { 3104 uint32_t uDstRva = pThis->paSections[iSect].RVA; 3105 uint8_t *pbDst = (uint8_t *)((uintptr_t)pvBits + uDstRva); 3106 uint32_t const cDstPtrs = pThis->paSections[iSect].cb / 5; 3107 uint32_t const idxSrcSkip = pSect->reserved1; 3108 if ((uint64_t)idxSrcSkip + cDstPtrs > cIndirectSymbols) 3109 return VERR_BAD_EXE_FORMAT; /// @todo better error code. 3110 3111 for (uint32_t i = 0; i < cDstPtrs; i++, uDstRva += 5, pbDst += 5) 3112 { 3113 uint32_t const idxSym = paidxIndirectSymbols[idxSrcSkip + i]; 3114 if (idxSym != INDIRECT_SYMBOL_ABS && idxSym != INDIRECT_SYMBOL_LOCAL) 3115 { 3116 AssertMsgReturn(idxSym < cSymbols, 3117 ("i=%#x idxSym=%#x cSymbols=%#x iSect=%#x\n", i, idxSym, cSymbols, iSect), 3118 VERR_BAD_EXE_FORMAT); /// @todo better error code. 3119 pbDst[0] = 0xeb; /* JMP rel32 */ 3120 uint32_t offDisp = paSymbols[idxSym].n_value - (uint32_t)uDstRva - 5; 3121 pbDst[1] = (uint8_t)offDisp; 3122 offDisp >>= 8; 3123 pbDst[2] = (uint8_t)offDisp; 3124 offDisp >>= 8; 3125 pbDst[3] = (uint8_t)offDisp; 3126 offDisp >>= 8; 3127 pbDst[4] = (uint8_t)offDisp; 3128 } 3129 } 3130 break; 3131 } 3132 break; 3133 } 3134 3135 } 3136 } 3137 else 3138 { 3139 /* Exact like for 32-bit, except for 64-bit symbol table, 64-bit addresses and no need to process S_SYMBOL_STUBS. */ 3140 macho_nlist_64_t const *paSymbols = (macho_nlist_64_t *)pThis->pvaSymbols; 3141 for (uint32_t iSect = 0; iSect < pThis->cSections; iSect++) 3142 { 3143 section_64_t const *pSect = (section_64_t const *)pThis->paSections[iSect].pvMachoSection; 3144 switch (pSect->flags & SECTION_TYPE) 3145 { 3146 case S_NON_LAZY_SYMBOL_POINTERS: 3147 case S_LAZY_SYMBOL_POINTERS: 3148 { 3149 uint64_t *pauDstPtrs = (uint64_t *)((uintptr_t)pvBits + pThis->paSections[iSect].RVA); 3150 uint32_t const cDstPtrs = pThis->paSections[iSect].cb / sizeof(pauDstPtrs[0]); 3151 uint32_t const idxSrcSkip = pSect->reserved1; 3152 if ((uint64_t)idxSrcSkip + cDstPtrs > cIndirectSymbols) 3153 return VERR_BAD_EXE_FORMAT; /// @todo better error code. 3154 3155 for (uint32_t i = 0; i < cDstPtrs; i++) 3156 { 3157 uint32_t const idxSym = paidxIndirectSymbols[idxSrcSkip + i]; 3158 if (idxSym == INDIRECT_SYMBOL_LOCAL) 3159 pauDstPtrs[i] += (int64_t)offDelta; 3160 else if (idxSym != INDIRECT_SYMBOL_ABS) 3161 { 3162 AssertMsgReturn(idxSym < cSymbols, 3163 ("i=%#x idxSym=%#x cSymbols=%#x iSect=%#x\n", i, idxSym, cSymbols, iSect), 3164 VERR_BAD_EXE_FORMAT); /// @todo better error code. 3165 pauDstPtrs[i] = paSymbols[idxSym].n_value; 3166 } 3167 } 3168 break; 3169 } 3170 3171 case S_SYMBOL_STUBS: 3172 if ( pThis->Core.enmArch == RTLDRARCH_X86_32 3173 && (pSect->flags & S_ATTR_SELF_MODIFYING_CODE) 3174 && pSect->reserved2 == 5) 3175 return VERR_BAD_EXE_FORMAT; 3176 break; 3177 } 3178 } 3179 } 3180 3181 return VINF_SUCCESS; 3182 } 3183 3184 3185 /** 3186 * MH_OBJECT: Applies base relocations to an (unprotected) image mapping. 2786 3187 * 2787 3188 * @returns IPRT status code. … … 2793 3194 { 2794 3195 /* 2795 * Ensure that we've got the symbol table and section fixups handy.3196 * Ensure that we've got the symbol table. 2796 3197 */ 2797 3198 int rc = kldrModMachOLoadObjSymTab(pThis); … … 2813 3214 if (!pSect->cFixups) 2814 3215 continue; 2815 2816 /* lazy load (and endian convert) the fixups. */ 2817 if (!pSect->paFixups) 2818 { 2819 rc = kldrModMachOLoadFixups(pThis, pSect->offFixups, pSect->cFixups, &pSect->paFixups); 2820 if (RT_FAILURE(rc)) 2821 break; 2822 } 3216 AssertReturn(pSect->paFixups, VERR_INTERNAL_ERROR_4); 3217 AssertReturn(pSect->pauFixupVirginData, VERR_INTERNAL_ERROR_4); 2823 3218 2824 3219 /* … … 2827 3222 uint8_t *pbSectBits = (uint8_t *)pvMapping + (uintptr_t)pSect->RVA; 2828 3223 if (pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE) /** @todo this aint right. */ 2829 rc = kldrModMachO FixupSectionGeneric32Bit(pThis, pbSectBits, pSect,2830 (macho_nlist_32_t *)pThis->pvaSymbols,2831 pThis->cSymbols, NewBaseAddress);3224 rc = kldrModMachOApplyFixupsGeneric32Bit(pThis, pbSectBits, (size_t)pSect->cb, pSect->RVA, pSect->LinkAddress, 3225 pSect->paFixups, pSect->cFixups, pSect->pauFixupVirginData, 3226 (macho_nlist_32_t *)pThis->pvaSymbols, pThis->cSymbols, NewBaseAddress); 2832 3227 else if ( pThis->Hdr.magic == IMAGE_MACHO64_SIGNATURE 2833 3228 && pThis->Hdr.cputype == CPU_TYPE_X86_64) 2834 rc = kldrModMachO FixupSectionAMD64(pThis, pbSectBits, pSect,2835 (macho_nlist_64_t *)pThis->pvaSymbols,2836 pThis->cSymbols, NewBaseAddress);3229 rc = kldrModMachOApplyFixupsAMD64(pThis, pbSectBits, (size_t)pSect->cb, pSect->RVA, 3230 pSect->paFixups, pSect->cFixups, pSect->pauFixupVirginData, 3231 (macho_nlist_64_t *)pThis->pvaSymbols, pThis->cSymbols, NewBaseAddress); 2837 3232 else 2838 3233 RTLDRMODMACHO_FAILED_RETURN(VERR_LDRMACHO_TODO); … … 2843 3238 2844 3239 return rc; 3240 } 3241 3242 3243 /** 3244 * Dylib: Applies base relocations to an (unprotected) image mapping. 3245 * 3246 * @returns IPRT status code. 3247 * @param pThis The Mach-O module interpreter instance. 3248 * @param pvMapping The mapping to fixup. 3249 * @param NewBaseAddress The address to fixup the mapping to. 3250 */ 3251 static int kldrModMachODylibDoFixups(PRTLDRMODMACHO pThis, void *pvMapping, RTLDRADDR NewBaseAddress) 3252 { 3253 /* 3254 * There must be a LC_DYSYMTAB. 3255 * We might be lucky, though, and not have any imports. 3256 */ 3257 dysymtab_command_t const *pDySymTab = pThis->pDySymTab; 3258 AssertReturn(pDySymTab, VERR_INTERNAL_ERROR_2); 3259 uint32_t cRelocations = pDySymTab->nlocrel + pDySymTab->nextrel; 3260 if (cRelocations == 0) 3261 return VINF_SUCCESS; 3262 3263 /* 3264 * Ensure that we've got the symbol table. 3265 */ 3266 int rc = kldrModMachOLoadObjSymTab(pThis); 3267 if (RT_FAILURE(rc)) 3268 return rc; 3269 3270 /* 3271 * Load the relocations if needed. 3272 */ 3273 macho_relocation_union_t const *paRelocations = pThis->paRelocations; 3274 if (!paRelocations) 3275 { 3276 uint32_t *paRawRelocs = (uint32_t *)RTMemAlloc(cRelocations * sizeof(macho_relocation_union_t)); 3277 if (!paRawRelocs) 3278 return VERR_NO_MEMORY; 3279 if (pDySymTab->nextrel) 3280 rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, paRawRelocs, pDySymTab->nextrel * sizeof(macho_relocation_union_t), 3281 pDySymTab->extreloff); 3282 if (pDySymTab->nlocrel && RT_SUCCESS(rc)) 3283 rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, 3284 (uint8_t *)paRawRelocs + pDySymTab->nextrel * sizeof(macho_relocation_union_t), 3285 pDySymTab->nlocrel * sizeof(macho_relocation_union_t), pDySymTab->locreloff); 3286 if (RT_SUCCESS(rc)) 3287 pThis->paRelocations = (macho_relocation_union_t *)paRawRelocs; 3288 else 3289 { 3290 RTMemFree(paRawRelocs); 3291 return rc; 3292 } 3293 3294 /* Byte swap if needed. */ 3295 if ( pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE 3296 || pThis->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE) 3297 { 3298 for (uint32_t i = 0; i < cRelocations; i++) 3299 { 3300 paRawRelocs[i * 2] = RT_BSWAP_U32(paRawRelocs[i * 2]); 3301 paRawRelocs[i * 2 + 1] = RT_BSWAP_U32(paRawRelocs[i * 2 + 1]); 3302 } 3303 ASMCompilerBarrier(); 3304 } 3305 3306 paRelocations = pThis->paRelocations; 3307 } 3308 3309 /* 3310 * Apply the fixups. 3311 */ 3312 if (pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE) /** @todo this aint right. */ 3313 return kldrModMachOApplyFixupsGeneric32Bit(pThis, (uint8_t *)pvMapping, (size_t)pThis->cbImage, 0, pThis->LinkAddress, 3314 paRelocations, cRelocations, pThis->pauRelocationsVirginData, 3315 (macho_nlist_32_t *)pThis->pvaSymbols, pThis->cSymbols, NewBaseAddress); 3316 if ( pThis->Hdr.magic == IMAGE_MACHO64_SIGNATURE 3317 && pThis->Hdr.cputype == CPU_TYPE_X86_64) 3318 return kldrModMachOApplyFixupsAMD64(pThis, (uint8_t *)pvMapping, (size_t)pThis->cbImage, 0, 3319 paRelocations, cRelocations, pThis->pauRelocationsVirginData, 3320 (macho_nlist_64_t *)pThis->pvaSymbols, pThis->cSymbols, NewBaseAddress); 3321 RTLDRMODMACHO_FAILED_RETURN(VERR_LDRMACHO_TODO); 2845 3322 } 2846 3323 … … 2852 3329 * @returns IPRT status code. 2853 3330 * @param pThis The Mach-O module interpreter instance. 2854 * @param pbSectBits Pointer to the section bits. 2855 * @param pFixupSect The section being fixed up. 3331 * @param pbBits Pointer to the bits to fix up. 3332 * @param cbBits Size of the bits to fix up. 3333 * @param uBitsRva The RVA of the bits. 3334 * @param uBitsLinkAddr The link address of the bits. 3335 * @param paFixups The fixups. 3336 * @param cFixups Number of fixups. 3337 * @param pauVirginData The virgin data / addends. Parallel to paFixups. 2856 3338 * @param paSyms Pointer to the symbol table. 2857 3339 * @param cSyms Number of symbols. 2858 3340 * @param NewBaseAddress The new base image address. 2859 3341 */ 2860 static int kldrModMachOFixupSectionGeneric32Bit(PRTLDRMODMACHO pThis, uint8_t *pbSectBits, PRTLDRMODMACHOSECT pFixupSect, 2861 macho_nlist_32_t *paSyms, uint32_t cSyms, RTLDRADDR NewBaseAddress) 2862 { 2863 const macho_relocation_info_t *paFixups = pFixupSect->paFixups; 2864 const uint32_t cFixups = pFixupSect->cFixups; 2865 size_t cbSectBits = (size_t)pFixupSect->cb; 2866 const uint8_t *pbSectVirginBits; 2867 uint32_t iFixup; 2868 RTLDRADDR SymAddr = ~(RTLDRADDR)0; 2869 int rc; 2870 2871 /* 2872 * Find the virgin bits. 2873 */ 2874 if (pFixupSect->offFile != -1) 2875 { 2876 rc = kldrModMachOMapVirginBits(pThis); 2877 if (RT_FAILURE(rc)) 2878 return rc; 2879 pbSectVirginBits = (const uint8_t *)pThis->pvBits + pFixupSect->offFile; 2880 } 2881 else 2882 pbSectVirginBits = NULL; 2883 3342 static int kldrModMachOApplyFixupsGeneric32Bit(PRTLDRMODMACHO pThis, uint8_t *pbBits, size_t cbBits, RTLDRADDR uBitsRva, 3343 RTLDRADDR uBitsLinkAddr, const macho_relocation_union_t *paFixups, 3344 const uint32_t cFixups, PCRTUINT64U const pauVirginData, 3345 macho_nlist_32_t *paSyms, uint32_t cSyms, RTLDRADDR NewBaseAddress) 3346 { 2884 3347 /* 2885 3348 * Iterate the fixups and apply them. 2886 3349 */ 2887 for (iFixup = 0; iFixup < cFixups; iFixup++) 2888 { 2889 RTPTRUNION uFix; 2890 RTPTRUNION uFixVirgin; 2891 union 2892 { 2893 macho_relocation_info_t r; 2894 scattered_relocation_info_t s; 2895 } Fixup; 2896 Fixup.r = paFixups[iFixup]; 3350 for (uint32_t iFixup = 0; iFixup < cFixups; iFixup++) 3351 { 3352 macho_relocation_union_t Fixup = paFixups[iFixup]; 3353 RTLDRADDR SymAddr = ~(RTLDRADDR)0; 3354 RTPTRUNION uFix; 2897 3355 2898 3356 if (!(Fixup.r.r_address & R_SCATTERED)) 2899 3357 { 2900 3358 /* sanity */ 2901 if ((uint32_t)Fixup.r.r_address >= cbSectBits) 2902 return VERR_LDR_BAD_FIXUP; 2903 2904 /* calc fixup addresses. */ 2905 uFix.pv = pbSectBits + Fixup.r.r_address; 2906 uFixVirgin.pv = pbSectVirginBits ? (uint8_t *)pbSectVirginBits + Fixup.r.r_address : 0; 3359 RTLDRMODMACHO_CHECK_RETURN((uint32_t)Fixup.r.r_address + RT_BIT_32(Fixup.r.r_length) <= cbBits, VERR_LDR_BAD_FIXUP); 3360 3361 /* Calc the fixup address. */ 3362 uFix.pv = pbBits + Fixup.r.r_address; 2907 3363 2908 3364 /* … … 2912 3368 switch (Fixup.r.r_length) 2913 3369 { 2914 /** @todo Deal with unaligned accesses on non x86 platforms. */2915 case 0: SymAddr = *uFixVirgin.pi8; break;2916 case 1: SymAddr = *uFixVirgin.pi16; break;2917 case 2: SymAddr = *uFixVirgin.pi32; break;2918 case 3: SymAddr = *uFixVirgin.pi64; break;3370 case 0: SymAddr = (int8_t)pauVirginData[iFixup].au8[0]; break; 3371 case 1: SymAddr = (int16_t)pauVirginData[iFixup].au16[0]; break; 3372 case 2: SymAddr = (int32_t)pauVirginData[iFixup].au32[0]; break; 3373 case 3: SymAddr = (int64_t)pauVirginData[iFixup].u; break; 3374 default: RTLDRMODMACHO_FAILED_RETURN(VERR_LDR_BAD_FIXUP); 2919 3375 } 2920 3376 if (Fixup.r.r_pcrel) 2921 SymAddr += Fixup.r.r_address + pFixupSect->LinkAddress;3377 SymAddr += Fixup.r.r_address + uBitsLinkAddr; 2922 3378 2923 3379 /* Add symbol / section address. */ … … 2969 3425 /* adjust for PC relative */ 2970 3426 if (Fixup.r.r_pcrel) 2971 SymAddr -= Fixup.r.r_address + pFixupSect->RVA+ NewBaseAddress;3427 SymAddr -= Fixup.r.r_address + uBitsRva + NewBaseAddress; 2972 3428 } 2973 3429 else … … 2979 3435 /* sanity */ 2980 3436 RTLDRMODMACHO_ASSERT(Fixup.s.r_scattered); 2981 if ((uint32_t)Fixup.s.r_address >= cbSectBits) 2982 return VERR_LDR_BAD_FIXUP; 2983 2984 /* calc fixup addresses. */ 2985 uFix.pv = pbSectBits + Fixup.s.r_address; 2986 uFixVirgin.pv = pbSectVirginBits ? (uint8_t *)pbSectVirginBits + Fixup.s.r_address : 0; 3437 RTLDRMODMACHO_CHECK_RETURN((uint32_t)Fixup.s.r_address + RT_BIT_32(Fixup.s.r_length) <= cbBits, VERR_LDR_BAD_FIXUP); 3438 3439 /* Calc the fixup address. */ 3440 uFix.pv = pbBits + Fixup.s.r_address; 2987 3441 2988 3442 /* … … 2992 3446 switch (Fixup.s.r_length) 2993 3447 { 2994 case 0: SymAddr = *uFixVirgin.pi8; break; 2995 case 1: SymAddr = *uFixVirgin.pi16; break; 2996 case 2: SymAddr = *uFixVirgin.pi32; break; 2997 case 3: SymAddr = *uFixVirgin.pi64; break; 3448 case 0: SymAddr = (int8_t)pauVirginData[iFixup].au8[0]; break; 3449 case 1: SymAddr = (int16_t)pauVirginData[iFixup].au16[0]; break; 3450 case 2: SymAddr = (int32_t)pauVirginData[iFixup].au32[0]; break; 3451 case 3: SymAddr = (int64_t)pauVirginData[iFixup].u; break; 3452 default: RTLDRMODMACHO_FAILED_RETURN(VERR_LDR_BAD_FIXUP); 2998 3453 } 2999 3454 if (Fixup.s.r_pcrel) … … 3021 3476 SymAddr += Value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress; 3022 3477 if (Fixup.s.r_pcrel) 3023 SymAddr -= Fixup.s.r_address + pFixupSect->RVA+ NewBaseAddress;3478 SymAddr -= Fixup.s.r_address + uBitsRva + NewBaseAddress; 3024 3479 3025 3480 Fixup.r.r_length = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_length; … … 3055 3510 * @returns IPRT status code. 3056 3511 * @param pThis The Mach-O module interpreter instance. 3057 * @param pbSectBits Pointer to the section bits. 3512 * @param pbBits Pointer to the section bits. 3513 * @param cbBits Size of the bits to fix up. 3514 * @param uBitsRva The RVA of the bits. 3515 * @param paFixups The fixups. 3516 * @param cFixups Number of fixups. 3517 * @param pauVirginData The virgin data / addends. Parallel to paFixups. 3058 3518 * @param pFixupSect The section being fixed up. 3059 3519 * @param paSyms Pointer to the symbol table. … … 3061 3521 * @param NewBaseAddress The new base image address. 3062 3522 */ 3063 static int kldrModMachOFixupSectionAMD64(PRTLDRMODMACHO pThis, uint8_t *pbSectBits, PRTLDRMODMACHOSECT pFixupSect, 3064 macho_nlist_64_t *paSyms, uint32_t cSyms, RTLDRADDR NewBaseAddress) 3065 { 3066 const macho_relocation_info_t *paFixups = pFixupSect->paFixups; 3067 const uint32_t cFixups = pFixupSect->cFixups; 3068 size_t cbSectBits = (size_t)pFixupSect->cb; 3069 const uint8_t *pbSectVirginBits; 3070 uint32_t iFixup; 3071 RTLDRADDR SymAddr; 3072 int rc; 3073 3074 /* 3075 * Find the virgin bits. 3076 */ 3077 if (pFixupSect->offFile != -1) 3078 { 3079 rc = kldrModMachOMapVirginBits(pThis); 3080 if (RT_FAILURE(rc)) 3081 return rc; 3082 pbSectVirginBits = (const uint8_t *)pThis->pvBits + pFixupSect->offFile; 3083 } 3084 else 3085 pbSectVirginBits = NULL; 3086 3523 static int kldrModMachOApplyFixupsAMD64(PRTLDRMODMACHO pThis, uint8_t *pbBits, size_t cbBits, RTLDRADDR uBitsRva, 3524 const macho_relocation_union_t *paFixups, 3525 const uint32_t cFixups, PCRTUINT64U const pauVirginData, 3526 macho_nlist_64_t *paSyms, uint32_t cSyms, RTLDRADDR NewBaseAddress) 3527 { 3087 3528 /* 3088 3529 * Iterate the fixups and apply them. 3089 3530 */ 3090 for (iFixup = 0; iFixup < cFixups; iFixup++) 3091 { 3092 union 3093 { 3094 macho_relocation_info_t r; 3095 scattered_relocation_info_t s; 3096 } Fixup; 3097 Fixup.r = paFixups[iFixup]; 3531 for (uint32_t iFixup = 0; iFixup < cFixups; iFixup++) 3532 { 3533 macho_relocation_union_t Fixup = paFixups[iFixup]; 3098 3534 3099 3535 /* AMD64 doesn't use scattered fixups. */ … … 3101 3537 3102 3538 /* sanity */ 3103 RTLDRMODMACHO_CHECK_RETURN((uint32_t)Fixup.r.r_address < cbSectBits, VERR_LDR_BAD_FIXUP);3539 RTLDRMODMACHO_CHECK_RETURN((uint32_t)Fixup.r.r_address + RT_BIT_32(Fixup.r.r_length) <= cbBits, VERR_LDR_BAD_FIXUP); 3104 3540 3105 3541 /* calc fixup addresses. */ 3106 3542 RTPTRUNION uFix; 3107 uFix.pv = pbSectBits + Fixup.r.r_address; 3108 RTPTRUNION uFixVirgin; 3109 uFixVirgin.pv = pbSectVirginBits ? (uint8_t *)pbSectVirginBits + Fixup.r.r_address : 0; 3543 uFix.pv = pbBits + Fixup.r.r_address; 3110 3544 3111 3545 /* … … 3113 3547 */ 3114 3548 /* Calc the linked symbol address / addend. */ 3549 RTLDRADDR SymAddr; 3115 3550 switch (Fixup.r.r_length) 3116 3551 { 3117 /** @todo Deal with unaligned accesses on non x86 platforms. */ 3118 case 2: SymAddr = *uFixVirgin.pi32; break; 3119 case 3: SymAddr = *uFixVirgin.pi64; break; 3552 case 2: SymAddr = (int32_t)pauVirginData[iFixup].au32[0]; break; 3553 case 3: SymAddr = (int64_t)pauVirginData[iFixup].u; break; 3120 3554 default: 3121 3555 RTLDRMODMACHO_FAILED_RETURN(VERR_LDR_BAD_FIXUP); … … 3164 3598 default: 3165 3599 { 3166 /* Adjust with fixup specific addend and v ierfy unsigned/r_pcrel. */3600 /* Adjust with fixup specific addend and verify unsigned/r_pcrel. */ 3167 3601 switch (Fixup.r.r_type) 3168 3602 { … … 3198 3632 /* branch to an external symbol may have to take a short detour. */ 3199 3633 if ( Fixup.r.r_type == X86_64_RELOC_BRANCH 3200 && SymAddr + Fixup.r.r_address + pFixupSect->RVA+ NewBaseAddress3634 && SymAddr + Fixup.r.r_address + uBitsRva + NewBaseAddress 3201 3635 - pSym->n_value 3202 3636 + UINT64_C(0x80000000) … … 3222 3656 /* 3223 3657 * This is a weird customer, it will always be follows by an UNSIGNED fixup. 3658 * The value is calculated: target - pair_target. 3659 * Note! The linker generally eliminate these when linking modules rather 3660 * than objects (-r). 3224 3661 */ 3225 3662 case X86_64_RELOC_SUBTRACTOR: 3226 3663 { 3227 macho_relocation_info_t Fixup2;3228 3229 3664 /* Deal with the SUBTRACT symbol first, by subtracting it from SymAddr. */ 3230 3665 switch (pSym->n_type & MACHO_N_TYPE) … … 3254 3689 iFixup++; 3255 3690 RTLDRMODMACHO_CHECK_RETURN(!Fixup.r.r_pcrel && iFixup < cFixups, VERR_LDR_BAD_FIXUP); 3256 Fixup2 = paFixups[iFixup];3691 macho_relocation_info_t const Fixup2 = paFixups[iFixup].r; 3257 3692 RTLDRMODMACHO_CHECK_RETURN( Fixup2.r_address == Fixup.r.r_address 3258 3693 && Fixup2.r_length == Fixup.r.r_length … … 3268 3703 RTLDRMODMACHO_CHECK_RETURN(!(pSym->n_type & MACHO_N_STAB), VERR_LDR_BAD_FIXUP); 3269 3704 3270 /* Add it 's value to SymAddr. */3705 /* Add its value to SymAddr. */ 3271 3706 switch (pSym->n_type & MACHO_N_TYPE) 3272 3707 { … … 3297 3732 RTLDRMODMACHO_CHECK_RETURN(Fixup2.r_symbolnum <= pThis->cSections, VERR_LDR_BAD_FIXUP); 3298 3733 pSymSect = &pThis->paSections[Fixup2.r_symbolnum - 1]; 3299 SymAddr += pSymSect->RVA + NewBaseAddress;3734 SymAddr += pSymSect->RVA - pSymSect->LinkAddress + NewBaseAddress; 3300 3735 } 3301 3736 else … … 3344 3779 /* adjust for PC relative */ 3345 3780 if (Fixup.r.r_pcrel) 3346 SymAddr -= Fixup.r.r_address + pFixupSect->RVA+ NewBaseAddress;3781 SymAddr -= Fixup.r.r_address + uBitsRva + NewBaseAddress; 3347 3782 3348 3783 /* … … 3369 3804 3370 3805 /** 3371 * Loads the symbol table for a MH_OBJECT file.3806 * Loads the symbol table (LC_SYMTAB). 3372 3807 * 3373 3808 * The symbol table is pointed to by RTLDRMODMACHO::pvaSymbols. … … 3413 3848 rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pvSyms, cbSyms, pThis->offSymbols); 3414 3849 if (RT_SUCCESS(rc) && pThis->cchStrings) 3415 rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pvStrings, 3416 pThis->cchStrings, pThis->offStrings); 3850 rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pvStrings, pThis->cchStrings, pThis->offStrings); 3417 3851 if (RT_SUCCESS(rc)) 3418 3852 { … … 3470 3904 * @param ppaFixups Where to put the pointer to the allocated fixup array. 3471 3905 */ 3472 static int kldrModMachOLoadFixups(PRTLDRMODMACHO pThis, RTFOFF offFixups, uint32_t cFixups, macho_relocation_info_t **ppaFixups)3473 { 3474 macho_relocation_ info_t *paFixups;3906 static int kldrModMachOLoadFixups(PRTLDRMODMACHO pThis, RTFOFF offFixups, uint32_t cFixups, macho_relocation_union_t **ppaFixups) 3907 { 3908 macho_relocation_union_t *paFixups; 3475 3909 size_t cbFixups; 3476 3910 … … 3478 3912 cbFixups = cFixups * sizeof(*paFixups); 3479 3913 RTLDRMODMACHO_CHECK_RETURN(cbFixups / sizeof(*paFixups) == cFixups, VERR_LDRMACHO_BAD_SYMTAB_SIZE); 3480 paFixups = (macho_relocation_ info_t *)RTMemAlloc(cbFixups);3914 paFixups = (macho_relocation_union_t *)RTMemAlloc(cbFixups); 3481 3915 if (!paFixups) 3482 3916 return VERR_NO_MEMORY; … … 3489 3923 3490 3924 /* do endian conversion if necessary. */ 3491 if ( pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE3492 || pThis->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE)3925 if ( pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE 3926 || pThis->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE) 3493 3927 { 3494 3928 uint32_t iFixup; … … 3508 3942 3509 3943 /** 3510 * Maps the virgin file bits into memory if not already done.3944 * Loads virgin data (addends) for an array of fixups. 3511 3945 * 3512 3946 * @returns IPRT status code. 3513 * @param pThis The Mach-O module interpreter instance. 3514 */ 3515 static int kldrModMachOMapVirginBits(PRTLDRMODMACHO pThis) 3516 { 3947 * @param pThis The Mach-O module interpreter instance. 3948 * @param pbBits The virgin bits to lift the data from 3949 * @param cbBits The number of virgin bytes. 3950 * @param paFixups The fixups. 3951 * @param cFixups Number of fixups 3952 * @param pszName Name for logging. 3953 * @param ppauVirginData Where to return the virgin data. 3954 */ 3955 static int rtldrMachOLoadVirginData(PRTLDRMODMACHO pThis, uint8_t const *pbBits, size_t cbBits, 3956 macho_relocation_union_t const *paFixups, uint32_t cFixups, const char *pszName, 3957 PRTUINT64U *ppauVirginData) 3958 { 3959 /* 3960 * In case we jettisoned the fixups, we will leave virgin data. 3961 */ 3962 if (*ppauVirginData) 3963 return VINF_SUCCESS; 3964 3965 #ifdef LOG_ENABLED 3966 /* 3967 * Ensure that we've got the symbol table if we're logging fixups. 3968 */ 3969 if (LogIs5Enabled()) 3970 { 3971 int rc = kldrModMachOLoadObjSymTab(pThis); 3972 if (RT_FAILURE(rc)) 3973 return rc; 3974 } 3975 #endif 3976 3977 3978 /* 3979 * Allocate memory and iterate the fixups to get the data. 3980 */ 3981 PRTUINT64U pauVirginData = *ppauVirginData = (PRTUINT64U)RTMemAllocZ(sizeof(uint64_t) * cFixups); 3982 if (pauVirginData) 3983 { 3984 Log5(("Fixups for %s: (%u)\n", pszName, cFixups)); 3985 for (uint32_t i = 0; i < cFixups; i++) 3986 { 3987 uint32_t off; 3988 uint32_t cShift; 3989 if (!paFixups[i].s.r_scattered) 3990 { 3991 off = paFixups[i].r.r_address; 3992 cShift = paFixups[i].r.r_length; 3993 } 3994 else 3995 { 3996 off = paFixups[i].s.r_address; 3997 cShift = paFixups[i].s.r_length; 3998 } 3999 RTLDRMODMACHO_CHECK_RETURN(off + RT_BIT_32(cShift) <= cbBits, VERR_LDR_BAD_FIXUP); 4000 4001 /** @todo This ASSUMES same endian in the image and on the host. Would need 4002 * to check target cpu (pThis->Core.enmArch) endianness against host to get 4003 * it right... (outside the loop, obviously) */ 4004 switch (cShift) 4005 { 4006 case 3: 4007 pauVirginData[i].u = RT_MAKE_U64_FROM_U8(pbBits[off], pbBits[off + 1], pbBits[off + 2], pbBits[off + 3], 4008 pbBits[off + 4], pbBits[off + 5], pbBits[off + 6], pbBits[off + 7]); 4009 break; 4010 case 2: 4011 pauVirginData[i].u = (int32_t)RT_MAKE_U32_FROM_U8(pbBits[off], pbBits[off + 1], pbBits[off + 2], pbBits[off + 3]); 4012 break; 4013 case 1: 4014 pauVirginData[i].u = (int16_t)RT_MAKE_U16(pbBits[off], pbBits[off + 1]); 4015 break; 4016 case 0: 4017 pauVirginData[i].u = (int8_t)pbBits[off]; 4018 break; 4019 default: 4020 RTLDRMODMACHO_FAILED_RETURN(VERR_LDR_BAD_FIXUP); 4021 } 4022 4023 #ifdef LOG_ENABLED 4024 if (LogIs5Enabled()) 4025 { 4026 if (!paFixups[i].s.r_scattered) 4027 { 4028 Log5((" #%06x: %#08x LB %u: t=%#x pc=%u ex=%u sym=%#010x add=%#RX64\n", 4029 i, off, RT_BIT_32(cShift), paFixups[i].r.r_type, paFixups[i].r.r_pcrel, paFixups[i].r.r_extern, 4030 paFixups[i].r.r_symbolnum, pauVirginData[i].u)); 4031 if (paFixups[i].r.r_symbolnum < pThis->cSymbols) 4032 { 4033 if (pThis->Hdr.magic == IMAGE_MACHO64_SIGNATURE || pThis->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE) 4034 { 4035 macho_nlist_64_t const *pSym = (macho_nlist_64_t const *)pThis->pvaSymbols + paFixups[i].r.r_symbolnum; 4036 Log5((" sym: %#04x:%#018RX64 t=%#04x d=%#06x %s\n", 4037 pSym->n_sect, pSym->n_value, pSym->n_type, pSym->n_desc, 4038 pSym->n_un.n_strx < pThis->cchStrings ? &pThis->pchStrings[pSym->n_un.n_strx] : "")); 4039 4040 } 4041 else 4042 { 4043 macho_nlist_32_t const *pSym = (macho_nlist_32_t const *)pThis->pvaSymbols + paFixups[i].r.r_symbolnum; 4044 Log5((" sym: %#04x:%#010RX32 t=%#04x d=%#06x %s\n", 4045 pSym->n_sect, pSym->n_value, pSym->n_type, pSym->n_desc, 4046 (uint32_t)pSym->n_un.n_strx < pThis->cchStrings ? &pThis->pchStrings[pSym->n_un.n_strx] : "")); 4047 } 4048 } 4049 } 4050 else 4051 Log5((" #%06x: %#08x LB %u: t=%#x pc=%u val=%#010x add=%#RX64\n", i, off, RT_BIT_32(cShift), 4052 paFixups[i].s.r_type, paFixups[i].s.r_pcrel, paFixups[i].s.r_value, pauVirginData[i].u)); 4053 } 4054 #endif 4055 } 4056 return VINF_SUCCESS; 4057 } 4058 RT_NOREF(pThis, pszName); 4059 return VERR_NO_MEMORY; 4060 } 4061 4062 4063 /** 4064 * MH_OBJECT: Loads fixups and addends for each section. 4065 * 4066 * @returns IPRT status code. 4067 * @param pThis The Mach-O module interpreter instance. 4068 * @param pbBits The image bits. First time we're called, these are 4069 * ASSUMED to be in virgin state and suitable for 4070 * saving addends. 4071 */ 4072 static int rtldrMachOObjLoadFixupsAndVirginData(PRTLDRMODMACHO pThis, uint8_t const *pbBits) 4073 { 4074 PRTLDRMODMACHOSECT pSect = pThis->paSections; 4075 for (uint32_t i = 0; i < pThis->cSections; i++, pSect++) 4076 if ( !pSect->paFixups 4077 && pSect->cFixups > 0) 4078 { 4079 /* 4080 * Load and endian convert the fixups. 4081 */ 4082 int rc = kldrModMachOLoadFixups(pThis, pSect->offFixups, pSect->cFixups, &pSect->paFixups); 4083 if (RT_SUCCESS(rc)) 4084 { 4085 /* 4086 * Save virgin data (addends) for each fixup. 4087 */ 4088 rc = rtldrMachOLoadVirginData(pThis, &pbBits[(size_t)pSect->RVA], (size_t)pSect->cb, pSect->paFixups, pSect->cFixups, 4089 pThis->aSegments[pSect->iSegment].SegInfo.pszName, &pSect->pauFixupVirginData); 4090 if (RT_SUCCESS(rc)) 4091 continue; 4092 4093 RTMemFree(pSect->pauFixupVirginData); 4094 pSect->pauFixupVirginData = NULL; 4095 RTMemFree(pSect->paFixups); 4096 pSect->paFixups = NULL; 4097 } 4098 return rc; 4099 } 4100 4101 return VINF_SUCCESS; 4102 } 4103 4104 4105 /** 4106 * Dylib: Loads fixups and addends. 4107 * 4108 * @returns IPRT status code. 4109 * @param pThis The Mach-O module interpreter instance. 4110 * @param pbBits The image bits. First time we're called, these are 4111 * ASSUMED to be in virgin state and suitable for 4112 * saving addends. 4113 */ 4114 static int rtldrMachODylibLoadFixupsAndVirginData(PRTLDRMODMACHO pThis, uint8_t const *pbBits) 4115 { 4116 /* 4117 * Don't do it again if we already loaded them. 4118 */ 4119 if (pThis->paRelocations) 4120 { 4121 Assert(pThis->pauRelocationsVirginData); 4122 return VINF_SUCCESS; 4123 } 4124 4125 /* 4126 * There must be a LC_DYSYMTAB. Fixups are optionals. 4127 */ 4128 dysymtab_command_t const *pDySymTab = pThis->pDySymTab; 4129 AssertReturn(pDySymTab, VERR_INTERNAL_ERROR_2); 4130 uint32_t cRelocations = pDySymTab->nlocrel + pDySymTab->nextrel; 4131 if (cRelocations == 0) 4132 return VINF_SUCCESS; 4133 4134 /* 4135 * Load fixups. 4136 */ 3517 4137 int rc = VINF_SUCCESS; 3518 if (!pThis->pvBits) 3519 rc = pThis->Core.pReader->pfnMap(pThis->Core.pReader, &pThis->pvBits); 4138 uint32_t *paRawRelocs = (uint32_t *)RTMemAlloc(cRelocations * sizeof(macho_relocation_union_t)); 4139 if (paRawRelocs) 4140 { 4141 pThis->paRelocations = (macho_relocation_union_t *)paRawRelocs; 4142 4143 if (pDySymTab->nextrel) 4144 rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, paRawRelocs, 4145 pDySymTab->nextrel * sizeof(macho_relocation_union_t), pDySymTab->extreloff); 4146 if (pDySymTab->nlocrel && RT_SUCCESS(rc)) 4147 rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, 4148 (uint8_t *)paRawRelocs + pDySymTab->nextrel * sizeof(macho_relocation_union_t), 4149 pDySymTab->nlocrel * sizeof(macho_relocation_union_t), pDySymTab->locreloff); 4150 if (RT_SUCCESS(rc)) 4151 { 4152 /* Byte swap if needed. */ 4153 if ( pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE 4154 || pThis->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE) 4155 { 4156 for (uint32_t i = 0; i < cRelocations; i++) 4157 { 4158 paRawRelocs[i * 2] = RT_BSWAP_U32(paRawRelocs[i * 2]); 4159 paRawRelocs[i * 2 + 1] = RT_BSWAP_U32(paRawRelocs[i * 2 + 1]); 4160 } 4161 ASMCompilerBarrier(); 4162 } 4163 4164 /* 4165 * Load virgin data (addends). 4166 */ 4167 rc = rtldrMachOLoadVirginData(pThis, pbBits, (size_t)pThis->cbImage, pThis->paRelocations, cRelocations, 4168 "whole-image", &pThis->pauRelocationsVirginData); 4169 if (RT_SUCCESS(rc)) 4170 return VINF_SUCCESS; 4171 4172 RTMemFree(pThis->pauRelocationsVirginData); 4173 pThis->pauRelocationsVirginData = NULL; 4174 } 4175 RTMemFree(pThis->paRelocations); 4176 pThis->paRelocations = NULL; 4177 } 4178 else 4179 rc = VERR_NO_MEMORY; 3520 4180 return rc; 3521 4181 } … … 3558 4218 #endif 3559 4219 3560 3561 4220 /** 3562 4221 * @interface_method_impl{RTLDROPS,pfnGetImageSize} … … 3593 4252 if ( pThis->aSegments[i].SegInfo.cbFile == -1 3594 4253 || pThis->aSegments[i].SegInfo.offFile == -1 3595 || pThis->aSegments[i].SegInfo.LinkAddress == NIL_RTLDRADDR 4254 || pThis->aSegments[i].SegInfo.RVA == NIL_RTLDRADDR 4255 || pThis->aSegments[i].SegInfo.cbMapped == 0 3596 4256 || !pThis->aSegments[i].SegInfo.Alignment) 3597 4257 continue; … … 3619 4279 PRTLDRMODMACHO pThis = RT_FROM_MEMBER(pMod, RTLDRMODMACHO, Core); 3620 4280 int rc; 3621 RT_NOREF(OldBaseAddress);3622 4281 3623 4282 /* … … 3626 4285 if (pThis->Hdr.filetype == MH_OBJECT) 3627 4286 { 3628 rc = kldrModMachOObjDoImports(pThis, NewBaseAddress, pfnGetImport, pvUser); 4287 rc = rtldrMachOObjLoadFixupsAndVirginData(pThis, (uint8_t const *)pvBits); 4288 if (RT_SUCCESS(rc)) 4289 rc = kldrModMachOObjDoImports(pThis, NewBaseAddress, pfnGetImport, pvUser); 3629 4290 if (RT_SUCCESS(rc)) 3630 4291 rc = kldrModMachOObjDoFixups(pThis, pvBits, NewBaseAddress); … … 3632 4293 } 3633 4294 else 3634 rc = VERR_LDRMACHO_TODO; 3635 /*{ 3636 rc = kldrModMachODoFixups(pThis, pvBits, NewBaseAddress, OldBaseAddress, pfnGetImport, pvUser); 4295 { 4296 rc = rtldrMachODylibLoadFixupsAndVirginData(pThis, (uint8_t const *)pvBits); 3637 4297 if (RT_SUCCESS(rc)) 3638 rc = kldrModMachODoImports(pThis, pvBits, pfnGetImport, pvUser); 3639 }*/ 4298 rc = kldrModMachODylibDoImports(pThis, NewBaseAddress, pfnGetImport, pvUser); 4299 if (RT_SUCCESS(rc)) 4300 rc = kldrModMachODylibDoIndirectSymbols(pThis, pvBits, NewBaseAddress - OldBaseAddress); 4301 if (RT_SUCCESS(rc)) 4302 rc = kldrModMachODylibDoFixups(pThis, pvBits, NewBaseAddress); 4303 } 3640 4304 3641 4305 /* … … 4069 4733 for (uint32_t iSlot = 0; iSlot < cSlots; iSlot++) 4070 4734 { 4735 /* 4736 * Check that the data offset is valid. There appears to be no alignment 4737 * requirements here, which is a little weird consindering the PPC heritage. 4738 */ 4071 4739 uint32_t const offData = RT_BE2H_U32(pSuper->aSlots[iSlot].offData); 4072 4740 if ( offData < offFirst 4073 || offData > cbBlob - sizeof(RTCRAPLCSHDR) 4074 || (offData & 3)) 4741 || offData > cbBlob - sizeof(RTCRAPLCSHDR)) 4075 4742 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4076 4743 "Slot #%u has an invalid data offset: %#x (min %#x, max %#x-4)",
Note:
See TracChangeset
for help on using the changeset viewer.

