Ignore:
Timestamp:
Feb 7, 2007, 5:42:32 AM (19 years ago)
Author:
bird
Message:

implemented kldrModMachOPreParseLoadCommands

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/kLdr/kLdrModMachO.c

    r2952 r2954  
    3333#include "kLdrInternal.h"
    3434#include "kLdrModMachO.h"
     35
     36/* quick hack for now. */
     37typedef struct nlist
     38{
     39    uint32_t    n_strx;
     40    uint8_t     n_type;
     41    int8_t      n_other;
     42    int16_t     n_desc;
     43    uint32_t    n_value;
     44} nlist_t;
    3545
    3646
     
    7585*******************************************************************************/
    7686/**
    77  * Instance data for the MACH-O MH_OBJECT module interpreter.
     87 * Instance data for the Mach-O MH_OBJECT module interpreter.
    7888 * @todo interpret the other MH_* formats.
    7989 */
     
    121131
    122132static int  kldrModMachODoCreate(PKLDRRDR pRdr, PKLDRMODMACHO *ppMod);
    123 static int  kldrModMachOPreParseLoadCommands(uint8_t *pbLoadCommands, const mach_header_32_t *pHdr,
     133static int  kldrModMachOPreParseLoadCommands(uint8_t *pbLoadCommands, const mach_header_32_t *pHdr, PKLDRRDR pRdr,
    124134                                             uint32_t *pcSegments, uint32_t *pcbStringPool);
    125135static int  kldrModMachOParseLoadCommands(PKLDRMODMACHO pModMachO, char *pbStringPool, uint32_t cbStringPool);
     
    243253                     ? sizeof(mach_header_32_t) : sizeof(mach_header_64_t));
    244254    if (!rc)
    245         rc = kldrModMachOPreParseLoadCommands(pbLoadCommands, &s.Hdr32, &cSegments, &cbStringPool);
     255        rc = kldrModMachOPreParseLoadCommands(pbLoadCommands, &s.Hdr32, pRdr, &cSegments, &cbStringPool);
    246256    if (rc)
    247257    {
     
    375385 * @param   pbLoadCommands  The load commands to parse.
    376386 * @param   pHdr            The header.
     387 * @param   pRdr            The file reader.
    377388 * @param   pcSegments      Where to store the segment count.
    378389 * @param   pcbStringPool   Where to store the string pool size.
    379390 */
    380 static int  kldrModMachOPreParseLoadCommands(uint8_t *pbLoadCommands, const mach_header_32_t *pHdr,
     391static int  kldrModMachOPreParseLoadCommands(uint8_t *pbLoadCommands, const mach_header_32_t *pHdr, PKLDRRDR pRdr,
    381392                                             uint32_t *pcSegments, uint32_t *pcbStringPool)
    382393{
     394    union
     395    {
     396        uint8_t              *pb;
     397        load_command_t       *pLoadCmd;
     398        segment_command_32_t *pSeg32;
     399        segment_command_64_t *pSeg64;
     400        thread_command_t     *pThread;
     401        symtab_command_t     *pSymTab;
     402        uuid_command_t       *pUuid;
     403    } u;
     404    const uint64_t cbFile = kLdrRdrSize(pRdr);
     405    uint32_t cSegments = 0;
     406    uint32_t cbStringPool = 0;
     407    uint32_t cLeft = pHdr->ncmds;
     408    uint32_t cbLeft = pHdr->sizeofcmds;
     409    uint8_t *pb = pbLoadCommands;
     410    int      fConvertEndian = pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE
     411                           || pHdr->magic == IMAGE_MACHO64_SIGNATURE_OE;
     412
    383413    *pcSegments = 0;
    384414    *pcbStringPool = 0;
     415
     416    while (cLeft-- > 0)
     417    {
     418        u.pb = pb;
     419
     420        /*
     421         * Convert and validate command header.
     422         */
     423        if (cbLeft < sizeof(load_command_t))
     424            return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
     425        if (fConvertEndian)
     426        {
     427            u.pLoadCmd->cmd = KLDRHLP_E2E_U32(u.pLoadCmd->cmd);
     428            u.pLoadCmd->cmdsize = KLDRHLP_E2E_U32(u.pLoadCmd->cmdsize);
     429        }
     430        if (u.pLoadCmd->cmdsize > cbLeft)
     431            return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
     432        cbLeft -= u.pLoadCmd->cmdsize;
     433        pb += u.pLoadCmd->cmdsize;
     434
     435        /*
     436         * Convert endian if needed, parse and validate the command.
     437         */
     438        switch (u.pLoadCmd->cmd)
     439        {
     440            case LC_SEGMENT_32:
     441            {
     442                section_32_t *pSect;
     443                section_32_t *pFirstSect;
     444                uint32_t cSectionsLeft;
     445
     446                /* convert and verify*/
     447                if (u.pLoadCmd->cmdsize < sizeof(segment_command_32_t))
     448                    return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
     449                if (fConvertEndian)
     450                {
     451                    u.pSeg32->vmaddr   = KLDRHLP_E2E_U32(u.pSeg32->vmaddr);
     452                    u.pSeg32->vmsize   = KLDRHLP_E2E_U32(u.pSeg32->vmsize);
     453                    u.pSeg32->fileoff  = KLDRHLP_E2E_U32(u.pSeg32->fileoff);
     454                    u.pSeg32->filesize = KLDRHLP_E2E_U32(u.pSeg32->filesize);
     455                    u.pSeg32->maxprot  = KLDRHLP_E2E_U32(u.pSeg32->maxprot);
     456                    u.pSeg32->initprot = KLDRHLP_E2E_U32(u.pSeg32->initprot);
     457                    u.pSeg32->nsects   = KLDRHLP_E2E_U32(u.pSeg32->nsects);
     458                    u.pSeg32->flags    = KLDRHLP_E2E_U32(u.pSeg32->flags);
     459                }
     460
     461                if (    u.pSeg32->filesize
     462                    &&  (   u.pSeg32->fileoff > cbFile
     463                         || (uint64_t)u.pSeg32->fileoff + u.pSeg32->filesize > cbFile))
     464                    return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
     465                if (!u.pSeg32->filesize && u.pSeg32->fileoff)
     466                    return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
     467                if (u.pSeg32->vmsize < u.pSeg32->filesize)
     468                    return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
     469                if ((u.pSeg32->maxprot & u.pSeg32->initprot) != u.pSeg32->initprot)
     470                    return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
     471                if (u.pSeg32->flags & ~(SG_HIGHVM | SG_FVMLIB | SG_NORELOC | SG_PROTECTED_VERSION_1))
     472                    return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
     473                if (u.pSeg32->nsects * sizeof(section_32_t) > u.pLoadCmd->cmdsize - sizeof(segment_command_32_t))
     474                    return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
     475
     476                /*
     477                 * convert, validate and parse the sections.
     478                 */
     479                cSectionsLeft = u.pSeg32->nsects;
     480                pFirstSect = pSect = (section_32_t *)(u.pSeg32 + 1);
     481                while (cSectionsLeft-- > 0)
     482                {
     483                    int fFileBits;
     484
     485                    if (fConvertEndian)
     486                    {
     487                        pSect->addr      = KLDRHLP_E2E_U32(pSect->addr);
     488                        pSect->size      = KLDRHLP_E2E_U32(pSect->size);
     489                        pSect->offset    = KLDRHLP_E2E_U32(pSect->offset);
     490                        pSect->align     = KLDRHLP_E2E_U32(pSect->align);
     491                        pSect->reloff    = KLDRHLP_E2E_U32(pSect->reloff);
     492                        pSect->nreloc    = KLDRHLP_E2E_U32(pSect->nreloc);
     493                        pSect->flags     = KLDRHLP_E2E_U32(pSect->flags);
     494                        pSect->reserved1 = KLDRHLP_E2E_U32(pSect->reserved1);
     495                        pSect->reserved2 = KLDRHLP_E2E_U32(pSect->reserved2);
     496                    }
     497
     498                    /* validate */
     499                    switch (pSect->flags & SECTION_TYPE)
     500                    {
     501                        case S_ZEROFILL:
     502                            if (pSect->reserved1 || pSect->reserved2)
     503                                return KLDR_ERR_MACHO_BAD_SECTION;
     504                            fFileBits = 0;
     505                            break;
     506                        case S_REGULAR:
     507                        case S_CSTRING_LITERALS:
     508                            if (pSect->reserved1 || pSect->reserved2)
     509                                return KLDR_ERR_MACHO_BAD_SECTION;
     510                            fFileBits = 1;
     511                            break;
     512
     513                        case S_LITERAL_POINTERS:
     514                        case S_INTERPOSING:
     515                        case S_GB_ZEROFILL:
     516                        case S_NON_LAZY_SYMBOL_POINTERS:
     517                        case S_LAZY_SYMBOL_POINTERS:
     518                        case S_4BYTE_LITERALS:
     519                        case S_8BYTE_LITERALS:
     520                        case S_16BYTE_LITERALS:
     521                        case S_SYMBOL_STUBS:
     522                        case S_COALESCED:
     523                        case S_MOD_INIT_FUNC_POINTERS:
     524                        case S_MOD_TERM_FUNC_POINTERS:
     525                            return KLDR_ERR_MACHO_UNSUPPORTED_SECTION;
     526
     527                        default:
     528                            return KLDR_ERR_MACHO_UNKNOWN_SECTION;
     529                    }
     530                    if (pSect->flags & ~(  S_ATTR_PURE_INSTRUCTIONS | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS
     531                                         | S_ATTR_NO_DEAD_STRIP | S_ATTR_LIVE_SUPPORT | S_ATTR_SELF_MODIFYING_CODE
     532                                         | S_ATTR_DEBUG | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_EXT_RELOC
     533                                         | S_ATTR_LOC_RELOC | SECTION_TYPE))
     534                        return KLDR_ERR_MACHO_BAD_SECTION;
     535                    if (!pSect->size)
     536                        return KLDR_ERR_MACHO_BAD_SECTION;
     537                    if (    pSect->addr - u.pSeg32->vmaddr > u.pSeg32->vmsize
     538                        ||  pSect->addr - u.pSeg32->vmaddr + pSect->size > u.pSeg32->vmsize)
     539                        return KLDR_ERR_MACHO_BAD_SECTION;
     540                    if (    pSect->align >= 31
     541                        ||  (((1 << pSect->align) - 1) & pSect->addr)
     542                        ||  (((1 << pSect->align) - 1) & u.pSeg32->vmaddr))
     543                        return KLDR_ERR_MACHO_BAD_SECTION;
     544                    if (    fFileBits
     545                        &&  (   pSect->offset > cbFile
     546                             || (uint64_t)pSect->offset + pSect->size > cbFile))
     547                        return KLDR_ERR_MACHO_BAD_SECTION;
     548                    if (!fFileBits && pSect->offset)
     549                        return KLDR_ERR_MACHO_BAD_SECTION;
     550                    if (!pSect->nreloc && pSect->reloff)
     551                        return KLDR_ERR_MACHO_BAD_SECTION;
     552                    if (    pSect->nreloc
     553                        &&  (   pSect->reloff > cbFile
     554                             || (uint64_t)pSect->reloff + (off_t)pSect->nreloc * sizeof(nlist_t)) > cbFile)
     555                        return KLDR_ERR_MACHO_BAD_SECTION;
     556
     557
     558                    /* count segments and strings */
     559                    switch (pHdr->filetype)
     560                    {
     561                        case MH_OBJECT:
     562                        {
     563                            /* Don't load debug symbols. (test this) */
     564                            if (pSect->flags & S_ATTR_DEBUG)
     565                                break;
     566
     567                            /* a new segment? */
     568                            if (    pSect == pFirstSect
     569                                ||  kLdrHlpStrNComp(pSect->segname, (pSect - 1)->segname, sizeof(pSect->segname)))
     570                            {
     571                                /* verify that the linker/assembler has ordered sections correctly. */
     572                                section_32_t *pCur = (pSect - 2);
     573                                while ((uintptr_t)pCur >= (uintptr_t)pFirstSect)
     574                                {
     575                                    if (!kLdrHlpStrNComp(pCur->segname, pSect->segname, sizeof(pSect->segname)))
     576                                        return KLDR_ERR_MACHO_BAD_SECTION_ORDER;
     577                                    pCur--;
     578                                }
     579
     580                                /* ok. count it and the string. */
     581                                cSegments++;
     582                                cbStringPool += kLdrHlpStrLen(pSect->segname) + 1;
     583                            }
     584                            break;
     585                        }
     586
     587                        default:
     588                            return KLDR_ERR_INVALID_PARAMETER;
     589                    }
     590
     591                    /* next */
     592                    pSect++;
     593                }
     594                break;
     595            }
     596
     597            case LC_SEGMENT_64:
     598                /* copy 32-bit code */
     599                break;
     600
     601            case LC_SYMTAB:
     602                if (fConvertEndian)
     603                {
     604                    u.pSymTab->symoff  = KLDRHLP_E2E_U32(u.pSymTab->symoff);
     605                    u.pSymTab->nsyms   = KLDRHLP_E2E_U32(u.pSymTab->nsyms);
     606                    u.pSymTab->stroff  = KLDRHLP_E2E_U32(u.pSymTab->stroff);
     607                    u.pSymTab->strsize = KLDRHLP_E2E_U32(u.pSymTab->strsize);
     608                }
     609
     610                /* verify */
     611                if (    u.pSymTab->symoff >= cbFile
     612                    ||  (uint64_t)u.pSymTab->symoff + u.pSymTab->nsyms * sizeof(nlist_t) > kLdrRdrSize(pRdr))
     613                    return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
     614                if (    u.pSymTab->stroff >= cbFile
     615                    ||  (uint64_t)u.pSymTab->stroff + u.pSymTab->strsize > cbFile)
     616                    return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
     617                break;
     618
     619            case LC_THREAD:
     620            case LC_UNIXTHREAD:
     621            {
     622                uint32_t *pu32 = (uint32_t *)(u.pb + sizeof(load_command_t));
     623                uint32_t cItemsLeft = (u.pThread->cmdsize - sizeof(load_command_t)) / sizeof(uint32_t);
     624                while (cItemsLeft)
     625                {
     626                    /* convert & verify header items ([0] == flavor, [1] == uint32_t count). */
     627                    if (cItemsLeft < 2)
     628                        return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
     629                    if (fConvertEndian)
     630                    {
     631                        pu32[0] = KLDRHLP_E2E_U32(pu32[0]);
     632                        pu32[1] = KLDRHLP_E2E_U32(pu32[1]);
     633                    }
     634                    if (pu32[1] + 2 > cItemsLeft)
     635                        return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
     636
     637                    /* convert & verify according to flavor. */
     638                    switch (pu32[0])
     639                    {
     640                        /** @todo */
     641                        default:
     642                            break;
     643                    }
     644
     645                    /* next */
     646                    cItemsLeft -= pu32[1] + 2;
     647                    pu32 += pu32[1] + 2;
     648                }
     649                break;
     650            }
     651
     652            case LC_UUID:
     653                if (u.pUuid->cmdsize != sizeof(uuid_command_t))
     654                    return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
     655                /** @todo Check anything here need converting? */
     656                break;
     657
     658            case LC_LOADFVMLIB:
     659            case LC_IDFVMLIB:
     660            case LC_IDENT:
     661            case LC_FVMFILE:
     662            case LC_PREPAGE:
     663            case LC_DYSYMTAB:
     664            case LC_LOAD_DYLIB:
     665            case LC_ID_DYLIB:
     666            case LC_LOAD_DYLINKER:
     667            case LC_ID_DYLINKER:
     668            case LC_PREBOUND_DYLIB:
     669            case LC_ROUTINES:
     670            case LC_ROUTINES_64:
     671            case LC_SUB_FRAMEWORK:
     672            case LC_SUB_UMBRELLA:
     673            case LC_SUB_CLIENT:
     674            case LC_SUB_LIBRARY:
     675            case LC_TWOLEVEL_HINTS:
     676            case LC_PREBIND_CKSUM:
     677            case LC_LOAD_WEAK_DYLIB:
     678            case LC_SYMSEG:
     679                return KLDR_ERR_MACHO_UNSUPPORTED_LOAD_COMMAND;
     680
     681            default:
     682                return KLDR_ERR_MACHO_UNKNOWN_LOAD_COMMAND;
     683        }
     684    }
     685
     686    /* be strict (for now). */
     687    if (cbLeft)
     688        return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
     689
     690    *pcSegments = cSegments;
     691    *pcbStringPool = cLeft;
     692
    385693    return 0;
    386694}
     
    17232031/** @copydoc kLdrModRelocateBits */
    17242032static int kldrModMachORelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
    1725                                  PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
     2033                                    PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
    17262034{
    17272035    PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
     
    17402048
    17412049/**
    1742  * The PE module interpreter method table.
     2050 * The Mach-O module interpreter method table.
    17432051 */
    1744 KLDRMODOPS g_kLdrModPEOps =
    1745 {
    1746     "PE",
     2052KLDRMODOPS g_kLdrModMachOOps =
     2053{
     2054    "Mach-O",
    17472055    NULL,
    17482056    kldrModMachOCreate,
Note: See TracChangeset for help on using the changeset viewer.