VirtualBox

Changeset 95635 in vbox


Ignore:
Timestamp:
Jul 14, 2022 2:10:42 AM (3 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
152279
Message:

IPRT/ldrPE: Implemented generating page hashes (for using in signing). bugref:8691

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/ldr/ldrPE.cpp

    r95612 r95635  
    4646#include <iprt/utf16.h>
    4747#include <iprt/x86.h>
     48#if !defined(IPRT_WITHOUT_LDR_VERIFY) || !defined(IPRT_WITHOUT_LDR_PAGE_HASHING)
     49# include <iprt/zero.h>
     50#endif
    4851#ifndef IPRT_WITHOUT_LDR_VERIFY
    49 #include <iprt/zero.h>
    5052# include <iprt/crypto/pkcs7.h>
    5153# include <iprt/crypto/spc.h>
     
    269271static void rtldrPEConvert32BitLoadConfigTo64Bit(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg);
    270272static int  rtldrPEApplyFixups(PRTLDRMODPE pModPe, const void *pvBitsR, void *pvBitsW, RTUINTPTR BaseAddress, RTUINTPTR OldBaseAddress);
     273#ifndef IPRT_WITHOUT_LDR_PAGE_HASHING
     274static int  rtLdrPE_QueryPageHashes(PRTLDRMODPE pModPe, RTDIGESTTYPE enmDigest, void *pvBuf, size_t cbBuf, size_t *pcbRet);
     275static uint32_t rtLdrPE_GetHashablePages(PRTLDRMODPE pModPe);
     276#endif
    271277
    272278
     
    20722078        }
    20732079
     2080#ifndef IPRT_WITHOUT_LDR_PAGE_HASHING
     2081        case RTLDRPROP_HASHABLE_PAGES:
     2082            *pcbRet = sizeof(uint32_t);
     2083            *(uint32_t *)pvBuf = rtLdrPE_GetHashablePages(pModPe);
     2084            return VINF_SUCCESS;
     2085
     2086        case RTLDRPROP_SHA1_PAGE_HASHES:
     2087            return rtLdrPE_QueryPageHashes(pModPe, RTDIGESTTYPE_SHA1, pvBuf, cbBuf, pcbRet);
     2088
     2089        case RTLDRPROP_SHA256_PAGE_HASHES:
     2090            return rtLdrPE_QueryPageHashes(pModPe, RTDIGESTTYPE_SHA256, pvBuf, cbBuf, pcbRet);
     2091#endif
     2092
    20742093        case RTLDRPROP_SIGNATURE_CHECKS_ENFORCED:
    20752094            Assert(cbBuf == sizeof(bool));
     
    21982217
    21992218
    2200 #ifndef IPRT_WITHOUT_LDR_VERIFY
    22012219/**
    22022220 * Returns the digest size for the given digest type.
     
    22162234    }
    22172235}
    2218 #endif
    22192236
    22202237
     
    23882405}
    23892406
     2407#ifndef IPRT_WITHOUT_LDR_PAGE_HASHING
     2408
     2409/**
     2410 * Returns the size of the page hashes, including the terminator entry.
     2411 *
     2412 * Used for handling RTLDRPROP_HASHABLE_PAGES.
     2413 *
     2414 * @returns Number of page hashes.
     2415 * @param   pModPe              The PE module.
     2416 */
     2417static uint32_t rtLdrPE_GetHashablePages(PRTLDRMODPE pModPe)
     2418{
     2419    uint32_t const  cbPage = _4K;
     2420    uint32_t        cPages = 1; /* termination entry */
     2421
     2422    /* Add implicit header section: */
     2423    cPages += (pModPe->cbHeaders + cbPage - 1) / cbPage;
     2424
     2425    /* Add on disk pages for each section.  Each starts with a fresh page and
     2426       we ASSUMES that it is page aligned (in memory). */
     2427    for (uint32_t i = 0; i < pModPe->cSections; i++)
     2428    {
     2429        uint32_t const cbRawData = pModPe->paSections[i].SizeOfRawData;
     2430        if (cbRawData > 0)
     2431            cPages += (cbRawData + cbPage - 1) / cbPage;
     2432    }
     2433
     2434    return cPages;
     2435}
     2436
     2437
     2438/**
     2439 * Worker for rtLdrPE_QueryPageHashes.
     2440 *
     2441 * Keep in mind that rtldrPE_VerifyAllPageHashes does similar work, so some
     2442 * fixes may apply both places.
     2443 */
     2444static int rtLdrPE_CalcPageHashes(PRTLDRMODPE pModPe, RTDIGESTTYPE const enmDigest, uint32_t const cbHash,
     2445                                  uint8_t *pbDst, uint8_t *pbScratch, uint32_t cbScratch, uint32_t const cbPage)
     2446{
     2447    /*
     2448     * Calculate the special places.
     2449     */
     2450    RTLDRPEHASHSPECIALS SpecialPlaces = { 0, 0, 0, 0, 0, 0 }; /* shut up gcc */
     2451    int rc = rtldrPe_CalcSpecialHashPlaces(pModPe, &SpecialPlaces, NULL);
     2452    if (RT_FAILURE(rc))
     2453        return rc;
     2454
     2455    /*
     2456     * Walk section table and hash the pages in each.  Because the headers are
     2457     * in an implicit section, the loop advancing is a little funky.
     2458     */
     2459    int32_t const   cSections   = pModPe->cSections;
     2460    int32_t         iSection    = -1;
     2461    uint32_t        offRawData  = 0;
     2462    uint32_t        cbRawData   = pModPe->cbHeaders;
     2463    uint32_t        offLastPage = 0;
     2464
     2465    uint32_t const  cbScratchReadMax = cbScratch / cbPage * cbPage;
     2466    uint32_t        cbScratchRead    = 0;
     2467    uint32_t        offScratchRead   = 0;
     2468
     2469    for (;;)
     2470    {
     2471        /*
     2472         * Process the pages in this section.
     2473         */
     2474        uint32_t cPagesInSection = (cbRawData + cbPage - 1) / cbPage;
     2475        for (uint32_t iPage = 0; iPage < cPagesInSection; iPage++)
     2476        {
     2477            uint32_t const offPageInFile = offRawData + iPage * cbPage;
     2478            uint32_t const cbPageInFile  = RT_MIN(cbPage, offPageInFile - cbRawData);
     2479            offLastPage = offPageInFile;
     2480
     2481            /* Calculate and output the page offset. */
     2482            *(uint32_t *)pbDst = offPageInFile;
     2483            pbDst += sizeof(uint32_t);
     2484
     2485            /*
     2486             * Read/find in the raw page.
     2487             */
     2488            /* Did we get a cache hit? */
     2489            uint8_t *pbCur = pbScratch;
     2490            if (   offPageInFile + cbPageInFile <= offScratchRead + cbScratchRead
     2491                && offPageInFile                >= offScratchRead)
     2492                pbCur += offPageInFile - offScratchRead;
     2493            /* Missed, read more. */
     2494            else
     2495            {
     2496                offScratchRead = offPageInFile;
     2497                cbScratchRead  = SpecialPlaces.cbToHash - offPageInFile;
     2498                if (cbScratchRead > cbScratchReadMax)
     2499                    cbScratchRead = cbScratchReadMax;
     2500                rc = pModPe->Core.pReader->pfnRead(pModPe->Core.pReader, pbCur, cbScratchRead, offScratchRead);
     2501                if (RT_FAILURE(rc))
     2502                    return VERR_LDRVI_READ_ERROR_HASH;
     2503            }
     2504
     2505            /*
     2506             * Hash it.
     2507             */
     2508            RTLDRPEHASHCTXUNION HashCtx;
     2509            rc = rtLdrPE_HashInit(&HashCtx, enmDigest);
     2510            AssertRCReturn(rc, rc);
     2511
     2512            /* Deal with special places. */
     2513            uint32_t cbLeft = cbPageInFile;
     2514            if (offPageInFile < SpecialPlaces.offEndSpecial)
     2515            {
     2516                uint32_t off = offPageInFile;
     2517                if (off < SpecialPlaces.offCksum)
     2518                {
     2519                    /* Hash everything up to the checksum. */
     2520                    uint32_t cbChunk = RT_MIN(SpecialPlaces.offCksum - off, cbLeft);
     2521                    rtLdrPE_HashUpdate(&HashCtx, enmDigest, pbCur, cbChunk);
     2522                    pbCur  += cbChunk;
     2523                    cbLeft -= cbChunk;
     2524                    off    += cbChunk;
     2525                }
     2526
     2527                if (off < SpecialPlaces.offCksum + SpecialPlaces.cbCksum && off >= SpecialPlaces.offCksum)
     2528                {
     2529                    /* Skip the checksum */
     2530                    uint32_t cbChunk = RT_MIN(SpecialPlaces.offCksum + SpecialPlaces.cbCksum - off, cbLeft);
     2531                    pbCur  += cbChunk;
     2532                    cbLeft -= cbChunk;
     2533                    off    += cbChunk;
     2534                }
     2535
     2536                if (off < SpecialPlaces.offSecDir && off >= SpecialPlaces.offCksum + SpecialPlaces.cbCksum)
     2537                {
     2538                    /* Hash everything between the checksum and the data dir entry. */
     2539                    uint32_t cbChunk = RT_MIN(SpecialPlaces.offSecDir - off, cbLeft);
     2540                    rtLdrPE_HashUpdate(&HashCtx, enmDigest, pbCur, cbChunk);
     2541                    pbCur  += cbChunk;
     2542                    cbLeft -= cbChunk;
     2543                    off    += cbChunk;
     2544                }
     2545
     2546                if (off < SpecialPlaces.offSecDir + SpecialPlaces.cbSecDir && off >= SpecialPlaces.offSecDir)
     2547                {
     2548                    /* Skip the security data directory entry. */
     2549                    uint32_t cbChunk = RT_MIN(SpecialPlaces.offSecDir + SpecialPlaces.cbSecDir - off, cbLeft);
     2550                    pbCur  += cbChunk;
     2551                    cbLeft -= cbChunk;
     2552                    off    += cbChunk;
     2553                }
     2554            }
     2555
     2556            rtLdrPE_HashUpdate(&HashCtx, enmDigest, pbCur, cbLeft);
     2557            if (cbPageInFile < cbPage)
     2558                rtLdrPE_HashUpdate(&HashCtx, enmDigest, g_abRTZero4K, cbPage - cbPageInFile);
     2559
     2560            /*
     2561             * Finish the hash calculation storing it in the table.
     2562             */
     2563            rtLdrPE_HashFinalize(&HashCtx, enmDigest, (PRTLDRPEHASHRESUNION)pbDst);
     2564            pbDst += cbHash;
     2565        }
     2566
     2567        /*
     2568         * Advance to the next section.
     2569         */
     2570        iSection++;
     2571        if (iSection >= cSections)
     2572            break;
     2573        offRawData = pModPe->paSections[iSection].PointerToRawData;
     2574        cbRawData  = pModPe->paSections[iSection].SizeOfRawData;
     2575    }
     2576
     2577    /*
     2578     * Add the terminator entry.
     2579     */
     2580    *(uint32_t *)pbDst = offLastPage;
     2581    RT_BZERO(&pbDst[sizeof(uint32_t)], cbHash);
     2582
     2583    return VINF_SUCCESS;
     2584}
     2585
     2586
     2587/**
     2588 * Creates the page hash table for the image.
     2589 *
     2590 * Used for handling RTLDRPROP_SHA1_PAGE_HASHES and
     2591 * RTLDRPROP_SHA256_PAGE_HASHES.
     2592 *
     2593 * @returns IPRT status code.
     2594 * @param   pModPe              The PE module.
     2595 * @param   enmDigest           The digest to use when hashing the pages.
     2596 * @param   pvBuf               Where to return the page hash table.
     2597 * @param   cbBuf               The size of the buffer @a pvBuf points to.
     2598 * @param   pcbRet              Where to return the output/needed size.
     2599 */
     2600static int rtLdrPE_QueryPageHashes(PRTLDRMODPE pModPe, RTDIGESTTYPE enmDigest, void *pvBuf, size_t cbBuf, size_t *pcbRet)
     2601{
     2602    /*
     2603     * Check that we've got enough buffer space.
     2604     */
     2605    uint32_t const cbPage   = _4K;
     2606    uint32_t const cEntries = rtLdrPE_GetHashablePages(pModPe);
     2607    uint32_t const cbHash   = rtLdrPE_HashGetHashSize(enmDigest);
     2608    AssertReturn(cbHash > 0, VERR_INTERNAL_ERROR_3);
     2609
     2610    size_t const   cbNeeded = (size_t)(cbHash + 4) * cEntries;
     2611    *pcbRet = cbNeeded;
     2612    if (cbNeeded > cbBuf)
     2613        return VERR_BUFFER_OVERFLOW;
     2614
     2615    /*
     2616     * Allocate a scratch buffer and call worker to do the real job.
     2617     */
     2618# ifdef IN_RING0
     2619    uint32_t    cbScratch = _256K - _4K;
     2620# else
     2621    uint32_t    cbScratch = _1M;
     2622# endif
     2623    void       *pvScratch = RTMemTmpAlloc(cbScratch);
     2624    if (!pvScratch)
     2625    {
     2626        cbScratch = _4K;
     2627        pvScratch = RTMemTmpAlloc(cbScratch);
     2628        if (!pvScratch)
     2629            return VERR_NO_TMP_MEMORY;
     2630    }
     2631
     2632    int rc = rtLdrPE_CalcPageHashes(pModPe, enmDigest, cbHash, (uint8_t *)pvBuf, (uint8_t *)pvScratch, cbScratch, cbPage);
     2633
     2634    RTMemTmpFree(pvScratch);
     2635    return rc;
     2636}
     2637
     2638#endif /* !IPRT_WITHOUT_LDR_PAGE_HASHING */
    23902639#ifndef IPRT_WITHOUT_LDR_VERIFY
    23912640
     
    29073156        rtLdrPE_HashUpdate(&HashCtx, enmDigest, pbCur, cbLeft);
    29083157        if (cbPageInFile < _4K)
    2909             rtLdrPE_HashUpdate(&HashCtx, enmDigest, &g_abRTZero4K[cbPageInFile], _4K - cbPageInFile);
     3158            rtLdrPE_HashUpdate(&HashCtx, enmDigest, g_abRTZero4K, _4K - cbPageInFile);
    29103159
    29113160        /*
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette