Changeset 95635 in vbox for trunk/src/VBox/Runtime/common/ldr
- Timestamp:
- Jul 14, 2022 2:10:42 AM (3 years ago)
- svn:sync-xref-src-repo-rev:
- 152279
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/ldr/ldrPE.cpp
r95612 r95635 46 46 #include <iprt/utf16.h> 47 47 #include <iprt/x86.h> 48 #if !defined(IPRT_WITHOUT_LDR_VERIFY) || !defined(IPRT_WITHOUT_LDR_PAGE_HASHING) 49 # include <iprt/zero.h> 50 #endif 48 51 #ifndef IPRT_WITHOUT_LDR_VERIFY 49 #include <iprt/zero.h>50 52 # include <iprt/crypto/pkcs7.h> 51 53 # include <iprt/crypto/spc.h> … … 269 271 static void rtldrPEConvert32BitLoadConfigTo64Bit(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg); 270 272 static int rtldrPEApplyFixups(PRTLDRMODPE pModPe, const void *pvBitsR, void *pvBitsW, RTUINTPTR BaseAddress, RTUINTPTR OldBaseAddress); 273 #ifndef IPRT_WITHOUT_LDR_PAGE_HASHING 274 static int rtLdrPE_QueryPageHashes(PRTLDRMODPE pModPe, RTDIGESTTYPE enmDigest, void *pvBuf, size_t cbBuf, size_t *pcbRet); 275 static uint32_t rtLdrPE_GetHashablePages(PRTLDRMODPE pModPe); 276 #endif 271 277 272 278 … … 2072 2078 } 2073 2079 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 2074 2093 case RTLDRPROP_SIGNATURE_CHECKS_ENFORCED: 2075 2094 Assert(cbBuf == sizeof(bool)); … … 2198 2217 2199 2218 2200 #ifndef IPRT_WITHOUT_LDR_VERIFY2201 2219 /** 2202 2220 * Returns the digest size for the given digest type. … … 2216 2234 } 2217 2235 } 2218 #endif2219 2236 2220 2237 … … 2388 2405 } 2389 2406 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 */ 2417 static 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 */ 2444 static 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 */ 2600 static 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 */ 2390 2639 #ifndef IPRT_WITHOUT_LDR_VERIFY 2391 2640 … … 2907 3156 rtLdrPE_HashUpdate(&HashCtx, enmDigest, pbCur, cbLeft); 2908 3157 if (cbPageInFile < _4K) 2909 rtLdrPE_HashUpdate(&HashCtx, enmDigest, &g_abRTZero4K[cbPageInFile], _4K - cbPageInFile);3158 rtLdrPE_HashUpdate(&HashCtx, enmDigest, g_abRTZero4K, _4K - cbPageInFile); 2910 3159 2911 3160 /*
Note:
See TracChangeset
for help on using the changeset viewer.