Changeset 51770 in vbox for trunk/src/VBox/Runtime/common
- Timestamp:
- Jul 1, 2014 6:14:02 PM (11 years ago)
- svn:sync-xref-src-repo-rev:
- 94611
- Location:
- trunk
- Files:
-
- 108 added
- 1 deleted
- 21 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
- Property svn:mergeinfo changed
/branches/bird/hardenedwindows (added) merged: 92692-94610
- Property svn:mergeinfo changed
-
trunk/src/VBox
- Property svn:mergeinfo changed
/branches/bird/hardenedwindows/src/VBox (added) merged: 92692-94610
- Property svn:mergeinfo changed
-
trunk/src/VBox/Runtime/common/err/errinfo.cpp
r44529 r51770 1 1 /* $Id$ */ 2 2 /** @file 3 * IPRT - Error Info .3 * IPRT - Error Info, Setters. 4 4 */ 5 5 6 6 /* 7 * Copyright (C) 2010-201 2Oracle Corporation7 * Copyright (C) 2010-2014 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 33 33 34 34 #include <iprt/assert.h> 35 #include <iprt/mem.h>36 35 #include <iprt/string.h> 37 36 38 37 39 40 RTDECL(PRTERRINFO) RTErrInfoAlloc(size_t cbMsg) 41 { 42 PRTERRINFO pErrInfo; 43 RTErrInfoAllocEx(cbMsg, &pErrInfo); 44 return pErrInfo; 45 } 46 47 48 RTDECL(int) RTErrInfoAllocEx(size_t cbMsg, PRTERRINFO *ppErrInfo) 49 { 50 if (cbMsg == 0) 51 cbMsg = _4K; 52 else 53 cbMsg = RT_ALIGN_Z(cbMsg, 256); 54 55 PRTERRINFO pErrInfo; 56 *ppErrInfo = pErrInfo = (PRTERRINFO)RTMemTmpAlloc(sizeof(*pErrInfo) + cbMsg); 57 if (RT_UNLIKELY(!pErrInfo)) 58 return VERR_NO_TMP_MEMORY; 59 60 RTErrInfoInit(pErrInfo, (char *)(pErrInfo + 1), cbMsg); 61 pErrInfo->fFlags = RTERRINFO_FLAGS_T_ALLOC | RTERRINFO_FLAGS_MAGIC; 62 return VINF_SUCCESS; 63 } 64 65 66 RTDECL(void) RTErrInfoFree(PRTERRINFO pErrInfo) 67 { 68 RTMemTmpFree(pErrInfo); 69 } 70 71 72 RTDECL(int) RTErrInfoSet(PRTERRINFO pErrInfo, int rc, const char *pszMsg) 38 RTDECL(int) RTErrInfoSet(PRTERRINFO pErrInfo, int rc, const char *pszMsg) 73 39 { 74 40 if (pErrInfo) … … 85 51 86 52 87 RTDECL(int) 53 RTDECL(int) RTErrInfoSetF(PRTERRINFO pErrInfo, int rc, const char *pszFormat, ...) 88 54 { 89 55 va_list va; … … 95 61 96 62 97 RTDECL(int) 63 RTDECL(int) RTErrInfoSetV(PRTERRINFO pErrInfo, int rc, const char *pszFormat, va_list va) 98 64 { 99 65 if (pErrInfo) … … 109 75 } 110 76 77 78 RTDECL(int) RTErrInfoAdd(PRTERRINFO pErrInfo, int rc, const char *pszMsg) 79 { 80 if (pErrInfo) 81 { 82 AssertPtr(pErrInfo); 83 if (pErrInfo->fFlags & RTERRINFO_FLAGS_SET) 84 RTStrCat(pErrInfo->pszMsg, pErrInfo->cbMsg, pszMsg); 85 else 86 { 87 while (*pszMsg == ' ') 88 pszMsg++; 89 return RTErrInfoSet(pErrInfo, rc, pszMsg); 90 } 91 } 92 return rc; 93 } 94 95 96 RTDECL(int) RTErrInfoAddF(PRTERRINFO pErrInfo, int rc, const char *pszFormat, ...) 97 { 98 va_list va; 99 va_start(va, pszFormat); 100 RTErrInfoAddV(pErrInfo, rc, pszFormat, va); 101 va_end(va); 102 return rc; 103 } 104 105 106 RTDECL(int) RTErrInfoAddV(PRTERRINFO pErrInfo, int rc, const char *pszFormat, va_list va) 107 { 108 if (pErrInfo) 109 { 110 AssertPtr(pErrInfo); 111 Assert((pErrInfo->fFlags & RTERRINFO_FLAGS_MAGIC_MASK) == RTERRINFO_FLAGS_MAGIC); 112 if (pErrInfo->fFlags & RTERRINFO_FLAGS_SET) 113 { 114 char *pszOut = (char *)memchr(pErrInfo->pszMsg, '\0', pErrInfo->cbMsg - 2); 115 if (pszOut) 116 RTStrPrintfV(pszOut, &pErrInfo->pszMsg[pErrInfo->cbMsg] - pszOut, pszFormat, va); 117 } 118 else 119 { 120 while (*pszFormat == ' ') 121 pszFormat++; 122 return RTErrInfoSetV(pErrInfo, rc, pszFormat, va); 123 } 124 } 125 return rc; 126 } 127 -
trunk/src/VBox/Runtime/common/err/errmsg.cpp
r48935 r51770 46 46 static const RTSTATUSMSG g_aStatusMsgs[] = 47 47 { 48 #include "errmsgdata.h" 48 #ifndef IPRT_NO_ERROR_DATA 49 # include "errmsgdata.h" 50 #else 51 { "Success.", "Success.", "VINF_SUCCESS", 0 }, 52 #endif 49 53 { NULL, NULL, NULL, 0 } 50 54 }; … … 77 81 unsigned iFound = ~0; 78 82 unsigned i; 79 for (i = 0; i < RT_ELEMENTS(g_aStatusMsgs) ; i++)83 for (i = 0; i < RT_ELEMENTS(g_aStatusMsgs) - 1; i++) 80 84 { 81 85 if (g_aStatusMsgs[i].iCode == rc) … … 105 109 */ 106 110 int iMsg = ASMAtomicXchgU32(&g_iUnknownMsgs, (g_iUnknownMsgs + 1) % RT_ELEMENTS(g_aUnknownMsgs)); 107 RTStrPrintf(&g_aszUnknownStr[iMsg][0], sizeof(g_aszUnknownStr[iMsg]), "Unknown Status 0x%X", rc);111 RTStrPrintf(&g_aszUnknownStr[iMsg][0], sizeof(g_aszUnknownStr[iMsg]), "Unknown Status %d (%#x)", rc, rc); 108 112 return &g_aUnknownMsgs[iMsg]; 109 113 } -
trunk/src/VBox/Runtime/common/ldr/Makefile.kup
r5430 r51770 1 -
trunk/src/VBox/Runtime/common/ldr/ldr.cpp
r49044 r51770 39 39 #include <iprt/log.h> 40 40 #include "internal/ldr.h" 41 42 43 RTDECL(bool) RTLdrIsLoadable(const char *pszFilename)44 {45 /*46 * Try to load the library.47 */48 RTLDRMOD hLib;49 int rc = RTLdrLoad(pszFilename, &hLib);50 if (RT_SUCCESS(rc))51 {52 RTLdrClose(hLib);53 return true;54 }55 return false;56 }57 RT_EXPORT_SYMBOL(RTLdrIsLoadable);58 41 59 42 -
trunk/src/VBox/Runtime/common/ldr/ldrELF.cpp
r48935 r51770 117 117 * @param enmArch Architecture specifier. 118 118 * @param phLdrMod Where to store the handle. 119 * @param pErrInfo Where to return extended error information. Optional. 119 120 */ 120 int rtldrELFOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTLDRMOD phLdrMod )121 int rtldrELFOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo) 121 122 { 122 123 const char *pszLogName = pReader->pfnLogName(pReader); NOREF(pszLogName); -
trunk/src/VBox/Runtime/common/ldr/ldrELFRelocatable.cpp.h
r49044 r51770 1402 1402 RTLDRELF_NAME(ReadDbgInfo), 1403 1403 NULL /*pfnQueryProp*/, 1404 NULL /*pfnVerifySignature*/, 1405 NULL /*pfnHashImage*/, 1404 1406 42 1405 1407 }; -
trunk/src/VBox/Runtime/common/ldr/ldrEx.cpp
r49044 r51770 33 33 #include "internal/iprt.h" 34 34 35 #include <iprt/alloc.h>36 35 #include <iprt/assert.h> 36 #include <iprt/err.h> 37 37 #include <iprt/log.h> 38 #include <iprt/md5.h> 39 #include <iprt/mem.h> 40 #include <iprt/sha.h> 38 41 #include <iprt/string.h> 39 #include <iprt/err.h>40 42 #include "internal/ldr.h" 41 43 #include "internal/ldrMZ.h" 42 44 43 44 /** 45 * Open part with reader. 46 * 47 * @returns iprt status code. 48 * @param pReader The loader reader instance which will provide the raw image bits. 49 * @param fFlags Reserved, MBZ. 50 * @param enmArch Architecture specifier. 51 * @param phMod Where to store the handle. 52 */ 53 int rtldrOpenWithReader(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTLDRMOD phMod) 54 { 45 #ifdef LDR_ONLY_PE 46 # undef LDR_WITH_PE 47 # undef LDR_WITH_KLDR 48 # undef LDR_WITH_ELF 49 # undef LDR_WITH_LX 50 # undef LDR_WITH_LE 51 # undef LDR_WITH_NE 52 # undef LDR_WITH_MZ 53 # undef LDR_WITH_AOUT 54 # define LDR_WITH_PE 55 #endif 56 57 58 RTDECL(int) RTLdrOpenWithReader(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTLDRMOD phMod, PRTERRINFO pErrInfo) 59 { 60 /* 61 * Resolve RTLDRARCH_HOST. 62 */ 63 if (enmArch == RTLDRARCH_HOST) 64 #if defined(RT_ARCH_AMD64) 65 enmArch = RTLDRARCH_AMD64; 66 #elif defined(RT_ARCH_X86) 67 enmArch = RTLDRARCH_X86_32; 68 #else 69 enmArch = RTLDRARCH_WHATEVER; 70 #endif 71 55 72 /* 56 73 * Read and verify the file signature. … … 105 122 if (uSign.u32 == IMAGE_NT_SIGNATURE) 106 123 #ifdef LDR_WITH_PE 107 rc = rtldrPEOpen(pReader, fFlags, enmArch, offHdr, phMod );124 rc = rtldrPEOpen(pReader, fFlags, enmArch, offHdr, phMod, pErrInfo); 108 125 #else 109 126 rc = VERR_PE_EXE_NOT_SUPPORTED; … … 111 128 else if (uSign.u32 == IMAGE_ELF_SIGNATURE) 112 129 #if defined(LDR_WITH_ELF) 113 rc = rtldrELFOpen(pReader, fFlags, enmArch, phMod );130 rc = rtldrELFOpen(pReader, fFlags, enmArch, phMod, pErrInfo); 114 131 #else 115 132 rc = VERR_ELF_EXE_NOT_SUPPORTED; … … 117 134 else if (uSign.au16[0] == IMAGE_LX_SIGNATURE) 118 135 #ifdef LDR_WITH_LX 119 rc = rtldrLXOpen(pReader, fFlags, enmArch, offHdr, phMod );136 rc = rtldrLXOpen(pReader, fFlags, enmArch, offHdr, phMod, pErrInfo); 120 137 #else 121 138 rc = VERR_LX_EXE_NOT_SUPPORTED; … … 123 140 else if (uSign.au16[0] == IMAGE_LE_SIGNATURE) 124 141 #ifdef LDR_WITH_LE 125 rc = rtldrLEOpen(pReader, fFlags, enmArch, phMod );142 rc = rtldrLEOpen(pReader, fFlags, enmArch, phMod, pErrInfo); 126 143 #else 127 144 rc = VERR_LE_EXE_NOT_SUPPORTED; … … 129 146 else if (uSign.au16[0] == IMAGE_NE_SIGNATURE) 130 147 #ifdef LDR_WITH_NE 131 rc = rtldrNEOpen(pReader, fFlags, enmArch, phMod );148 rc = rtldrNEOpen(pReader, fFlags, enmArch, phMod, pErrInfo); 132 149 #else 133 150 rc = VERR_NE_EXE_NOT_SUPPORTED; … … 135 152 else if (uSign.au16[0] == IMAGE_DOS_SIGNATURE) 136 153 #ifdef LDR_WITH_MZ 137 rc = rtldrMZOpen(pReader, fFlags, enmArch, phMod );154 rc = rtldrMZOpen(pReader, fFlags, enmArch, phMod, pErrInfo); 138 155 #else 139 156 rc = VERR_MZ_EXE_NOT_SUPPORTED; … … 143 160 0) 144 161 #ifdef LDR_WITH_AOUT 145 rc = rtldrAOUTOpen(pReader, fFlags, enmArch, phMod );162 rc = rtldrAOUTOpen(pReader, fFlags, enmArch, phMod, pErrInfo); 146 163 #else 147 164 rc = VERR_AOUT_EXE_NOT_SUPPORTED; … … 158 175 /* Try kLdr if it's a format we don't recognize. */ 159 176 if (rc <= VERR_INVALID_EXE_SIGNATURE && rc > VERR_BAD_EXE_FORMAT) 160 rc = rtldrkLdrOpen(pReader, fFlags, enmArch, phMod); 177 { 178 int rc2 = rtldrkLdrOpen(pReader, fFlags, enmArch, phMod, pErrInfo); 179 if (rc2 == VERR_MZ_EXE_NOT_SUPPORTED) /* Quick fix for bad return code. */ 180 rc = rc; 181 } 161 182 #endif 162 183 … … 542 563 RTDECL(int) RTLdrQueryProp(RTLDRMOD hLdrMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf) 543 564 { 565 return RTLdrQueryPropEx(hLdrMod, enmProp, pvBuf, cbBuf, NULL); 566 } 567 RT_EXPORT_SYMBOL(RTLdrQueryProp); 568 569 570 RTDECL(int) RTLdrQueryPropEx(RTLDRMOD hLdrMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf, size_t *pcbRet) 571 { 544 572 AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), RTLDRENDIAN_INVALID); 545 573 PRTLDRMODINTERNAL pMod = (PRTLDRMODINTERNAL)hLdrMod; 546 574 575 AssertPtrNullReturn(pcbRet, VERR_INVALID_POINTER); 576 size_t cbRet; 577 if (!pcbRet) 578 pcbRet = &cbRet; 579 547 580 /* 548 581 * Do some pre screening of the input … … 551 584 { 552 585 case RTLDRPROP_UUID: 586 *pcbRet = sizeof(RTUUID); 553 587 AssertReturn(cbBuf == sizeof(RTUUID), VERR_INVALID_PARAMETER); 554 588 break; 555 589 case RTLDRPROP_TIMESTAMP_SECONDS: 590 *pcbRet = sizeof(int64_t); 556 591 AssertReturn(cbBuf == sizeof(int32_t) || cbBuf == sizeof(int64_t), VERR_INVALID_PARAMETER); 557 592 break; 593 case RTLDRPROP_IS_SIGNED: 594 *pcbRet = sizeof(bool); 595 AssertReturn(cbBuf == sizeof(bool), VERR_INVALID_PARAMETER); 596 break; 597 case RTLDRPROP_PKCS7_SIGNED_DATA: 598 *pcbRet = 0; 599 break; 600 case RTLDRPROP_SIGNATURE_CHECKS_ENFORCED: 601 *pcbRet = sizeof(bool); 602 AssertReturn(cbBuf == sizeof(bool), VERR_INVALID_PARAMETER); 603 break; 604 558 605 default: 559 606 AssertFailedReturn(VERR_INVALID_FUNCTION); … … 566 613 if (!pMod->pOps->pfnQueryProp) 567 614 return VERR_NOT_SUPPORTED; 568 return pMod->pOps->pfnQueryProp(pMod, enmProp, pvBuf, cbBuf); 569 } 570 RT_EXPORT_SYMBOL(RTLdrQueryProp); 615 return pMod->pOps->pfnQueryProp(pMod, enmProp, pvBuf, cbBuf, pcbRet); 616 } 617 RT_EXPORT_SYMBOL(RTLdrQueryPropEx); 618 619 620 RTDECL(int) RTLdrVerifySignature(RTLDRMOD hLdrMod, PFNRTLDRVALIDATESIGNEDDATA pfnCallback, void *pvUser, PRTERRINFO pErrInfo) 621 { 622 AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), VERR_INVALID_HANDLE); 623 PRTLDRMODINTERNAL pMod = (PRTLDRMODINTERNAL)hLdrMod; 624 AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER); 625 626 /* 627 * Call the image specific worker, if there is one. 628 */ 629 if (!pMod->pOps->pfnVerifySignature) 630 return VERR_NOT_SUPPORTED; 631 return pMod->pOps->pfnVerifySignature(pMod, pfnCallback, pvUser, pErrInfo); 632 } 633 RT_EXPORT_SYMBOL(RTLdrVerifySignature); 634 635 636 RTDECL(int) RTLdrHashImage(RTLDRMOD hLdrMod, RTDIGESTTYPE enmDigest, char *pszDigest, size_t cbDigest) 637 { 638 AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), VERR_INVALID_HANDLE); 639 PRTLDRMODINTERNAL pMod = (PRTLDRMODINTERNAL)hLdrMod; 640 641 /* 642 * Make sure there is sufficient space for the wanted digest and that 643 * it's supported. 644 */ 645 switch (enmDigest) 646 { 647 case RTDIGESTTYPE_MD5: AssertReturn(cbDigest >= RTMD5_DIGEST_LEN + 1, VERR_BUFFER_OVERFLOW); break; 648 case RTDIGESTTYPE_SHA1: AssertReturn(cbDigest >= RTSHA1_DIGEST_LEN + 1, VERR_BUFFER_OVERFLOW); break; 649 case RTDIGESTTYPE_SHA256: AssertReturn(cbDigest >= RTSHA256_DIGEST_LEN + 1, VERR_BUFFER_OVERFLOW); break; 650 case RTDIGESTTYPE_SHA512: AssertReturn(cbDigest >= RTSHA512_DIGEST_LEN + 1, VERR_BUFFER_OVERFLOW); break; 651 default: 652 if (enmDigest > RTDIGESTTYPE_INVALID && enmDigest < RTDIGESTTYPE_END) 653 return VERR_NOT_SUPPORTED; 654 AssertFailedReturn(VERR_INVALID_PARAMETER); 655 } 656 AssertPtrReturn(pszDigest, VERR_INVALID_POINTER); 657 658 /* 659 * Call the image specific worker, if there is one. 660 */ 661 if (!pMod->pOps->pfnHashImage) 662 return VERR_NOT_SUPPORTED; 663 return pMod->pOps->pfnHashImage(pMod, enmDigest, pszDigest, cbDigest); 664 } 665 RT_EXPORT_SYMBOL(RTLdrHashImage); 571 666 572 667 -
trunk/src/VBox/Runtime/common/ldr/ldrFile.cpp
r48935 r51770 218 218 if (RT_SUCCESS(rc)) 219 219 { 220 pFileReader->Core.uMagic = RTLDRREADER_MAGIC; 220 221 pFileReader->Core.pfnRead = rtldrFileRead; 221 222 pFileReader->Core.pfnTell = rtldrFileTell; … … 258 259 259 260 /* 260 * Resolve RTLDRARCH_HOST.261 */262 if (enmArch == RTLDRARCH_HOST)263 #if defined(RT_ARCH_AMD64)264 enmArch = RTLDRARCH_AMD64;265 #elif defined(RT_ARCH_X86)266 enmArch = RTLDRARCH_X86_32;267 #else268 enmArch = RTLDRARCH_WHATEVER;269 #endif270 271 /*272 261 * Create file reader & invoke worker which identifies and calls the image interpreter. 273 262 */ … … 276 265 if (RT_SUCCESS(rc)) 277 266 { 278 rc = rtldrOpenWithReader(pReader, fFlags, enmArch, phLdrMod);267 rc = RTLdrOpenWithReader(pReader, fFlags, enmArch, phLdrMod, NULL); 279 268 if (RT_SUCCESS(rc)) 280 269 { … … 309 298 310 299 /* 311 * Resolve RTLDRARCH_HOST.312 */313 if (enmArch == RTLDRARCH_HOST)314 # if defined(RT_ARCH_AMD64)315 enmArch = RTLDRARCH_AMD64;316 # elif defined(RT_ARCH_X86)317 enmArch = RTLDRARCH_X86_32;318 # else319 enmArch = RTLDRARCH_WHATEVER;320 # endif321 322 /*323 300 * Create file reader & invoke worker which identifies and calls the image interpreter. 324 301 */ … … 327 304 if (RT_SUCCESS(rc)) 328 305 { 329 rc = rtldrkLdrOpen(pReader, fFlags, enmArch, phLdrMod );306 rc = rtldrkLdrOpen(pReader, fFlags, enmArch, phLdrMod, NULL); 330 307 if (RT_SUCCESS(rc)) 331 308 { -
trunk/src/VBox/Runtime/common/ldr/ldrMemory.cpp
r51519 r51770 244 244 pThis->pvMapping = NULL; 245 245 pThis->cMappings = 0; 246 pThis->Core. pszName = "rdrmem";246 pThis->Core.uMagic = RTLDRREADER_MAGIC; 247 247 pThis->Core.pfnRead = rtldrRdrMem_Read; 248 248 pThis->Core.pfnTell = rtldrRdrMem_Tell; … … 305 305 if (RT_SUCCESS(rc)) 306 306 { 307 rc = rtldrOpenWithReader(pReader, fFlags, enmArch, phLdrMod);307 rc = RTLdrOpenWithReader(pReader, fFlags, enmArch, phLdrMod, NULL); 308 308 if (RT_SUCCESS(rc)) 309 309 { -
trunk/src/VBox/Runtime/common/ldr/ldrNative.cpp
r49044 r51770 71 71 rtldrNativeEnumSymbols, 72 72 /* ext: */ 73 NULL, 74 NULL, 73 75 NULL, 74 76 NULL, … … 319 321 RT_EXPORT_SYMBOL(RTLdrGetNativeHandle); 320 322 323 324 RTDECL(bool) RTLdrIsLoadable(const char *pszFilename) 325 { 326 /* 327 * Try to load the library. 328 */ 329 RTLDRMOD hLib; 330 int rc = RTLdrLoad(pszFilename, &hLib); 331 if (RT_SUCCESS(rc)) 332 { 333 RTLdrClose(hLib); 334 return true; 335 } 336 return false; 337 } 338 RT_EXPORT_SYMBOL(RTLdrIsLoadable); 339 -
trunk/src/VBox/Runtime/common/ldr/ldrPE.cpp
r49044 r51770 33 33 #include "internal/iprt.h" 34 34 35 #include <iprt/alloc.h>36 35 #include <iprt/assert.h> 36 #include <iprt/asm.h> 37 #include <iprt/err.h> 37 38 #include <iprt/log.h> 39 #include <iprt/md5.h> 40 #include <iprt/mem.h> 38 41 #include <iprt/path.h> 42 #include <iprt/sha.h> 39 43 #include <iprt/string.h> 40 #include <iprt/err.h> 44 #ifndef IPRT_WITHOUT_LDR_VERIFY 45 # include <iprt/crypto/pkcs7.h> 46 # include <iprt/crypto/spc.h> 47 # include <iprt/crypto/x509.h> 48 #endif 41 49 #include <iprt/formats/codeview.h> 42 50 #include "internal/ldrPE.h" … … 53 61 */ 54 62 #define PE_RVA2TYPE(pvBits, rva, type) ((type) ((uintptr_t)pvBits + (uintptr_t)(rva)) ) 63 64 /** The max size of the security directory. */ 65 #ifdef IN_RING3 66 # define RTLDRMODPE_MAX_SECURITY_DIR_SIZE _4M 67 #else 68 # define RTLDRMODPE_MAX_SECURITY_DIR_SIZE _1M 69 #endif 55 70 56 71 … … 92 107 /** The image timestamp. */ 93 108 uint32_t uTimestamp; 109 /** Set if the image is 64-bit, clear if 32-bit. */ 110 bool f64Bit; 94 111 /** The import data directory entry. */ 95 112 IMAGE_DATA_DIRECTORY ImportDir; … … 100 117 /** The debug directory entry. */ 101 118 IMAGE_DATA_DIRECTORY DebugDir; 102 } RTLDRMODPE, *PRTLDRMODPE; 119 /** The security directory entry. */ 120 IMAGE_DATA_DIRECTORY SecurityDir; 121 122 /** Offset of the first PKCS \#7 SignedData signature if present. */ 123 uint32_t offPkcs7SignedData; 124 /** Size of the first PKCS \#7 SignedData. */ 125 uint32_t cbPkcs7SignedData; 126 127 /** Copy of the optional header field DllCharacteristics. */ 128 uint16_t fDllCharacteristics; 129 } RTLDRMODPE; 130 /** Pointer to the instance data for a PE loader module. */ 131 typedef RTLDRMODPE *PRTLDRMODPE; 132 103 133 104 134 /** … … 132 162 133 163 164 /** 165 * PE hash context union. 166 */ 167 typedef union RTLDRPEHASHCTXUNION 168 { 169 RTSHA512CONTEXT Sha512; 170 RTSHA256CONTEXT Sha256; 171 RTSHA1CONTEXT Sha1; 172 RTMD5CONTEXT Md5; 173 } RTLDRPEHASHCTXUNION; 174 /** Pointer to a PE hash context union. */ 175 typedef RTLDRPEHASHCTXUNION *PRTLDRPEHASHCTXUNION; 176 177 178 /** 179 * PE hash digests 180 */ 181 typedef union RTLDRPEHASHRESUNION 182 { 183 uint8_t abSha512[RTSHA512_HASH_SIZE]; 184 uint8_t abSha256[RTSHA256_HASH_SIZE]; 185 uint8_t abSha1[RTSHA1_HASH_SIZE]; 186 uint8_t abMd5[RTMD5_HASH_SIZE]; 187 } RTLDRPEHASHRESUNION; 188 /** Pointer to a PE hash work set. */ 189 typedef RTLDRPEHASHRESUNION *PRTLDRPEHASHRESUNION; 190 191 /** 192 * Special places to watch out for when hashing a PE image. 193 */ 194 typedef struct RTLDRPEHASHSPECIALS 195 { 196 uint32_t cbToHash; 197 uint32_t offCksum; 198 uint32_t cbCksum; 199 uint32_t offSecDir; 200 uint32_t cbSecDir; 201 uint32_t offEndSpecial; 202 } RTLDRPEHASHSPECIALS; 203 /** Pointer to the structure with the special hash places. */ 204 typedef RTLDRPEHASHSPECIALS *PRTLDRPEHASHSPECIALS; 205 206 207 #ifndef IPRT_WITHOUT_LDR_VERIFY 208 /** 209 * Parsed signature data. 210 */ 211 typedef struct RTLDRPESIGNATURE 212 { 213 /** The outer content info wrapper. */ 214 RTCRPKCS7CONTENTINFO ContentInfo; 215 /** Pointer to the decoded SignedData inside the ContentInfo member. */ 216 PRTCRPKCS7SIGNEDDATA pSignedData; 217 /** Pointer to the indirect data content. */ 218 PRTCRSPCINDIRECTDATACONTENT pIndData; 219 /** The digest type employed by the signature. */ 220 RTDIGESTTYPE enmDigest; 221 222 /** Pointer to the raw signatures. This is allocated in the continuation of 223 * this structure to keep things simple. The size is given by the security 224 * export directory. */ 225 WIN_CERTIFICATE const *pRawData; 226 227 /** Hash scratch data. */ 228 RTLDRPEHASHCTXUNION HashCtx; 229 /** Hash result. */ 230 RTLDRPEHASHRESUNION HashRes; 231 } RTLDRPESIGNATURE; 232 /** Pointed to SigneData parsing stat and output. */ 233 typedef RTLDRPESIGNATURE *PRTLDRPESIGNATURE; 234 #endif 235 236 134 237 /******************************************************************************* 135 238 * Internal Functions * … … 251 354 { 252 355 if ((RTFOFF)offFile + cbToRead > cbFile) 253 cbToRead = cbFile - (RTFOFF)offFile;356 cbToRead = (uint32_t)(cbFile - (RTFOFF)offFile); 254 357 int rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pbMem, cbToRead, offFile); 255 358 if (RT_FAILURE(rc)) … … 331 434 if (uRva == NIL_RTLDRADDR || uRva > pThis->cbImage) 332 435 { 333 if (offFile < 0 )436 if (offFile < 0 || offFile >= UINT32_MAX) 334 437 return VERR_INVALID_PARAMETER; 335 return rtldrPEReadPartFromFile(pThis, offFile, cbMem, ppvMem);336 } 337 return rtldrPEReadPartByRva(pThis, pvBits, uRva, cbMem, ppvMem);438 return rtldrPEReadPartFromFile(pThis, (uint32_t)offFile, cbMem, ppvMem); 439 } 440 return rtldrPEReadPartByRva(pThis, pvBits, (uint32_t)uRva, cbMem, ppvMem); 338 441 } 339 442 … … 549 652 rc = VERR_BAD_EXE_FORMAT; 550 653 } 551 pFirstThunk->u1.Function = Value;654 pFirstThunk->u1.Function = (uint32_t)Value; 552 655 if (pFirstThunk->u1.Function != Value) 553 656 { … … 664 767 /* Some bound checking just to be sure it works... */ 665 768 if ((uintptr_t)pbr - (uintptr_t)pBaseRelocs + pbr->SizeOfBlock > cbBaseRelocs) 666 cRelocations = (((uintptr_t)pBaseRelocs + cbBaseRelocs) - (uintptr_t)pbr - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(uint16_t); 769 cRelocations = (uint32_t)( (((uintptr_t)pBaseRelocs + cbBaseRelocs) - (uintptr_t)pbr - sizeof(IMAGE_BASE_RELOCATION)) 770 / sizeof(uint16_t) ); 667 771 668 772 /* … … 692 796 { 693 797 case IMAGE_REL_BASED_HIGHLOW: /* 32-bit, add delta. */ 694 *u.pu32 += uDelta;798 *u.pu32 += (uint32_t)uDelta; 695 799 break; 696 800 case IMAGE_REL_BASED_DIR64: /* 64-bit, add delta. */ … … 717 821 pwoffFixup++; 718 822 int32_t i32 = (uint32_t)(*u.pu16 << 16) | *pwoffFixup; 719 i32 += uDelta;823 i32 += (uint32_t)uDelta; 720 824 i32 += 0x8000; //?? 721 825 *u.pu16 = (uint16_t)(i32 >> 16); … … 760 864 761 865 /** @copydoc RTLDROPS::pfnRelocate. */ 762 static int rtldrPERelocate(PRTLDRMODINTERNAL pMod, void *pvBits, RTUINTPTR NewBaseAddress, RTUINTPTR OldBaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser) 866 static DECLCALLBACK(int) rtldrPERelocate(PRTLDRMODINTERNAL pMod, void *pvBits, RTUINTPTR NewBaseAddress, RTUINTPTR OldBaseAddress, 867 PFNRTLDRIMPORT pfnGetImport, void *pvUser) 763 868 { 764 869 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod; … … 926 1031 if (RT_SUCCESS(rc)) 927 1032 { 928 uint ptr_tuNamePrev = 0;1033 uint32_t uNamePrev = 0; 929 1034 for (uint32_t uOrdinal = 0; uOrdinal < cOrdinals; uOrdinal++) 930 1035 { … … 1063 1168 uint32_t *paRVANames = PE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, uint32_t *); 1064 1169 uint16_t *paOrdinals = PE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, uint16_t *); 1065 uint ptr_tuNamePrev = 0;1170 uint32_t uNamePrev = 0; 1066 1171 unsigned cOrdinals = RT_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions); 1067 1172 for (unsigned uOrdinal = 0; uOrdinal < cOrdinals; uOrdinal++) … … 1074 1179 const char *pszName = NULL; 1075 1180 /* Search from previous + 1 to the end. */ 1076 u nsigneduName = uNamePrev + 1;1181 uint32_t uName = uNamePrev + 1; 1077 1182 while (uName < pExpDir->NumberOfNames) 1078 1183 { … … 1147 1252 1148 1253 /* 1254 * Allocate temporary memory for a path buffer (this code is also compiled 1255 * and maybe even used in stack starved environments). 1256 */ 1257 char *pszPath = (char *)RTMemTmpAlloc(RTPATH_MAX); 1258 if (!pszPath) 1259 return VERR_NO_TMP_MEMORY; 1260 1261 /* 1149 1262 * Get the debug directory. 1150 1263 */ … … 1156 1269 (void const **)&paDbgDir); 1157 1270 if (RT_FAILURE(rcRet)) 1271 { 1272 RTMemTmpFree(pszPath); 1158 1273 return rcRet; 1274 } 1159 1275 1160 1276 /* … … 1170 1286 1171 1287 void const *pvPart = NULL; 1172 char szPath[RTPATH_MAX];1173 1288 RTLDRDBGINFO DbgInfo; 1174 1289 RT_ZERO(DbgInfo.u); … … 1190 1305 DbgInfo.u.Cv.uMinorVer = paDbgDir[i].MinorVersion; 1191 1306 DbgInfo.u.Cv.uTimestamp = paDbgDir[i].TimeDateStamp; 1192 if ( paDbgDir[i].SizeOfData < sizeof(szPath)1307 if ( paDbgDir[i].SizeOfData < RTPATH_MAX 1193 1308 && paDbgDir[i].SizeOfData > 16 1194 1309 && ( DbgInfo.LinkAddress != NIL_RTLDRADDR … … 1228 1343 case IMAGE_DEBUG_TYPE_MISC: 1229 1344 DbgInfo.enmType = RTLDRDBGINFOTYPE_UNKNOWN; 1230 if ( paDbgDir[i].SizeOfData < sizeof(szPath)1345 if ( paDbgDir[i].SizeOfData < RTPATH_MAX 1231 1346 && paDbgDir[i].SizeOfData > RT_UOFFSETOF(IMAGE_DEBUG_MISC, Data)) 1232 1347 { … … 1249 1364 else 1250 1365 { 1251 char *pszPath = szPath;1252 1366 rc = RTUtf16ToUtf8Ex((PCRTUTF16)&pMisc->Data[0], 1253 1367 (pMisc->Length - RT_OFFSETOF(IMAGE_DEBUG_MISC, Data)) / sizeof(RTUTF16), 1254 &pszPath, sizeof(szPath), NULL);1368 &pszPath, RTPATH_MAX, NULL); 1255 1369 if (RT_SUCCESS(rc)) 1256 DbgInfo.pszExtFile = szPath;1370 DbgInfo.pszExtFile = pszPath; 1257 1371 else 1258 1372 rcRet = rc; /* continue without a filename. */ … … 1283 1397 it's probably the current ANSI/Windows code page for the process 1284 1398 generating the image anyways.) */ 1285 if (DbgInfo.pszExtFile && DbgInfo.pszExtFile != szPath) 1286 { 1287 char *pszPath = szPath; 1399 if (DbgInfo.pszExtFile && DbgInfo.pszExtFile != pszPath) 1400 { 1288 1401 rc = RTLatin1ToUtf8Ex(DbgInfo.pszExtFile, 1289 1402 paDbgDir[i].SizeOfData - ((uintptr_t)DbgInfo.pszExtFile - (uintptr_t)pvBits), 1290 &pszPath, sizeof(szPath), NULL);1403 &pszPath, RTPATH_MAX, NULL); 1291 1404 if (RT_FAILURE(rc)) 1292 1405 { … … 1296 1409 } 1297 1410 if (DbgInfo.pszExtFile) 1298 RTPathChangeToUnixSlashes( szPath, true /*fForce*/);1411 RTPathChangeToUnixSlashes(pszPath, true /*fForce*/); 1299 1412 1300 1413 rc = pfnCallback(pMod, &DbgInfo, pvUser); … … 1308 1421 1309 1422 rtldrPEFreePart(pModPe, pvBits, paDbgDir); 1423 RTMemTmpFree(pszPath); 1310 1424 return rcRet; 1311 1425 } … … 1491 1605 1492 1606 /** @interface_method_impl{RTLDROPS,pfnQueryProp} */ 1493 static DECLCALLBACK(int) rtldrPE_QueryProp(PRTLDRMODINTERNAL pMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf )1607 static DECLCALLBACK(int) rtldrPE_QueryProp(PRTLDRMODINTERNAL pMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf, size_t *pcbRet) 1494 1608 { 1495 1609 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod; … … 1497 1611 { 1498 1612 case RTLDRPROP_TIMESTAMP_SECONDS: 1613 Assert(*pcbRet == cbBuf); 1499 1614 if (cbBuf == sizeof(int32_t)) 1500 1615 *(int32_t *)pvBuf = pModPe->uTimestamp; … … 1502 1617 *(int64_t *)pvBuf = pModPe->uTimestamp; 1503 1618 else 1504 return VERR_INVALID_PARAMETER; 1619 AssertFailedReturn(VERR_INTERNAL_ERROR_3); 1620 break; 1621 1622 case RTLDRPROP_IS_SIGNED: 1623 Assert(cbBuf == sizeof(bool)); 1624 Assert(*pcbRet == cbBuf); 1625 *(bool *)pvBuf = pModPe->offPkcs7SignedData != 0; 1626 break; 1627 1628 case RTLDRPROP_PKCS7_SIGNED_DATA: 1629 { 1630 if (pModPe->cbPkcs7SignedData == 0) 1631 return VERR_NOT_FOUND; 1632 Assert(pModPe->offPkcs7SignedData > pModPe->SecurityDir.VirtualAddress); 1633 1634 *pcbRet = pModPe->cbPkcs7SignedData; 1635 if (cbBuf < pModPe->cbPkcs7SignedData) 1636 return VERR_BUFFER_OVERFLOW; 1637 return pModPe->Core.pReader->pfnRead(pModPe->Core.pReader, pvBuf, pModPe->cbPkcs7SignedData, 1638 pModPe->offPkcs7SignedData); 1639 } 1640 1641 case RTLDRPROP_SIGNATURE_CHECKS_ENFORCED: 1642 Assert(cbBuf == sizeof(bool)); 1643 Assert(*pcbRet == cbBuf); 1644 *(bool *)pvBuf = pModPe->offPkcs7SignedData > 0 1645 && (pModPe->fDllCharacteristics & IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY); 1505 1646 break; 1506 1647 … … 1512 1653 1513 1654 1655 1656 /* 1657 * Lots of Authenticode fun ahead. 1658 */ 1659 1660 1661 /** 1662 * Initializes the hash context. 1663 * 1664 * @returns VINF_SUCCESS or VERR_NOT_SUPPORTED. 1665 * @param pHashCtx The hash context union. 1666 * @param enmDigest The hash type we're calculating.. 1667 */ 1668 static int rtLdrPE_HashInit(PRTLDRPEHASHCTXUNION pHashCtx, RTDIGESTTYPE enmDigest) 1669 { 1670 switch (enmDigest) 1671 { 1672 case RTDIGESTTYPE_SHA512: RTSha512Init(&pHashCtx->Sha512); break; 1673 case RTDIGESTTYPE_SHA256: RTSha256Init(&pHashCtx->Sha256); break; 1674 case RTDIGESTTYPE_SHA1: RTSha1Init(&pHashCtx->Sha1); break; 1675 case RTDIGESTTYPE_MD5: RTMd5Init(&pHashCtx->Md5); break; 1676 default: AssertFailedReturn(VERR_NOT_SUPPORTED); 1677 } 1678 return VINF_SUCCESS; 1679 } 1680 1681 1682 /** 1683 * Updates the hash with more data. 1684 * 1685 * @param pHashCtx The hash context union. 1686 * @param enmDigest The hash type we're calculating.. 1687 * @param pvBuf Pointer to a buffer with bytes to add to thash. 1688 * @param cbBuf How many bytes to add from @a pvBuf. 1689 */ 1690 static void rtLdrPE_HashUpdate(PRTLDRPEHASHCTXUNION pHashCtx, RTDIGESTTYPE enmDigest, void const *pvBuf, size_t cbBuf) 1691 { 1692 switch (enmDigest) 1693 { 1694 case RTDIGESTTYPE_SHA512: RTSha512Update(&pHashCtx->Sha512, pvBuf, cbBuf); break; 1695 case RTDIGESTTYPE_SHA256: RTSha256Update(&pHashCtx->Sha256, pvBuf, cbBuf); break; 1696 case RTDIGESTTYPE_SHA1: RTSha1Update(&pHashCtx->Sha1, pvBuf, cbBuf); break; 1697 case RTDIGESTTYPE_MD5: RTMd5Update(&pHashCtx->Md5, pvBuf, cbBuf); break; 1698 default: AssertReleaseFailed(); 1699 } 1700 } 1701 1702 1703 /** 1704 * Finalizes the hash calculations. 1705 * 1706 * @param pHashCtx The hash context union. 1707 * @param enmDigest The hash type we're calculating.. 1708 * @param pHashRes The hash result union. 1709 */ 1710 static void rtLdrPE_HashFinalize(PRTLDRPEHASHCTXUNION pHashCtx, RTDIGESTTYPE enmDigest, PRTLDRPEHASHRESUNION pHashRes) 1711 { 1712 switch (enmDigest) 1713 { 1714 case RTDIGESTTYPE_SHA512: RTSha512Final(&pHashCtx->Sha512, pHashRes->abSha512); break; 1715 case RTDIGESTTYPE_SHA256: RTSha256Final(&pHashCtx->Sha256, pHashRes->abSha256); break; 1716 case RTDIGESTTYPE_SHA1: RTSha1Final(&pHashCtx->Sha1, pHashRes->abSha1); break; 1717 case RTDIGESTTYPE_MD5: RTMd5Final(pHashRes->abMd5, &pHashCtx->Md5); break; 1718 default: AssertReleaseFailed(); 1719 } 1720 } 1721 1722 1723 /** 1724 * Returns the digest size for the given digest type. 1725 * 1726 * @returns Size in bytes. 1727 * @param enmDigest The hash type in question. 1728 */ 1729 static uint32_t rtLdrPE_HashGetHashSize(RTDIGESTTYPE enmDigest) 1730 { 1731 switch (enmDigest) 1732 { 1733 case RTDIGESTTYPE_SHA512: return RTSHA512_HASH_SIZE; 1734 case RTDIGESTTYPE_SHA256: return RTSHA256_HASH_SIZE; 1735 case RTDIGESTTYPE_SHA1: return RTSHA1_HASH_SIZE; 1736 case RTDIGESTTYPE_MD5: return RTMD5_HASH_SIZE; 1737 default: AssertReleaseFailedReturn(0); 1738 } 1739 } 1740 1741 1742 /** 1743 * Calculate the special too watch out for when hashing the image. 1744 * 1745 * @returns IPRT status code. 1746 * @param pModPe The PE module. 1747 * @param pPlaces The structure where to store the special places. 1748 * @param pErrInfo Optional error info. 1749 */ 1750 static int rtldrPe_CalcSpecialHashPlaces(PRTLDRMODPE pModPe, PRTLDRPEHASHSPECIALS pPlaces, PRTERRINFO pErrInfo) 1751 { 1752 /* 1753 * If we're here despite a missing signature, we need to get the file size. 1754 */ 1755 pPlaces->cbToHash = pModPe->SecurityDir.VirtualAddress; 1756 if (pPlaces->cbToHash == 0) 1757 { 1758 RTFOFF cbFile = pModPe->Core.pReader->pfnSize(pModPe->Core.pReader); 1759 pPlaces->cbToHash = (uint32_t)cbFile; 1760 if (pPlaces->cbToHash != (RTFOFF)cbFile) 1761 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_FILE_LENGTH_ERROR, "File is too large: %RTfoff", cbFile); 1762 } 1763 1764 /* 1765 * Calculate the special places. 1766 */ 1767 pPlaces->offCksum = (uint32_t)pModPe->offNtHdrs 1768 + (pModPe->f64Bit 1769 ? RT_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.CheckSum) 1770 : RT_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.CheckSum)); 1771 pPlaces->cbCksum = RT_SIZEOFMEMB(IMAGE_NT_HEADERS32, OptionalHeader.CheckSum); 1772 pPlaces->offSecDir = (uint32_t)pModPe->offNtHdrs 1773 + (pModPe->f64Bit 1774 ? RT_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]) 1775 : RT_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY])); 1776 pPlaces->cbSecDir = sizeof(IMAGE_DATA_DIRECTORY); 1777 pPlaces->offEndSpecial = pPlaces->offSecDir + pPlaces->cbSecDir; 1778 return VINF_SUCCESS; 1779 } 1780 1781 1782 /** 1783 * Calculates the whole image hash. 1784 * 1785 * The Authenticode_PE.docx version 1.0 explains how the hash is calculated, 1786 * points 8 thru 14 are bogus. If you study them a little carefully, it is 1787 * clear that the algorithm will only work if the raw data for the section have 1788 * no gaps between them or in front of them. So, this elaborate section sorting 1789 * by PointerToRawData and working them section by section could simply be 1790 * replaced by one point: 1791 * 1792 * 8. Add all the file content between SizeOfHeaders and the 1793 * attribute certificate table to the hash. Then finalize 1794 * the hash. 1795 * 1796 * Not sure if Microsoft is screwing with us on purpose here or whether they 1797 * assigned some of this work to less talented engineers and tech writers. I 1798 * love fact that they say it's "simplified" and should yield the correct hash 1799 * for "almost all" files. Stupid, Stupid, Microsofties!! 1800 * 1801 * My simplified implementation that just hashes the entire file up to the 1802 * signature or end of the file produces the same SHA1 values as "signtool 1803 * verify /v" does both for edited executables with gaps between/before/after 1804 * sections raw data and normal executables without any gaps. 1805 * 1806 * @returns IPRT status code. 1807 * @param pModPe The PE module. 1808 * @param pvScratch Scratch buffer. 1809 * @param cbScratch Size of the scratch buffer. 1810 * @param enmDigest The hash digest type we're calculating. 1811 * @param pHashCtx Hash context scratch area. 1812 * @param pHashRes Hash result buffer. 1813 * @param pErrInfo Optional error info buffer. 1814 */ 1815 static int rtldrPE_HashImageCommon(PRTLDRMODPE pModPe, void *pvScratch, uint32_t cbScratch, RTDIGESTTYPE enmDigest, 1816 PRTLDRPEHASHCTXUNION pHashCtx, PRTLDRPEHASHRESUNION pHashRes, PRTERRINFO pErrInfo) 1817 { 1818 int rc = rtLdrPE_HashInit(pHashCtx, enmDigest); 1819 if (RT_FAILURE(rc)) 1820 return rc; 1821 1822 /* 1823 * Calculate the special places. 1824 */ 1825 RTLDRPEHASHSPECIALS SpecialPlaces; 1826 rc = rtldrPe_CalcSpecialHashPlaces(pModPe, &SpecialPlaces, pErrInfo); 1827 if (RT_FAILURE(rc)) 1828 return rc; 1829 1830 /* 1831 * Work our way thru the image data. 1832 */ 1833 uint32_t off = 0; 1834 while (off < SpecialPlaces.cbToHash) 1835 { 1836 uint32_t cbRead = RT_MIN(SpecialPlaces.cbToHash - off, cbScratch); 1837 uint8_t *pbCur = (uint8_t *)pvScratch; 1838 rc = pModPe->Core.pReader->pfnRead(pModPe->Core.pReader, pbCur, cbRead, off); 1839 if (RT_FAILURE(rc)) 1840 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_READ_ERROR_HASH, "Hash read error at %#x: %Rrc (cbRead=%#zx)", 1841 off, rc, cbRead); 1842 1843 if (off < SpecialPlaces.offEndSpecial) 1844 { 1845 if (off < SpecialPlaces.offCksum) 1846 { 1847 /* Hash everything up to the checksum. */ 1848 uint32_t cbChunk = RT_MIN(SpecialPlaces.offCksum - off, cbRead); 1849 rtLdrPE_HashUpdate(pHashCtx, enmDigest, pbCur, cbChunk); 1850 pbCur += cbChunk; 1851 cbRead -= cbChunk; 1852 off += cbChunk; 1853 } 1854 1855 if (off < SpecialPlaces.offCksum + SpecialPlaces.cbCksum && off >= SpecialPlaces.offCksum) 1856 { 1857 /* Skip the checksum */ 1858 uint32_t cbChunk = RT_MIN(SpecialPlaces.offCksum + SpecialPlaces.cbCksum - off, cbRead); 1859 pbCur += cbChunk; 1860 cbRead -= cbChunk; 1861 off += cbChunk; 1862 } 1863 1864 if (off < SpecialPlaces.offSecDir && off >= SpecialPlaces.offCksum + SpecialPlaces.cbCksum) 1865 { 1866 /* Hash everything between the checksum and the data dir entry. */ 1867 uint32_t cbChunk = RT_MIN(SpecialPlaces.offSecDir - off, cbRead); 1868 rtLdrPE_HashUpdate(pHashCtx, enmDigest, pbCur, cbChunk); 1869 pbCur += cbChunk; 1870 cbRead -= cbChunk; 1871 off += cbChunk; 1872 } 1873 1874 if (off < SpecialPlaces.offSecDir + SpecialPlaces.cbSecDir && off >= SpecialPlaces.offSecDir) 1875 { 1876 /* Skip the security data directory entry. */ 1877 uint32_t cbChunk = RT_MIN(SpecialPlaces.offSecDir + SpecialPlaces.cbSecDir - off, cbRead); 1878 pbCur += cbChunk; 1879 cbRead -= cbChunk; 1880 off += cbChunk; 1881 } 1882 } 1883 1884 rtLdrPE_HashUpdate(pHashCtx, enmDigest, pbCur, cbRead); 1885 1886 /* Advance */ 1887 off += cbRead; 1888 } 1889 1890 /* 1891 * If there isn't a signature, experiments with signtool indicates that we 1892 * have to zero padd the file size until it's a multiple of 8. (This is 1893 * most likely to give 64-bit values in the certificate a natural alignment 1894 * when memory mapped.) 1895 */ 1896 if ( pModPe->SecurityDir.Size != SpecialPlaces.cbToHash 1897 && SpecialPlaces.cbToHash != RT_ALIGN_32(SpecialPlaces.cbToHash, WIN_CERTIFICATE_ALIGNMENT)) 1898 { 1899 static const uint8_t s_abZeros[WIN_CERTIFICATE_ALIGNMENT] = { 0,0,0,0, 0,0,0,0 }; 1900 rtLdrPE_HashUpdate(pHashCtx, enmDigest, s_abZeros, 1901 RT_ALIGN_32(SpecialPlaces.cbToHash, WIN_CERTIFICATE_ALIGNMENT) - SpecialPlaces.cbToHash); 1902 } 1903 1904 /* 1905 * Done. Finalize the hashes. 1906 */ 1907 rtLdrPE_HashFinalize(pHashCtx, enmDigest, pHashRes); 1908 return VINF_SUCCESS; 1909 } 1910 1911 #ifndef IPRT_WITHOUT_LDR_VERIFY 1912 1913 /** 1914 * Verifies image preconditions not checked by the open validation code. 1915 * 1916 * @returns IPRT status code. 1917 * @param pModPe The PE module. 1918 * @param pErrInfo Optional error info buffer. 1919 */ 1920 static int rtldrPE_VerifySignatureImagePrecoditions(PRTLDRMODPE pModPe, PRTERRINFO pErrInfo) 1921 { 1922 /* 1923 * Validate the sections. While doing so, track the amount of section raw 1924 * section data in the file so we can use this to validate the signature 1925 * table location later. 1926 */ 1927 uint32_t offNext = pModPe->cbHeaders; /* same */ 1928 for (uint32_t i = 0; i < pModPe->cSections; i++) 1929 if (pModPe->paSections[i].SizeOfRawData > 0) 1930 { 1931 uint64_t offEnd = (uint64_t)pModPe->paSections[i].PointerToRawData + pModPe->paSections[i].SizeOfRawData; 1932 if (offEnd > offNext) 1933 { 1934 if (offEnd >= _2G) 1935 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_SECTION_RAW_DATA_VALUES, 1936 "Section %#u specifies file data after 2GB: PointerToRawData=%#x SizeOfRawData=%#x", 1937 i, pModPe->paSections[i].PointerToRawData, pModPe->paSections[i].SizeOfRawData); 1938 offNext = (uint32_t)offEnd; 1939 } 1940 } 1941 uint32_t offEndOfSectionData = offNext; 1942 1943 /* 1944 * Validate the signature. 1945 */ 1946 if (!pModPe->SecurityDir.Size) 1947 return RTErrInfoSet(pErrInfo, VERR_LDRVI_NOT_SIGNED, "Not signed."); 1948 1949 uint32_t const offSignature = pModPe->SecurityDir.VirtualAddress; 1950 uint32_t const cbSignature = pModPe->SecurityDir.Size; 1951 if ( cbSignature <= sizeof(WIN_CERTIFICATE) 1952 || cbSignature >= RTLDRMODPE_MAX_SECURITY_DIR_SIZE 1953 || offSignature >= _2G) 1954 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_INVALID_SECURITY_DIR_ENTRY, 1955 "Invalid security data dir entry: cb=%#x off=%#x", cbSignature, offSignature); 1956 1957 if (offSignature < offEndOfSectionData) 1958 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_INVALID_SECURITY_DIR_ENTRY, 1959 "Invalid security data dir entry offset: %#x offEndOfSectionData=%#x", 1960 offSignature, offEndOfSectionData); 1961 1962 if (RT_ALIGN_32(offSignature, WIN_CERTIFICATE_ALIGNMENT) != offSignature) 1963 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_INVALID_SECURITY_DIR_ENTRY, 1964 "Misaligned security dir entry offset: %#x (alignment=%#x)", 1965 offSignature, WIN_CERTIFICATE_ALIGNMENT); 1966 1967 1968 return VINF_SUCCESS; 1969 } 1970 1971 1972 /** 1973 * Reads and checks the raw signature data. 1974 * 1975 * @returns IPRT status code. 1976 * @param pModPe The PE module. 1977 * @param ppSignature Where to return the pointer to the parsed 1978 * signature data. Pass to 1979 * rtldrPE_VerifySignatureDestroy when done. 1980 * @param pErrInfo Optional error info buffer. 1981 */ 1982 static int rtldrPE_VerifySignatureRead(PRTLDRMODPE pModPe, PRTLDRPESIGNATURE *ppSignature, PRTERRINFO pErrInfo) 1983 { 1984 *ppSignature = NULL; 1985 AssertReturn(pModPe->SecurityDir.Size > 0, VERR_INTERNAL_ERROR_2); 1986 1987 /* 1988 * Allocate memory for reading and parsing it. 1989 */ 1990 if (pModPe->SecurityDir.Size >= RTLDRMODPE_MAX_SECURITY_DIR_SIZE) 1991 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_INVALID_SECURITY_DIR_ENTRY, 1992 "Signature directory is to large: %#x", pModPe->SecurityDir.Size); 1993 1994 PRTLDRPESIGNATURE pSignature = (PRTLDRPESIGNATURE)RTMemTmpAllocZ(sizeof(*pSignature) + 64 + pModPe->SecurityDir.Size); 1995 if (!pSignature) 1996 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_NO_MEMORY_SIGNATURE, "Failed to allocate %zu bytes", 1997 sizeof(*pSignature) + 64 + pModPe->SecurityDir.Size); 1998 pSignature->pRawData = RT_ALIGN_PT(pSignature + 1, 64, WIN_CERTIFICATE const *); 1999 2000 2001 /* 2002 * Read it. 2003 */ 2004 int rc = pModPe->Core.pReader->pfnRead(pModPe->Core.pReader, (void *)pSignature->pRawData, 2005 pModPe->SecurityDir.Size, pModPe->SecurityDir.VirtualAddress); 2006 if (RT_SUCCESS(rc)) 2007 { 2008 /* 2009 * Check the table we've read in. 2010 */ 2011 uint32_t cbLeft = pModPe->SecurityDir.Size; 2012 WIN_CERTIFICATE const *pEntry = pSignature->pRawData; 2013 for (;;) 2014 { 2015 if ( cbLeft < sizeof(*pEntry) 2016 || pEntry->dwLength > cbLeft 2017 || pEntry->dwLength < sizeof(*pEntry)) 2018 rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_HDR_LENGTH, 2019 "Bad WIN_CERTIFICATE length: %#x (max %#x, signature=%u)", 2020 pEntry->dwLength, cbLeft, 0); 2021 else if (pEntry->wRevision != WIN_CERT_REVISION_2_0) 2022 rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_HDR_REVISION, 2023 "Unsupported WIN_CERTIFICATE revision value: %#x (signature=%u)", 2024 pEntry->wRevision, 0); 2025 else if (pEntry->wCertificateType != WIN_CERT_TYPE_PKCS_SIGNED_DATA) 2026 rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_HDR_TYPE, 2027 "Unsupported WIN_CERTIFICATE certificate type: %#x (signature=%u)", 2028 pEntry->wCertificateType, 0); 2029 else 2030 { 2031 /* advance */ 2032 uint32_t cbEntry = RT_ALIGN(pEntry->dwLength, WIN_CERTIFICATE_ALIGNMENT); 2033 if (cbEntry >= cbLeft) 2034 break; 2035 cbLeft -= cbEntry; 2036 pEntry = (WIN_CERTIFICATE *)((uintptr_t)pEntry + cbEntry); 2037 2038 /* For now, only one entry is supported. */ 2039 rc = RTErrInfoSet(pErrInfo, VERR_LDRVI_BAD_CERT_MULTIPLE, "Multiple WIN_CERTIFICATE entries are not supported."); 2040 } 2041 break; 2042 } 2043 if (RT_SUCCESS(rc)) 2044 { 2045 *ppSignature = pSignature; 2046 return VINF_SUCCESS; 2047 } 2048 } 2049 else 2050 rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_READ_ERROR_SIGNATURE, "Signature read error: %Rrc", rc); 2051 RTMemTmpFree(pSignature); 2052 return rc; 2053 } 2054 2055 2056 /** 2057 * Destroys the parsed signature. 2058 * 2059 * @param pModPe The PE module. 2060 * @param pSignature The signature data to destroy. 2061 */ 2062 static void rtldrPE_VerifySignatureDestroy(PRTLDRMODPE pModPe, PRTLDRPESIGNATURE pSignature) 2063 { 2064 RTCrPkcs7ContentInfo_Delete(&pSignature->ContentInfo); 2065 RTMemTmpFree(pSignature); 2066 } 2067 2068 2069 /** 2070 * Decodes the raw signature. 2071 * 2072 * @returns IPRT status code. 2073 * @param pModPe The PE module. 2074 * @param pSignature The signature data. 2075 * @param pErrInfo Optional error info buffer. 2076 */ 2077 static int rtldrPE_VerifySignatureDecode(PRTLDRMODPE pModPe, PRTLDRPESIGNATURE pSignature, PRTERRINFO pErrInfo) 2078 { 2079 WIN_CERTIFICATE const *pEntry = pSignature->pRawData; 2080 AssertReturn(pEntry->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA, VERR_INTERNAL_ERROR_2); 2081 AssertReturn(pEntry->wRevision == WIN_CERT_REVISION_2_0, VERR_INTERNAL_ERROR_2); 2082 2083 RTASN1CURSORPRIMARY PrimaryCursor; 2084 RTAsn1CursorInitPrimary(&PrimaryCursor, 2085 &pEntry->bCertificate[0], 2086 pEntry->dwLength - RT_OFFSETOF(WIN_CERTIFICATE, bCertificate), 2087 pErrInfo, 2088 &g_RTAsn1DefaultAllocator, 2089 0, 2090 "WinCert"); 2091 2092 int rc = RTCrPkcs7ContentInfo_DecodeAsn1(&PrimaryCursor.Cursor, 0, &pSignature->ContentInfo, "CI"); 2093 if (RT_SUCCESS(rc)) 2094 { 2095 if (RTCrPkcs7ContentInfo_IsSignedData(&pSignature->ContentInfo)) 2096 { 2097 pSignature->pSignedData = pSignature->ContentInfo.u.pSignedData; 2098 2099 /* 2100 * Decode the authenticode bits. 2101 */ 2102 if (!strcmp(pSignature->pSignedData->ContentInfo.ContentType.szObjId, RTCRSPCINDIRECTDATACONTENT_OID)) 2103 { 2104 pSignature->pIndData = pSignature->pSignedData->ContentInfo.u.pIndirectDataContent; 2105 Assert(pSignature->pIndData); 2106 2107 /* 2108 * Check that things add up. 2109 */ 2110 if (RT_SUCCESS(rc)) 2111 rc = RTCrPkcs7SignedData_CheckSanity(pSignature->pSignedData, 2112 RTCRPKCS7SIGNEDDATA_SANITY_F_AUTHENTICODE 2113 | RTCRPKCS7SIGNEDDATA_SANITY_F_ONLY_KNOWN_HASH 2114 | RTCRPKCS7SIGNEDDATA_SANITY_F_SIGNING_CERT_PRESENT, 2115 pErrInfo, "SD"); 2116 if (RT_SUCCESS(rc)) 2117 rc = RTCrSpcIndirectDataContent_CheckSanityEx(pSignature->pIndData, 2118 pSignature->pSignedData, 2119 RTCRSPCINDIRECTDATACONTENT_SANITY_F_ONLY_KNOWN_HASH, 2120 pErrInfo); 2121 if (RT_SUCCESS(rc)) 2122 { 2123 PCRTCRX509ALGORITHMIDENTIFIER pDigestAlgorithm = &pSignature->pIndData->DigestInfo.DigestAlgorithm; 2124 pSignature->enmDigest = RTCrX509AlgorithmIdentifier_QueryDigestType(pDigestAlgorithm); 2125 AssertReturn(pSignature->enmDigest != RTDIGESTTYPE_INVALID, VERR_INTERNAL_ERROR_4); /* Checked above! */ 2126 } 2127 } 2128 else 2129 rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_EXPECTED_INDIRECT_DATA_CONTENT_OID, 2130 "Unknown pSignedData.ContentInfo.ContentType.szObjId value: %s (expected %s)", 2131 pSignature->pSignedData->ContentInfo.ContentType.szObjId, RTCRSPCINDIRECTDATACONTENT_OID); 2132 } 2133 } 2134 return rc; 2135 } 2136 2137 2138 static int rtldrPE_VerifyAllPageHashesV2(PRTLDRMODPE pModPe, PCRTCRSPCSERIALIZEDOBJECTATTRIBUTE pAttrib, RTDIGESTTYPE enmDigest, 2139 void *pvScratch, size_t cbScratch, PRTERRINFO pErrInfo) 2140 { 2141 AssertReturn(cbScratch >= _4K, VERR_INTERNAL_ERROR_3); 2142 2143 /* 2144 * Calculate the special places. 2145 */ 2146 RTLDRPEHASHSPECIALS SpecialPlaces; 2147 int rc = rtldrPe_CalcSpecialHashPlaces(pModPe, &SpecialPlaces, pErrInfo); 2148 if (RT_FAILURE(rc)) 2149 return rc; 2150 2151 uint32_t const cbHash = rtLdrPE_HashGetHashSize(enmDigest); 2152 uint32_t const cPages = pAttrib->u.pPageHashesV2->RawData.Asn1Core.cb / (cbHash + 4); 2153 if (cPages * (cbHash + 4) != pAttrib->u.pPageHashesV2->RawData.Asn1Core.cb) 2154 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_PAGE_HASH_TAB_SIZE_OVERFLOW, 2155 "Page Hashes V2 size issue: cb=%#x cbHash=%#x", 2156 pAttrib->u.pPageHashesV2->RawData.Asn1Core.cb, cbHash); 2157 2158 /* 2159 * Walk the table. 2160 */ 2161 uint32_t const cbScratchReadMax = cbScratch & ~(uint32_t)(_4K - 1); 2162 uint32_t cbScratchRead = 0; 2163 uint32_t offScratchRead = 0; 2164 2165 uint32_t offPrev = 0; 2166 uint32_t offSectEnd = pModPe->cbHeaders; 2167 uint32_t iSh = UINT32_MAX; 2168 uint8_t const *pbHashTab = pAttrib->u.pPageHashesV2->RawData.Asn1Core.uData.pu8; 2169 for (uint32_t iPage = 0; iPage < cPages; iPage++) 2170 { 2171 /* Decode the page offset. */ 2172 uint32_t const offFile = RT_MAKE_U32_FROM_U8(pbHashTab[0], pbHashTab[1], pbHashTab[2], pbHashTab[3]); 2173 if (offFile >= SpecialPlaces.cbToHash) 2174 { 2175 /* The last entry is zero. */ 2176 if ( offFile == SpecialPlaces.cbToHash 2177 && iPage + 1 == cPages 2178 && ASMMemIsAll8(pbHashTab + 4, cbHash, 0) == NULL) 2179 return VINF_SUCCESS; 2180 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_PAGE_HASH_TAB_TOO_LONG, 2181 "Page hash entry #%u is beyond the signature table start: %#x, %#x", 2182 iPage, offFile, SpecialPlaces.cbToHash); 2183 } 2184 if (offFile < offPrev) 2185 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_PAGE_HASH_TAB_NOT_STRICTLY_SORTED, 2186 "Page hash table is not strictly sorted: entry #%u @%#x, previous @%#x\n", 2187 iPage, offFile, offPrev); 2188 2189 /* Figure out how much to read and how much to zero. Need keep track 2190 of the on-disk section boundraries. */ 2191 if (offFile >= offSectEnd) 2192 { 2193 iSh++; 2194 if ( iSh < pModPe->cSections 2195 && offFile - pModPe->paSections[iSh].PointerToRawData < pModPe->paSections[iSh].SizeOfRawData) 2196 offSectEnd = pModPe->paSections[iSh].PointerToRawData + pModPe->paSections[iSh].SizeOfRawData; 2197 else 2198 { 2199 iSh = 0; 2200 while ( iSh < pModPe->cSections 2201 && offFile - pModPe->paSections[iSh].PointerToRawData >= pModPe->paSections[iSh].SizeOfRawData) 2202 iSh++; 2203 if (iSh < pModPe->cSections) 2204 offSectEnd = pModPe->paSections[iSh].PointerToRawData + pModPe->paSections[iSh].SizeOfRawData; 2205 else 2206 return RTErrInfoSetF(pErrInfo, VERR_PAGE_HASH_TAB_HASHES_NON_SECTION_DATA, 2207 "Page hash entry #%u isn't in any section: %#x", iPage, offFile); 2208 } 2209 } 2210 2211 uint32_t cbRead = _4K; 2212 if (offFile + cbRead > offSectEnd) 2213 cbRead = offSectEnd - offFile; 2214 2215 if (offFile + cbRead > SpecialPlaces.cbToHash) 2216 cbRead = SpecialPlaces.cbToHash - offFile; 2217 2218 /* Did we get a cache hit? */ 2219 uint8_t *pbCur = (uint8_t *)pvScratch; 2220 if ( offFile + cbRead <= offScratchRead + cbScratchRead 2221 && offFile >= offScratchRead) 2222 pbCur += offFile - offScratchRead; 2223 /* Missed, read more. */ 2224 else 2225 { 2226 offScratchRead = offFile; 2227 cbScratchRead = offSectEnd - offFile; 2228 if (cbScratchRead > cbScratchReadMax) 2229 cbScratchRead = cbScratchReadMax; 2230 rc = pModPe->Core.pReader->pfnRead(pModPe->Core.pReader, pbCur, cbScratchRead, offScratchRead); 2231 if (RT_FAILURE(rc)) 2232 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_READ_ERROR_HASH, 2233 "Page hash read error at %#x: %Rrc (cbScratchRead=%#zx)", 2234 offScratchRead, rc, cbScratchRead); 2235 } 2236 2237 /* Zero any additional bytes in the page. */ 2238 if (cbRead != _4K) 2239 memset(pbCur + cbRead, 0, _4K - cbRead); 2240 2241 /* 2242 * Hash it. 2243 */ 2244 RTLDRPEHASHCTXUNION HashCtx; 2245 rc = rtLdrPE_HashInit(&HashCtx, enmDigest); 2246 AssertRCReturn(rc, rc); 2247 2248 /* Deal with special places. */ 2249 uint32_t cbLeft = _4K; 2250 if (offFile < SpecialPlaces.offEndSpecial) 2251 { 2252 uint32_t off = offFile; 2253 if (off < SpecialPlaces.offCksum) 2254 { 2255 /* Hash everything up to the checksum. */ 2256 uint32_t cbChunk = RT_MIN(SpecialPlaces.offCksum - off, cbLeft); 2257 rtLdrPE_HashUpdate(&HashCtx, enmDigest, pbCur, cbChunk); 2258 pbCur += cbChunk; 2259 cbLeft -= cbChunk; 2260 off += cbChunk; 2261 } 2262 2263 if (off < SpecialPlaces.offCksum + SpecialPlaces.cbCksum && off >= SpecialPlaces.offCksum) 2264 { 2265 /* Skip the checksum */ 2266 uint32_t cbChunk = RT_MIN(SpecialPlaces.offCksum + SpecialPlaces.cbCksum - off, cbLeft); 2267 pbCur += cbChunk; 2268 cbLeft -= cbChunk; 2269 off += cbChunk; 2270 } 2271 2272 if (off < SpecialPlaces.offSecDir && off >= SpecialPlaces.offCksum + SpecialPlaces.cbCksum) 2273 { 2274 /* Hash everything between the checksum and the data dir entry. */ 2275 uint32_t cbChunk = RT_MIN(SpecialPlaces.offSecDir - off, cbLeft); 2276 rtLdrPE_HashUpdate(&HashCtx, enmDigest, pbCur, cbChunk); 2277 pbCur += cbChunk; 2278 cbLeft -= cbChunk; 2279 off += cbChunk; 2280 } 2281 2282 if (off < SpecialPlaces.offSecDir + SpecialPlaces.cbSecDir && off >= SpecialPlaces.offSecDir) 2283 { 2284 /* Skip the security data directory entry. */ 2285 uint32_t cbChunk = RT_MIN(SpecialPlaces.offSecDir + SpecialPlaces.cbSecDir - off, cbLeft); 2286 pbCur += cbChunk; 2287 cbLeft -= cbChunk; 2288 off += cbChunk; 2289 } 2290 } 2291 2292 rtLdrPE_HashUpdate(&HashCtx, enmDigest, pbCur, cbLeft); 2293 2294 /* 2295 * Finish the hash calculation and compare the result. 2296 */ 2297 RTLDRPEHASHRESUNION HashRes; 2298 rtLdrPE_HashFinalize(&HashCtx, enmDigest, &HashRes); 2299 2300 pbHashTab += 4; 2301 if (memcmp(pbHashTab, &HashRes, cbHash) != 0) 2302 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_PAGE_HASH_MISMATCH, 2303 "Page hash v2 failed for page #%u, @%#x, %#x bytes: %.*Rhxs != %.*Rhxs", 2304 iPage, offFile, cbRead, (size_t)cbHash, pbHashTab, (size_t)cbHash, &HashRes); 2305 pbHashTab += cbHash; 2306 offPrev = offFile; 2307 } 2308 2309 return VINF_SUCCESS; 2310 } 2311 2312 2313 /** 2314 * Validates the image hash, including page hashes if present. 2315 * 2316 * @returns IPRT status code. 2317 * @param pModPe The PE module. 2318 * @param pSignature The decoded signature data. 2319 * @param pErrInfo Optional error info buffer. 2320 */ 2321 static int rtldrPE_VerifySignatureValidateHash(PRTLDRMODPE pModPe, PRTLDRPESIGNATURE pSignature, PRTERRINFO pErrInfo) 2322 { 2323 AssertReturn(pSignature->enmDigest > RTDIGESTTYPE_INVALID && pSignature->enmDigest < RTDIGESTTYPE_END, VERR_INTERNAL_ERROR_4); 2324 AssertPtrReturn(pSignature->pIndData, VERR_INTERNAL_ERROR_5); 2325 AssertReturn(RTASN1CORE_IS_PRESENT(&pSignature->pIndData->DigestInfo.Digest.Asn1Core), VERR_INTERNAL_ERROR_5); 2326 AssertPtrReturn(pSignature->pIndData->DigestInfo.Digest.Asn1Core.uData.pv, VERR_INTERNAL_ERROR_5); 2327 2328 uint32_t const cbHash = rtLdrPE_HashGetHashSize(pSignature->enmDigest); 2329 AssertReturn(pSignature->pIndData->DigestInfo.Digest.Asn1Core.cb == cbHash, VERR_INTERNAL_ERROR_5); 2330 2331 /* 2332 * Allocate a temporary memory buffer. 2333 */ 2334 #ifdef IN_RING0 2335 uint32_t cbScratch = _256K; 2336 #else 2337 uint32_t cbScratch = _1M; 2338 #endif 2339 void *pvScratch = RTMemTmpAlloc(cbScratch); 2340 if (!pvScratch) 2341 { 2342 cbScratch = _4K; 2343 pvScratch = RTMemTmpAlloc(cbScratch); 2344 if (!pvScratch) 2345 return RTErrInfoSet(pErrInfo, VERR_NO_TMP_MEMORY, "Failed to allocate 4KB of scratch space for hashing image."); 2346 } 2347 2348 /* 2349 * Calculate and compare the full image hash. 2350 */ 2351 int rc = rtldrPE_HashImageCommon(pModPe, pvScratch, cbScratch, pSignature->enmDigest, 2352 &pSignature->HashCtx, &pSignature->HashRes, pErrInfo); 2353 if (RT_SUCCESS(rc)) 2354 { 2355 if (!memcmp(&pSignature->HashRes, pSignature->pIndData->DigestInfo.Digest.Asn1Core.uData.pv, cbHash)) 2356 { 2357 /* 2358 * Compare the page hashes if present. 2359 */ 2360 PCRTCRSPCSERIALIZEDOBJECTATTRIBUTE pAttrib = RTCrSpcIndirectDataContent_GetPeImageHashesV2(pSignature->pIndData); 2361 if (pAttrib) 2362 rc = rtldrPE_VerifyAllPageHashesV2(pModPe, pAttrib, pSignature->enmDigest, pvScratch, cbScratch, pErrInfo); 2363 2364 return rc; 2365 } 2366 rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_IMAGE_HASH_MISMATCH, 2367 "Full image signature mismatch: %.*Rhxs, expected %.*Rhxs", 2368 cbHash, &pSignature->HashRes, 2369 cbHash, pSignature->pIndData->DigestInfo.Digest.Asn1Core.uData.pv); 2370 } 2371 2372 RTMemTmpFree(pvScratch); 2373 return rc; 2374 } 2375 2376 #endif /* !IPRT_WITHOUT_LDR_VERIFY */ 2377 2378 2379 /** @interface_method_impl{RTLDROPS,pfnVerifySignature} */ 2380 static DECLCALLBACK(int) rtldrPE_VerifySignature(PRTLDRMODINTERNAL pMod, PFNRTLDRVALIDATESIGNEDDATA pfnCallback, void *pvUser, 2381 PRTERRINFO pErrInfo) 2382 { 2383 #ifndef IPRT_WITHOUT_LDR_VERIFY 2384 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod; 2385 2386 int rc = rtldrPE_VerifySignatureImagePrecoditions(pModPe, pErrInfo); 2387 if (RT_SUCCESS(rc)) 2388 { 2389 PRTLDRPESIGNATURE pSignature = NULL; 2390 rc = rtldrPE_VerifySignatureRead(pModPe, &pSignature, pErrInfo); 2391 if (RT_SUCCESS(rc)) 2392 { 2393 rc = rtldrPE_VerifySignatureDecode(pModPe, pSignature, pErrInfo); 2394 if (RT_SUCCESS(rc)) 2395 rc = rtldrPE_VerifySignatureValidateHash(pModPe, pSignature, pErrInfo); 2396 if (RT_SUCCESS(rc)) 2397 { 2398 rc = pfnCallback(&pModPe->Core, RTLDRSIGNATURETYPE_PKCS7_SIGNED_DATA, 2399 &pSignature->ContentInfo, sizeof(pSignature->ContentInfo), 2400 pErrInfo, pvUser); 2401 } 2402 rtldrPE_VerifySignatureDestroy(pModPe, pSignature); 2403 } 2404 } 2405 return rc; 2406 #else 2407 return VERR_NOT_SUPPORTED; 2408 #endif 2409 } 2410 2411 2412 2413 /** @interface_method_impl{RTLDROPS,pfnHashImage} */ 2414 static DECLCALLBACK(int) rtldrPE_HashImage(PRTLDRMODINTERNAL pMod, RTDIGESTTYPE enmDigest, char *pszDigest, size_t cbDigest) 2415 { 2416 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod; 2417 2418 /* 2419 * Allocate a temporary memory buffer. 2420 */ 2421 uint32_t cbScratch = _16K; 2422 void *pvScratch = RTMemTmpAlloc(cbScratch); 2423 if (!pvScratch) 2424 { 2425 cbScratch = _4K; 2426 pvScratch = RTMemTmpAlloc(cbScratch); 2427 if (!pvScratch) 2428 return VERR_NO_TMP_MEMORY; 2429 } 2430 2431 /* 2432 * Do the hashing. 2433 */ 2434 RTLDRPEHASHCTXUNION HashCtx; 2435 RTLDRPEHASHRESUNION HashRes; 2436 int rc = rtldrPE_HashImageCommon(pModPe, pvScratch, cbScratch, enmDigest, &HashCtx, &HashRes, NULL); 2437 if (RT_SUCCESS(rc)) 2438 { 2439 /* 2440 * Format the digest into as human readable hash string. 2441 */ 2442 switch (enmDigest) 2443 { 2444 case RTDIGESTTYPE_SHA512: rc = RTSha512ToString(HashRes.abSha512, pszDigest, cbDigest); break; 2445 case RTDIGESTTYPE_SHA256: rc = RTSha256ToString(HashRes.abSha256, pszDigest, cbDigest); break; 2446 case RTDIGESTTYPE_SHA1: rc = RTSha1ToString(HashRes.abSha1, pszDigest, cbDigest); break; 2447 case RTDIGESTTYPE_MD5: rc = RTMd5ToString(HashRes.abMd5, pszDigest, cbDigest); break; 2448 default: AssertFailedReturn(VERR_INTERNAL_ERROR_3); 2449 } 2450 } 2451 return rc; 2452 } 2453 2454 1514 2455 /** @copydoc RTLDROPS::pfnDone */ 1515 2456 static DECLCALLBACK(int) rtldrPEDone(PRTLDRMODINTERNAL pMod) … … 1523 2464 return VINF_SUCCESS; 1524 2465 } 2466 1525 2467 1526 2468 /** @copydoc RTLDROPS::pfnClose */ … … 1566 2508 NULL, 1567 2509 rtldrPE_QueryProp, 2510 rtldrPE_VerifySignature, 2511 rtldrPE_HashImage, 1568 2512 42 1569 2513 }, … … 1597 2541 NULL, 1598 2542 rtldrPE_QueryProp, 2543 rtldrPE_VerifySignature, 2544 rtldrPE_HashImage, 1599 2545 42 1600 2546 }, … … 1660 2606 * volatile everywhere! Trying to prevent the compiler being a smarta$$ and reorder stuff. 1661 2607 */ 1662 IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *pLoadCfg32 = (IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *)pLoadCfg; 1663 IMAGE_LOAD_CONFIG_DIRECTORY64 volatile *pLoadCfg64 = pLoadCfg; 1664 1665 pLoadCfg64->SEHandlerCount = pLoadCfg32->SEHandlerCount; 1666 pLoadCfg64->SEHandlerTable = pLoadCfg32->SEHandlerTable; 1667 pLoadCfg64->SecurityCookie = pLoadCfg32->SecurityCookie; 1668 pLoadCfg64->EditList = pLoadCfg32->EditList; 1669 pLoadCfg64->Reserved1 = pLoadCfg32->Reserved1; 1670 pLoadCfg64->CSDVersion = pLoadCfg32->CSDVersion; 1671 pLoadCfg64->ProcessHeapFlags = pLoadCfg32->ProcessHeapFlags; /* switched place with ProcessAffinityMask, but we're more than 16 byte off by now so it doesn't matter. */ 1672 pLoadCfg64->ProcessAffinityMask = pLoadCfg32->ProcessAffinityMask; 1673 pLoadCfg64->VirtualMemoryThreshold = pLoadCfg32->VirtualMemoryThreshold; 1674 pLoadCfg64->MaximumAllocationSize = pLoadCfg32->MaximumAllocationSize; 1675 pLoadCfg64->LockPrefixTable = pLoadCfg32->LockPrefixTable; 1676 pLoadCfg64->DeCommitTotalFreeThreshold = pLoadCfg32->DeCommitTotalFreeThreshold; 1677 uint32_t u32DeCommitFreeBlockThreshold = pLoadCfg32->DeCommitFreeBlockThreshold; 1678 pLoadCfg64->DeCommitFreeBlockThreshold = u32DeCommitFreeBlockThreshold; 2608 IMAGE_LOAD_CONFIG_DIRECTORY32_V3 volatile *pLoadCfg32 = (IMAGE_LOAD_CONFIG_DIRECTORY32_V3 volatile *)pLoadCfg; 2609 IMAGE_LOAD_CONFIG_DIRECTORY64_V3 volatile *pLoadCfg64 = pLoadCfg; 2610 2611 pLoadCfg64->GuardFlags = pLoadCfg32->GuardFlags; 2612 pLoadCfg64->GuardCFFunctionCount = pLoadCfg32->GuardCFFunctionCount; 2613 pLoadCfg64->GuardCFFunctionTable = pLoadCfg32->GuardCFFunctionTable; 2614 pLoadCfg64->Reserved2 = pLoadCfg32->Reserved2; 2615 pLoadCfg64->GuardCFCCheckFunctionPointer= pLoadCfg32->GuardCFCCheckFunctionPointer; 2616 pLoadCfg64->SEHandlerCount = pLoadCfg32->SEHandlerCount; 2617 pLoadCfg64->SEHandlerTable = pLoadCfg32->SEHandlerTable; 2618 pLoadCfg64->SecurityCookie = pLoadCfg32->SecurityCookie; 2619 pLoadCfg64->EditList = pLoadCfg32->EditList; 2620 pLoadCfg64->Reserved1 = pLoadCfg32->Reserved1; 2621 pLoadCfg64->CSDVersion = pLoadCfg32->CSDVersion; 2622 pLoadCfg64->ProcessHeapFlags = pLoadCfg32->ProcessHeapFlags; /* switched place with ProcessAffinityMask, but we're more than 16 byte off by now so it doesn't matter. */ 2623 pLoadCfg64->ProcessAffinityMask = pLoadCfg32->ProcessAffinityMask; 2624 pLoadCfg64->VirtualMemoryThreshold = pLoadCfg32->VirtualMemoryThreshold; 2625 pLoadCfg64->MaximumAllocationSize = pLoadCfg32->MaximumAllocationSize; 2626 pLoadCfg64->LockPrefixTable = pLoadCfg32->LockPrefixTable; 2627 pLoadCfg64->DeCommitTotalFreeThreshold = pLoadCfg32->DeCommitTotalFreeThreshold; 2628 uint32_t u32DeCommitFreeBlockThreshold = pLoadCfg32->DeCommitFreeBlockThreshold; 2629 pLoadCfg64->DeCommitFreeBlockThreshold = u32DeCommitFreeBlockThreshold; 1679 2630 /* the rest is equal. */ 1680 2631 Assert( RT_OFFSETOF(IMAGE_LOAD_CONFIG_DIRECTORY32, DeCommitFreeBlockThreshold) … … 1720 2671 /* This restriction needs to be implemented elsewhere. */ 1721 2672 if ( (pFileHdr->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) 1722 && !(fFlags & RTLDR_O_FOR_DEBUG))2673 && !(fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION))) 1723 2674 { 1724 2675 Log(("rtldrPEOpen: %s: IMAGE_FILE_RELOCS_STRIPPED\n", pszLogName)); … … 1856 2807 1857 2808 case IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT: // 13 2809 if (fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION)) 2810 break; 1858 2811 Log(("rtldrPEOpen: %s: dir no. %d (DELAY_IMPORT) VirtualAddress=%#x Size=%#x is not supported!!!\n", 1859 2812 pszLogName, i, pDir->VirtualAddress, pDir->Size)); … … 1870 2823 return VERR_LDRPE_CERT_MALFORMED; 1871 2824 } 1872 if (pDir->Size >= _1M)2825 if (pDir->Size >= RTLDRMODPE_MAX_SECURITY_DIR_SIZE) 1873 2826 { 1874 2827 Log(("rtldrPEOpen: %s: Security directory is too large: %#x bytes\n", pszLogName, i, pDir->Size)); … … 1894 2847 1895 2848 case IMAGE_DIRECTORY_ENTRY_TLS: // 9 2849 if (fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION)) 2850 break; 1896 2851 Log(("rtldrPEOpen: %s: dir no. %d (TLS) VirtualAddress=%#x Size=%#x is not supported!!!\n", 1897 2852 pszLogName, i, pDir->VirtualAddress, pDir->Size)); … … 1899 2854 1900 2855 case IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR:// 14 2856 if (fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION)) 2857 break; 1901 2858 Log(("rtldrPEOpen: %s: dir no. %d (COM_DESCRIPTOR) VirtualAddress=%#x Size=%#x is not supported!!!\n", 1902 2859 pszLogName, i, pDir->VirtualAddress, pDir->Size)); … … 1945 2902 for (unsigned cSHdrsLeft = cSections; cSHdrsLeft > 0; cSHdrsLeft--, pSH++) 1946 2903 { 1947 const unsigned iSH = pSH - &paSections[0]; NOREF(iSH);2904 const unsigned iSH = (unsigned)(pSH - &paSections[0]); NOREF(iSH); 1948 2905 Log3(("RTLdrPE: #%d '%-8.8s' Characteristics: %08RX32\n" 1949 2906 "RTLdrPE: VirtAddr: %08RX32 VirtSize: %08RX32\n" … … 2110 3067 2111 3068 /** 2112 * Validates the data of some selected data directories entries. 2113 * 2114 * This requires a valid section table and thus has to wait 2115 * till after we've read and validated it. 3069 * Validates the data of some selected data directories entries and remember 3070 * important bits for later. 3071 * 3072 * This requires a valid section table and thus has to wait till after we've 3073 * read and validated it. 2116 3074 * 2117 3075 * @returns iprt status code. … … 2120 3078 * @param fFlags Loader flags, RTLDR_O_XXX. 2121 3079 */ 2122 static int rtldrPEValidateDirectories (PRTLDRMODPE pModPe, const IMAGE_OPTIONAL_HEADER64 *pOptHdr, uint32_t fFlags)3080 static int rtldrPEValidateDirectoriesAndRememberStuff(PRTLDRMODPE pModPe, const IMAGE_OPTIONAL_HEADER64 *pOptHdr, uint32_t fFlags) 2123 3081 { 2124 3082 const char *pszLogName = pModPe->Core.pReader->pfnLogName(pModPe->Core.pReader); NOREF(pszLogName); … … 2136 3094 if (Dir.Size) 2137 3095 { 2138 const size_t cbExpect = pOptHdr->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC 2139 ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32) 2140 : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64); 2141 if ( Dir.Size != cbExpect 2142 && ( cbExpect == sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32) 2143 && Dir.Size != (uint32_t)RT_OFFSETOF(IMAGE_LOAD_CONFIG_DIRECTORY32, SEHandlerTable)) 2144 ) 2145 { 2146 Log(("rtldrPEOpen: %s: load cfg dir: unexpected dir size of %d bytes, expected %d.\n", 2147 pszLogName, Dir.Size, cbExpect)); 3096 const size_t cbExpectV3 = !pModPe->f64Bit 3097 ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32_V3) 3098 : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64_V3); 3099 const size_t cbExpectV2 = !pModPe->f64Bit 3100 ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32_V2) 3101 : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64_V2); 3102 const size_t cbExpectV1 = !pModPe->f64Bit 3103 ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32_V1) 3104 : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64_V2) /*No V1*/; 3105 3106 if ( Dir.Size != cbExpectV3 3107 && Dir.Size != cbExpectV2 3108 && Dir.Size != cbExpectV1) 3109 { 3110 Log(("rtldrPEOpen: %s: load cfg dir: unexpected dir size of %d bytes, expected %d, %d, or %d.\n", 3111 pszLogName, Dir.Size, cbExpectV3, cbExpectV2, cbExpectV1)); 2148 3112 return VERR_LDRPE_LOAD_CONFIG_SIZE; 2149 3113 } … … 2158 3122 rtldrPEConvert32BitLoadConfigTo64Bit(&u.Cfg64); 2159 3123 2160 if (u.Cfg64.Size != cbExpect) 2161 { 2162 Log(("rtldrPEOpen: %s: load cfg dir: unexpected header size of %d bytes, expected %d.\n", 2163 pszLogName, u.Cfg64.Size, cbExpect)); 2164 return VERR_LDRPE_LOAD_CONFIG_SIZE; 2165 } 2166 if (u.Cfg64.LockPrefixTable) 3124 if (u.Cfg64.Size != Dir.Size) 3125 { 3126 /* Kludge, seen ati shipping 32-bit DLLs and EXEs with Dir.Size=0x40 3127 and Cfg64.Size=0x5c or 0x48. Windows seems to deal with it, so 3128 lets do so as well. */ 3129 if ( Dir.Size < u.Cfg64.Size 3130 && ( u.Cfg64.Size == cbExpectV3 3131 || u.Cfg64.Size == cbExpectV2) ) 3132 { 3133 Log(("rtldrPEOpen: %s: load cfg dir: Header (%d) and directory (%d) size mismatch, applying the ATI kludge\n", 3134 pszLogName, u.Cfg64.Size, Dir.Size)); 3135 Dir.Size = u.Cfg64.Size; 3136 memset(&u.Cfg64, 0, sizeof(u.Cfg64)); 3137 rc = rtldrPEReadRVA(pModPe, &u.Cfg64, Dir.Size, Dir.VirtualAddress); 3138 if (RT_FAILURE(rc)) 3139 return rc; 3140 rtldrPEConvert32BitLoadConfigTo64Bit(&u.Cfg64); 3141 } 3142 if (u.Cfg64.Size != Dir.Size) 3143 { 3144 Log(("rtldrPEOpen: %s: load cfg dir: unexpected header size of %d bytes, expected %d.\n", 3145 pszLogName, u.Cfg64.Size, Dir.Size)); 3146 return VERR_LDRPE_LOAD_CONFIG_SIZE; 3147 } 3148 } 3149 if (u.Cfg64.LockPrefixTable && !(fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION))) 2167 3150 { 2168 3151 Log(("rtldrPEOpen: %s: load cfg dir: lock prefix table at %RX64. We don't support lock prefix tables!\n", … … 2179 3162 } 2180 3163 #endif 2181 if (u.Cfg64.EditList )3164 if (u.Cfg64.EditList && !(fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION))) 2182 3165 { 2183 3166 Log(("rtldrPEOpen: %s: load cfg dir: EditList=%RX64 is unsupported!\n", … … 2185 3168 return VERR_BAD_EXE_FORMAT; 2186 3169 } 3170 /** @todo GuardCFC? Possibly related to: 3171 * http://research.microsoft.com/pubs/69217/ccs05-cfi.pdf 3172 * Not trusting something designed by bakas who don't know how to modify a 3173 * structure without messing up its natural alignment. */ 3174 if ( ( u.Cfg64.GuardCFCCheckFunctionPointer 3175 || u.Cfg64.Reserved2 3176 || u.Cfg64.GuardCFFunctionTable 3177 || u.Cfg64.GuardCFFunctionCount 3178 || u.Cfg64.GuardFlags) 3179 && !(fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION))) 3180 { 3181 Log(("rtldrPEOpen: %s: load cfg dir: Guard stuff: %RX64,%RX64,%RX64,%RX64,%RX32!\n", 3182 pszLogName, u.Cfg64.GuardCFCCheckFunctionPointer, u.Cfg64.Reserved2, 3183 u.Cfg64.GuardCFFunctionTable, u.Cfg64.GuardCFFunctionCount, u.Cfg64.GuardFlags)); 3184 return VERR_BAD_EXE_FORMAT; 3185 } 2187 3186 } 2188 3187 … … 2192 3191 */ 2193 3192 Dir = pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]; 2194 if (Dir.Size && !(fFlags & RTLDR_O_FOR_DEBUG))3193 if (Dir.Size) 2195 3194 { 2196 3195 PWIN_CERTIFICATE pFirst = (PWIN_CERTIFICATE)RTMemTmpAlloc(Dir.Size); … … 2200 3199 if (RT_SUCCESS(rc)) 2201 3200 { 2202 uint32_t off = 0; 2203 PWIN_CERTIFICATE pCur = pFirst; 3201 uint32_t off = 0; 2204 3202 do 2205 3203 { 3204 PWIN_CERTIFICATE pCur = (PWIN_CERTIFICATE)((uint8_t *)pFirst + off); 3205 2206 3206 /* validate the members. */ 2207 uint32_t const cbCur = RT_ALIGN_32(pCur->dwLength, 8); 2208 if ( cbCur < sizeof(WIN_CERTIFICATE) 2209 || cbCur + off > RT_ALIGN_32(Dir.Size, 8)) 3207 if ( pCur->dwLength < sizeof(WIN_CERTIFICATE) 3208 || pCur->dwLength + off > Dir.Size) 2210 3209 { 2211 3210 Log(("rtldrPEOpen: %s: cert at %#x/%#x: dwLength=%#x\n", pszLogName, off, Dir.Size, pCur->dwLength)); … … 2233 3232 } 2234 3233 2235 /** @todo Rainy Day: Implement further verification using openssl. */ 3234 /* Remember the first signed data certificate. */ 3235 if ( pCur->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA 3236 && pModPe->offPkcs7SignedData == 0) 3237 { 3238 pModPe->offPkcs7SignedData = Dir.VirtualAddress 3239 + (uint32_t)((uintptr_t)&pCur->bCertificate[0] - (uintptr_t)pFirst); 3240 pModPe->cbPkcs7SignedData = pCur->dwLength - RT_OFFSETOF(WIN_CERTIFICATE, bCertificate); 3241 } 2236 3242 2237 3243 /* next */ 2238 off += cbCur; 2239 pCur = (PWIN_CERTIFICATE)((uint8_t *)pCur + cbCur); 3244 off += RT_ALIGN(pCur->dwLength, WIN_CERTIFICATE_ALIGNMENT); 2240 3245 } while (off < Dir.Size); 2241 3246 } … … 2259 3264 * @param offNtHdrs The offset of the NT headers (where you find "PE\0\0"). 2260 3265 * @param phLdrMod Where to store the handle. 2261 */ 2262 int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF offNtHdrs, PRTLDRMOD phLdrMod) 3266 * @param pErrInfo Where to return extended error information. Optional. 3267 */ 3268 int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF offNtHdrs, 3269 PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo) 2263 3270 { 2264 3271 /* … … 2349 3356 pModPe->cbHeaders = OptHdr.SizeOfHeaders; 2350 3357 pModPe->uTimestamp = FileHdr.TimeDateStamp; 3358 pModPe->f64Bit = FileHdr.SizeOfOptionalHeader == sizeof(OptHdr); 2351 3359 pModPe->ImportDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; 2352 3360 pModPe->RelocDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; 2353 3361 pModPe->ExportDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; 2354 3362 pModPe->DebugDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]; 3363 pModPe->SecurityDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]; 3364 pModPe->fDllCharacteristics = OptHdr.DllCharacteristics; 2355 3365 2356 3366 /* 2357 3367 * Perform validation of some selected data directories which requires 2358 * inspection of the actual data. 3368 * inspection of the actual data. This also saves some certificate 3369 * information. 2359 3370 */ 2360 rc = rtldrPEValidateDirectories (pModPe, &OptHdr, fFlags);3371 rc = rtldrPEValidateDirectoriesAndRememberStuff(pModPe, &OptHdr, fFlags); 2361 3372 if (RT_SUCCESS(rc)) 2362 3373 { -
trunk/src/VBox/Runtime/common/ldr/ldrkStuff.cpp
r49045 r51770 838 838 839 839 /** @interface_method_impl{RTLDROPS,pfnQueryProp} */ 840 static DECLCALLBACK(int) rtkldr_QueryProp(PRTLDRMODINTERNAL pMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf )840 static DECLCALLBACK(int) rtkldr_QueryProp(PRTLDRMODINTERNAL pMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf, size_t *pcbRet) 841 841 { 842 842 PRTLDRMODKLDR pThis = (PRTLDRMODKLDR)pMod; … … 881 881 rtkldr_ReadDbgInfo, 882 882 rtkldr_QueryProp, 883 NULL, 884 NULL, 883 885 42 884 886 }; … … 893 895 * @param enmArch CPU architecture specifier for the image to be loaded. 894 896 * @param phLdrMod Where to store the handle. 897 * @param pErrInfo Where to return extended error information. Optional. 895 898 */ 896 int rtldrkLdrOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTLDRMOD phLdrMod )899 int rtldrkLdrOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo) 897 900 { 898 901 /* Convert enmArch to k-speak. */ -
trunk/src/VBox/Runtime/common/log/log.cpp
r50915 r51770 2609 2609 RT_EXPORT_SYMBOL(RTLogPrintfV); 2610 2610 2611 2612 /** 2613 * Dumper vprintf-like function outputting to a logger. 2614 * 2615 * @param pvUser Pointer to the logger instance to use, NULL for 2616 * default instance. 2617 * @param pszFormat Format string. 2618 * @param va Format arguments. 2619 */ 2620 RTDECL(void) RTLogDumpPrintfV(void *pvUser, const char *pszFormat, va_list va) 2621 { 2622 RTLogLoggerV((PRTLOGGER)pvUser, pszFormat, va); 2623 } 2624 RT_EXPORT_SYMBOL(RTLogDumpPrintfV); 2625 2626 2611 2627 #ifdef IN_RING3 2612 2628 -
trunk/src/VBox/Runtime/common/misc/sg.cpp
r44529 r51770 48 48 } 49 49 50 #ifndef RDESKTOP 50 51 AssertReleaseMsg( pSgBuf->cbSegLeft <= 32 * _1M 51 52 && (uintptr_t)pSgBuf->pvSegCur >= (uintptr_t)pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg … … 54 55 pSgBuf->idxSeg, pSgBuf->cSegs, pSgBuf->pvSegCur, pSgBuf->cbSegLeft, 55 56 pSgBuf->idxSeg, pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg, pSgBuf->idxSeg, pSgBuf->paSegs[pSgBuf->idxSeg].cbSeg)); 57 #endif 56 58 57 59 cbData = RT_MIN(*pcbData, pSgBuf->cbSegLeft); -
trunk/src/VBox/Runtime/common/string/RTStrPrintHexBytes.cpp
r44529 r51770 5 5 6 6 /* 7 * Copyright (C) 2009-201 0Oracle Corporation7 * Copyright (C) 2009-2014 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 38 38 RTDECL(int) RTStrPrintHexBytes(char *pszBuf, size_t cchBuf, void const *pv, size_t cb, uint32_t fFlags) 39 39 { 40 AssertReturn(! fFlags, VERR_INVALID_PARAMETER);40 AssertReturn(!(fFlags & ~RTSTRPRINTHEXBYTES_F_UPPER), VERR_INVALID_PARAMETER); 41 41 AssertPtrReturn(pszBuf, VERR_INVALID_POINTER); 42 42 AssertReturn(cb * 2 >= cb, VERR_BUFFER_OVERFLOW); … … 45 45 AssertPtrReturn(pv, VERR_INVALID_POINTER); 46 46 47 static char const s_szHexDigitsLower[17] = "0123456789abcdef"; 48 static char const s_szHexDigitsUpper[17] = "0123456789ABCDEF"; 49 const char *pszHexDigits = !(fFlags & RTSTRPRINTHEXBYTES_F_UPPER) ? s_szHexDigitsLower : s_szHexDigitsUpper; 50 47 51 uint8_t const *pb = (uint8_t const *)pv; 48 52 while (cb-- > 0) 49 53 { 50 static char const s_szHexDigits[17] = "0123456789abcdef";51 54 uint8_t b = *pb++; 52 *pszBuf++ = s_szHexDigits[b >> 4];53 *pszBuf++ = s_szHexDigits[b & 0xf];55 *pszBuf++ = pszHexDigits[b >> 4]; 56 *pszBuf++ = pszHexDigits[b & 0xf]; 54 57 } 55 58 *pszBuf = '\0'; -
trunk/src/VBox/Runtime/common/string/base64.cpp
r44529 r51770 35 35 #include <iprt/err.h> 36 36 #include <iprt/ctype.h> 37 #include <iprt/string.h> 37 38 #ifdef RT_STRICT 38 39 # include <iprt/asm.h> … … 120 121 121 122 122 /** 123 * Calculates the decoded data size for a Base64 encoded string. 124 * 125 * @returns The length in bytes. -1 if the encoding is bad. 126 * 127 * @param pszString The Base64 encoded string. 128 * @param ppszEnd If not NULL, this will point to the first char 129 * following the Base64 encoded text block. If 130 * NULL the entire string is assumed to be Base64. 131 */ 132 RTDECL(ssize_t) RTBase64DecodedSize(const char *pszString, char **ppszEnd) 123 RTDECL(ssize_t) RTBase64DecodedSizeEx(const char *pszString, size_t cchStringMax, char **ppszEnd) 133 124 { 134 125 #ifdef RT_STRICT … … 144 135 AssertCompile(sizeof(char) == sizeof(uint8_t)); 145 136 146 while ( (ch = *pszString))137 while (cchStringMax > 0 && (ch = *pszString)) 147 138 { 148 139 u8 = g_au8CharToVal[ch]; … … 154 145 /* advance */ 155 146 pszString++; 147 cchStringMax--; 156 148 } 157 149 … … 166 158 c6Bits++; 167 159 pszString++; 168 while ((ch = *pszString)) 160 cchStringMax--; 161 while (cchStringMax > 0 && (ch = *pszString)) 169 162 { 170 163 u8 = g_au8CharToVal[ch]; … … 177 170 } 178 171 pszString++; 172 cchStringMax--; 179 173 } 180 174 if (cbPad >= 3) … … 216 210 return cb; 217 211 } 212 RT_EXPORT_SYMBOL(RTBase64DecodedSizeEx); 213 214 215 RTDECL(ssize_t) RTBase64DecodedSize(const char *pszString, char **ppszEnd) 216 { 217 return RTBase64DecodedSizeEx(pszString, RTSTR_MAX, ppszEnd); 218 } 218 219 RT_EXPORT_SYMBOL(RTBase64DecodedSize); 219 220 220 221 221 /** 222 * Decodes a Base64 encoded string into the buffer supplied by the caller. 223 * 224 * @returns IPRT status code. 225 * @retval VERR_BUFFER_OVERFLOW if the buffer is too small. pcbActual will not 226 * be set, nor will ppszEnd. 227 * @retval VERR_INVALID_BASE64_ENCODING if the encoding is wrong. 228 * 229 * @param pszString The Base64 string. Whether the entire string or 230 * just the start of the string is in Base64 depends 231 * on whether ppszEnd is specified or not. 232 * @param pvData Where to store the decoded data. 233 * @param cbData The size of the output buffer that pvData points to. 234 * @param pcbActual Where to store the actual number of bytes returned. 235 * Optional. 236 * @param ppszEnd Indicates that the string may contain other stuff 237 * after the Base64 encoded data when not NULL. Will 238 * be set to point to the first char that's not part of 239 * the encoding. If NULL the entire string must be part 240 * of the Base64 encoded data. 241 */ 242 RTDECL(int) RTBase64Decode(const char *pszString, void *pvData, size_t cbData, size_t *pcbActual, char **ppszEnd) 222 RTDECL(int) RTBase64DecodeEx(const char *pszString, size_t cchStringMax, void *pvData, size_t cbData, 223 size_t *pcbActual, char **ppszEnd) 243 224 { 244 225 #ifdef RT_STRICT … … 251 232 uint8_t u8Trio[3] = { 0, 0, 0 }; /* shuts up gcc */ 252 233 uint8_t *pbData = (uint8_t *)pvData; 253 uint8_t u8 = BASE64_INVALID;234 uint8_t u8; 254 235 unsigned c6Bits = 0; 255 236 unsigned ch; … … 259 240 { 260 241 /* The first 6-bit group. */ 261 while ((u8 = g_au8CharToVal[ch = *pszString]) == BASE64_SPACE)262 pszString++ ;242 while ((u8 = cchStringMax > 0 ? g_au8CharToVal[ch = *pszString] : BASE64_INVALID) == BASE64_SPACE) 243 pszString++, cchStringMax--; 263 244 if (u8 >= 64) 264 245 { … … 268 249 u8Trio[0] = u8 << 2; 269 250 pszString++; 251 cchStringMax--; 270 252 271 253 /* The second 6-bit group. */ 272 while ((u8 = g_au8CharToVal[ch = *pszString]) == BASE64_SPACE)273 pszString++ ;254 while ((u8 = cchStringMax > 0 ? g_au8CharToVal[ch = *pszString] : BASE64_INVALID) == BASE64_SPACE) 255 pszString++, cchStringMax--; 274 256 if (u8 >= 64) 275 257 { … … 280 262 u8Trio[1] = u8 << 4; 281 263 pszString++; 264 cchStringMax--; 282 265 283 266 /* The third 6-bit group. */ 284 while ((u8 = g_au8CharToVal[ch = *pszString]) == BASE64_SPACE) 285 pszString++; 267 u8 = BASE64_INVALID; 268 while ((u8 = cchStringMax > 0 ? g_au8CharToVal[ch = *pszString] : BASE64_INVALID) == BASE64_SPACE) 269 pszString++, cchStringMax--; 286 270 if (u8 >= 64) 287 271 { … … 292 276 u8Trio[2] = u8 << 6; 293 277 pszString++; 278 cchStringMax--; 294 279 295 280 /* The fourth 6-bit group. */ 296 while ((u8 = g_au8CharToVal[ch = *pszString]) == BASE64_SPACE) 297 pszString++; 281 u8 = BASE64_INVALID; 282 while ((u8 = cchStringMax > 0 ? g_au8CharToVal[ch = *pszString] : BASE64_INVALID) == BASE64_SPACE) 283 pszString++, cchStringMax--; 298 284 if (u8 >= 64) 299 285 { … … 303 289 u8Trio[2] |= u8; 304 290 pszString++; 291 cchStringMax--; 305 292 306 293 /* flush the trio */ … … 323 310 cbPad = 1; 324 311 pszString++; 325 while ((ch = *pszString)) 312 cchStringMax--; 313 while (cchStringMax > 0 && (ch = *pszString)) 326 314 { 327 315 u8 = g_au8CharToVal[ch]; … … 333 321 } 334 322 pszString++; 323 cchStringMax--; 335 324 } 336 325 if (cbPad >= 3) … … 399 388 *pcbActual = pbData - (uint8_t *)pvData; 400 389 return VINF_SUCCESS; 390 } 391 RT_EXPORT_SYMBOL(RTBase64DecodeEx); 392 393 394 RTDECL(int) RTBase64Decode(const char *pszString, void *pvData, size_t cbData, size_t *pcbActual, char **ppszEnd) 395 { 396 return RTBase64DecodeEx(pszString, RTSTR_MAX, pvData, cbData, pcbActual, ppszEnd); 401 397 } 402 398 RT_EXPORT_SYMBOL(RTBase64Decode); -
trunk/src/VBox/Runtime/common/string/uniread.cpp
r48935 r51770 35 35 #include <string.h> 36 36 #include <stdlib.h> 37 #ifdef _MSC_VER 38 # include <direct.h> 39 #else 40 # include <unistd.h> 41 #endif 37 42 38 43 … … 40 45 * Global Variables * 41 46 *******************************************************************************/ 42 /** When set, no output is produced. Very useful when debugging ths code. */43 static bool g_fQuiet = false;44 47 /** The file we're currently parsing. */ 45 48 static const char *g_pszCurFile; 46 49 /** The current line number. */ 47 50 static unsigned g_iLine; 51 /** The current output file. */ 52 static FILE *g_pCurOutFile; 48 53 49 54 … … 884 889 //if (pInfo->???) 885 890 // AppendFlag(pszFlags, "RTUNI_BSPACE"); 891 #if 0 886 892 if (pInfo->fInvNFD_QC != 0 || pInfo->fInvNFC_QC != 0) 887 893 { … … 894 900 else if (pInfo->paDecompositionMapping && !*pInfo->pszDecompositionType) 895 901 fprintf(stderr, "uniread: U+%05X is not QC_NFX but has canonical mappings.\n", pInfo->CodePoint); 902 #endif 896 903 897 904 if (!*pszFlags) … … 906 913 907 914 /** 915 * Closes the primary output stream. 916 */ 917 static int Stream1Close(void) 918 { 919 if (g_pCurOutFile && g_pCurOutFile != stdout && g_pCurOutFile != stderr) 920 { 921 if (fclose(g_pCurOutFile) != 0) 922 { 923 fprintf(stderr, "Error closing output file.\n"); 924 return -1; 925 } 926 } 927 g_pCurOutFile = NULL; 928 return 0; 929 } 930 931 932 /** 933 * Initializes the 1st stream to output to a given file. 934 */ 935 static int Stream1Init(const char *pszName) 936 { 937 int rc = Stream1Close(); 938 if (!rc) 939 { 940 g_pCurOutFile = fopen(pszName, "w"); 941 if (!g_pCurOutFile) 942 { 943 fprintf(stderr, "Error opening output file '%s'.\n", pszName); 944 rc = -1; 945 } 946 } 947 return rc; 948 } 949 950 951 /** 908 952 * printf wrapper for the primary output stream. 909 953 * … … 917 961 va_list va; 918 962 va_start(va, pszFormat); 919 if (!g_fQuiet) 920 cch = vfprintf(stdout, pszFormat, va); 921 else 922 cch = (int)strlen(pszFormat); 963 cch = vfprintf(g_pCurOutFile, pszFormat, va); 923 964 va_end(va); 924 965 return cch; … … 974 1015 * Print the unidata.cpp file header and include list. 975 1016 */ 976 int PrintHeader(const char *argv0) 977 { 978 Stream1Printf("/** @file\n" 979 " *\n" 1017 int PrintHeader(const char *argv0, const char *pszBaseDir) 1018 { 1019 char szBuf[1024]; 1020 if (!pszBaseDir) 1021 { 1022 memset(szBuf, 0, sizeof(szBuf)); 1023 #ifdef _MSC_VER 1024 _getcwd(szBuf, sizeof(szBuf)); 1025 #else 1026 getcwd(szBuf, sizeof(szBuf)); 1027 #endif 1028 pszBaseDir = szBuf; 1029 } 1030 1031 Stream1Printf("/* $" "Id" "$ */\n" 1032 "/** @file\n" 980 1033 " * IPRT - Unicode Tables.\n" 981 1034 " *\n" 982 " * Automatically Generated by %s (" __DATE__ " " __TIME__ ")\n" 1035 " * Automatically Generated from %s\n" 1036 " * by %s (" __DATE__ " " __TIME__ ")\n" 983 1037 " */\n" 984 1038 "\n" 985 1039 "/*\n" 986 " * Copyright (C) 2006-201 0Oracle Corporation\n"1040 " * Copyright (C) 2006-2014 Oracle Corporation\n" 987 1041 " *\n" 988 1042 " * This file is part of VirtualBox Open Source Edition (OSE), as\n" … … 1006 1060 "#include <iprt/uni.h>\n" 1007 1061 "\n", 1008 argv0);1062 pszBaseDir, argv0); 1009 1063 return 0; 1010 1064 } … … 1020 1074 */ 1021 1075 Stream2Init(); 1022 Stream2Printf(" const RTUNIFLAGSRANGEg_aRTUniFlagsRanges[] =\n"1076 Stream2Printf("RT_DECL_DATA_CONST(const RTUNIFLAGSRANGE) g_aRTUniFlagsRanges[] =\n" 1023 1077 "{\n"); 1024 1078 RTUNICP i = 0; … … 1047 1101 if (iStart < 0) 1048 1102 { 1049 Stream1Printf("static const uint8_t g_afRTUniFlags0x%06x[] = 1103 Stream1Printf("static const uint8_t g_afRTUniFlags0x%06x[] =\n" 1050 1104 "{\n", i); 1051 1105 iStart = i; … … 1069 1123 { 1070 1124 Stream2Init(); 1071 Stream2Printf(" const RTUNICASERANGEg_aRTUniUpperRanges[] =\n"1125 Stream2Printf("RT_DECL_DATA_CONST(const RTUNICASERANGE) g_aRTUniUpperRanges[] =\n" 1072 1126 "{\n"); 1073 1127 RTUNICP i = 0; … … 1095 1149 if (iStart < 0) 1096 1150 { 1097 Stream1Printf("static const RTUNICP g_afRTUniUpper0x%06x[] = 1151 Stream1Printf("static const RTUNICP g_afRTUniUpper0x%06x[] =\n" 1098 1152 "{\n", i); 1099 1153 iStart = i; … … 1116 1170 { 1117 1171 Stream2Init(); 1118 Stream2Printf(" const RTUNICASERANGEg_aRTUniLowerRanges[] =\n"1172 Stream2Printf("RT_DECL_DATA_CONST(const RTUNICASERANGE) g_aRTUniLowerRanges[] =\n" 1119 1173 "{\n"); 1120 1174 RTUNICP i = 0; … … 1142 1196 if (iStart < 0) 1143 1197 { 1144 Stream1Printf("static const RTUNICP g_afRTUniLower0x%06x[] = 1198 Stream1Printf("static const RTUNICP g_afRTUniLower0x%06x[] =\n" 1145 1199 "{\n", i); 1146 1200 iStart = i; … … 1202 1256 pszBaseDir = argv[argi]; 1203 1257 } 1204 else if ( !strcmp(argv[argi], "-q")1205 || !strcmp(argv[argi], "--quiet"))1206 g_fQuiet = true;1207 1258 else 1208 1259 { … … 1232 1283 1233 1284 /* 1234 * Pr int stuff.1285 * Produce output files. 1235 1286 */ 1236 rc = PrintHeader(argv[0]); 1237 if (rc) 1238 return rc; 1239 rc = PrintFlags(); 1240 if (rc) 1241 return rc; 1242 rc = PrintUpper(); 1243 if (rc) 1244 return rc; 1245 rc = PrintLower(); 1246 if (rc) 1247 return rc; 1287 rc = Stream1Init("unidata-flags.cpp"); 1288 if (!rc) 1289 rc = PrintHeader(argv[0], pszBaseDir); 1290 if (!rc) 1291 rc = PrintFlags(); 1292 1293 rc = Stream1Init("unidata-upper.cpp"); 1294 if (!rc) 1295 rc = PrintHeader(argv[0], pszBaseDir); 1296 if (!rc) 1297 rc = PrintUpper(); 1298 1299 rc = Stream1Init("unidata-lower.cpp"); 1300 if (!rc) 1301 rc = PrintHeader(argv[0], pszBaseDir); 1302 if (!rc) 1303 rc = PrintLower(); 1304 if (!rc) 1305 rc = Stream1Close(); 1248 1306 1249 1307 /* done */ 1250 fflush(stdout);1251 1252 1308 return rc; 1253 1309 } -
trunk/src/VBox/Runtime/common/string/utf-16.cpp
r50795 r51770 171 171 172 172 173 RTDECL(int) RTUtf16ICmp(register PCRTUTF16 pwsz1, register PCRTUTF16 pwsz2)174 {175 if (pwsz1 == pwsz2)176 return 0;177 if (!pwsz1)178 return -1;179 if (!pwsz2)180 return 1;181 182 PCRTUTF16 pwsz1Start = pwsz1; /* keep it around in case we have to backtrack on a surrogate pair */183 for (;;)184 {185 register RTUTF16 wc1 = *pwsz1;186 register RTUTF16 wc2 = *pwsz2;187 register int iDiff = wc1 - wc2;188 if (iDiff)189 {190 /* unless they are *both* surrogate pairs, there is no chance they'll be identical. */191 if ( wc1 < 0xd800192 || wc2 < 0xd800193 || wc1 > 0xdfff194 || wc2 > 0xdfff)195 {196 /* simple UCS-2 char */197 iDiff = RTUniCpToUpper(wc1) - RTUniCpToUpper(wc2);198 if (iDiff)199 iDiff = RTUniCpToLower(wc1) - RTUniCpToLower(wc2);200 }201 else202 {203 /* a damned pair */204 RTUNICP uc1;205 RTUNICP uc2;206 if (wc1 >= 0xdc00)207 {208 if (pwsz1Start == pwsz1)209 return iDiff;210 uc1 = pwsz1[-1];211 if (uc1 < 0xd800 || uc1 >= 0xdc00)212 return iDiff;213 uc1 = 0x10000 + (((uc1 & 0x3ff) << 10) | (wc1 & 0x3ff));214 uc2 = 0x10000 + (((pwsz2[-1] & 0x3ff) << 10) | (wc2 & 0x3ff));215 }216 else217 {218 uc1 = *++pwsz1;219 if (uc1 < 0xdc00 || uc1 >= 0xe000)220 return iDiff;221 uc1 = 0x10000 + (((wc1 & 0x3ff) << 10) | (uc1 & 0x3ff));222 uc2 = 0x10000 + (((wc2 & 0x3ff) << 10) | (*++pwsz2 & 0x3ff));223 }224 iDiff = RTUniCpToUpper(uc1) - RTUniCpToUpper(uc2);225 if (iDiff)226 iDiff = RTUniCpToLower(uc1) - RTUniCpToLower(uc2); /* serious paranoia! */227 }228 if (iDiff)229 return iDiff;230 }231 if (!wc1)232 return 0;233 pwsz1++;234 pwsz2++;235 }236 }237 RT_EXPORT_SYMBOL(RTUtf16ICmp);238 239 240 RTDECL(PRTUTF16) RTUtf16ToLower(PRTUTF16 pwsz)241 {242 PRTUTF16 pwc = pwsz;243 for (;;)244 {245 RTUTF16 wc = *pwc;246 if (!wc)247 break;248 if (wc < 0xd800 || wc >= 0xdc00)249 {250 RTUNICP ucFolded = RTUniCpToLower(wc);251 if (ucFolded < 0x10000)252 *pwc++ = RTUniCpToLower(wc);253 }254 else255 {256 /* surrogate */257 RTUTF16 wc2 = pwc[1];258 if (wc2 >= 0xdc00 && wc2 <= 0xdfff)259 {260 RTUNICP uc = 0x10000 + (((wc & 0x3ff) << 10) | (wc2 & 0x3ff));261 RTUNICP ucFolded = RTUniCpToLower(uc);262 if (uc != ucFolded && ucFolded >= 0x10000) /* we don't support shrinking the string */263 {264 uc -= 0x10000;265 *pwc++ = 0xd800 | (uc >> 10);266 *pwc++ = 0xdc00 | (uc & 0x3ff);267 }268 }269 else /* invalid encoding. */270 pwc++;271 }272 }273 return pwsz;274 }275 RT_EXPORT_SYMBOL(RTUtf16ToLower);276 277 278 RTDECL(PRTUTF16) RTUtf16ToUpper(PRTUTF16 pwsz)279 {280 PRTUTF16 pwc = pwsz;281 for (;;)282 {283 RTUTF16 wc = *pwc;284 if (!wc)285 break;286 if (wc < 0xd800 || wc >= 0xdc00)287 *pwc++ = RTUniCpToUpper(wc);288 else289 {290 /* surrogate */291 RTUTF16 wc2 = pwc[1];292 if (wc2 >= 0xdc00 && wc2 <= 0xdfff)293 {294 RTUNICP uc = 0x10000 + (((wc & 0x3ff) << 10) | (wc2 & 0x3ff));295 RTUNICP ucFolded = RTUniCpToUpper(uc);296 if (uc != ucFolded && ucFolded >= 0x10000) /* we don't support shrinking the string */297 {298 uc -= 0x10000;299 *pwc++ = 0xd800 | (uc >> 10);300 *pwc++ = 0xdc00 | (uc & 0x3ff);301 }302 }303 else /* invalid encoding. */304 pwc++;305 }306 }307 return pwsz;308 }309 RT_EXPORT_SYMBOL(RTUtf16ToUpper);310 311 312 173 RTDECL(int) RTUtf16ValidateEncoding(PCRTUTF16 pwsz) 313 174 { … … 786 647 RT_EXPORT_SYMBOL(RTUtf16PutCpInternal); 787 648 788 789 /**790 * Validate the UTF-16 encoding and calculates the length of a Latin1 encoding.791 *792 * @returns iprt status code.793 * @param pwsz The UTF-16 string.794 * @param cwc The max length of the UTF-16 string to consider.795 * @param pcch Where to store the length (excluding '\\0') of the Latin1 string. (cch == cb, btw)796 */797 static int rtUtf16CalcLatin1Length(PCRTUTF16 pwsz, size_t cwc, size_t *pcch)798 {799 int rc = VINF_SUCCESS;800 size_t cch = 0;801 while (cwc > 0)802 {803 RTUTF16 wc = *pwsz++; cwc--;804 if (!wc)805 break;806 else if (RT_LIKELY(wc < 0x100))807 ++cch;808 else809 {810 if (wc < 0xd800 || wc > 0xdfff)811 {812 if (wc >= 0xfffe)813 {814 RTStrAssertMsgFailed(("endian indicator! wc=%#x\n", wc));815 rc = VERR_CODE_POINT_ENDIAN_INDICATOR;816 break;817 }818 }819 else820 {821 if (wc >= 0xdc00)822 {823 RTStrAssertMsgFailed(("Wrong 1st char in surrogate! wc=%#x\n", wc));824 rc = VERR_INVALID_UTF16_ENCODING;825 break;826 }827 if (cwc <= 0)828 {829 RTStrAssertMsgFailed(("Invalid length! wc=%#x\n", wc));830 rc = VERR_INVALID_UTF16_ENCODING;831 break;832 }833 wc = *pwsz++; cwc--;834 if (wc < 0xdc00 || wc > 0xdfff)835 {836 RTStrAssertMsgFailed(("Wrong 2nd char in surrogate! wc=%#x\n", wc));837 rc = VERR_INVALID_UTF16_ENCODING;838 break;839 }840 }841 842 rc = VERR_NO_TRANSLATION;843 break;844 }845 }846 847 /* done */848 *pcch = cch;849 return rc;850 }851 852 853 /**854 * Recodes an valid UTF-16 string as Latin1.855 *856 * @returns iprt status code.857 * @param pwsz The UTF-16 string.858 * @param cwc The number of RTUTF16 characters to process from pwsz. The recoding859 * will stop when cwc or '\\0' is reached.860 * @param psz Where to store the Latin1 string.861 * @param cch The size of the Latin1 buffer, excluding the terminator.862 */863 static int rtUtf16RecodeAsLatin1(PCRTUTF16 pwsz, size_t cwc, char *psz, size_t cch)864 {865 unsigned char *pch = (unsigned char *)psz;866 int rc = VINF_SUCCESS;867 while (cwc > 0)868 {869 RTUTF16 wc = *pwsz++; cwc--;870 if (!wc)871 break;872 if (RT_LIKELY(wc < 0x100))873 {874 if (RT_UNLIKELY(cch < 1))875 {876 RTStrAssertMsgFailed(("Buffer overflow! 1\n"));877 rc = VERR_BUFFER_OVERFLOW;878 break;879 }880 cch--;881 *pch++ = (unsigned char)wc;882 }883 else884 {885 if (wc < 0xd800 || wc > 0xdfff)886 {887 if (wc >= 0xfffe)888 {889 RTStrAssertMsgFailed(("endian indicator! wc=%#x\n", wc));890 rc = VERR_CODE_POINT_ENDIAN_INDICATOR;891 break;892 }893 }894 else895 {896 if (wc >= 0xdc00)897 {898 RTStrAssertMsgFailed(("Wrong 1st char in surrogate! wc=%#x\n", wc));899 rc = VERR_INVALID_UTF16_ENCODING;900 break;901 }902 if (cwc <= 0)903 {904 RTStrAssertMsgFailed(("Invalid length! wc=%#x\n", wc));905 rc = VERR_INVALID_UTF16_ENCODING;906 break;907 }908 RTUTF16 wc2 = *pwsz++; cwc--;909 if (wc2 < 0xdc00 || wc2 > 0xdfff)910 {911 RTStrAssertMsgFailed(("Wrong 2nd char in surrogate! wc=%#x\n", wc));912 rc = VERR_INVALID_UTF16_ENCODING;913 break;914 }915 }916 917 rc = VERR_NO_TRANSLATION;918 break;919 }920 }921 922 /* done */923 *pch = '\0';924 return rc;925 }926 927 928 RTDECL(int) RTUtf16ToLatin1Tag(PCRTUTF16 pwszString, char **ppszString, const char *pszTag)929 {930 /*931 * Validate input.932 */933 Assert(VALID_PTR(ppszString));934 Assert(VALID_PTR(pwszString));935 *ppszString = NULL;936 937 /*938 * Validate the UTF-16 string and calculate the length of the UTF-8 encoding of it.939 */940 size_t cch;941 int rc = rtUtf16CalcLatin1Length(pwszString, RTSTR_MAX, &cch);942 if (RT_SUCCESS(rc))943 {944 /*945 * Allocate buffer and recode it.946 */947 char *pszResult = (char *)RTMemAllocTag(cch + 1, pszTag);948 if (pszResult)949 {950 rc = rtUtf16RecodeAsLatin1(pwszString, RTSTR_MAX, pszResult, cch);951 if (RT_SUCCESS(rc))952 {953 *ppszString = pszResult;954 return rc;955 }956 957 RTMemFree(pszResult);958 }959 else960 rc = VERR_NO_STR_MEMORY;961 }962 return rc;963 }964 RT_EXPORT_SYMBOL(RTUtf16ToLatin1Tag);965 966 967 RTDECL(int) RTUtf16ToLatin1ExTag(PCRTUTF16 pwszString, size_t cwcString, char **ppsz, size_t cch, size_t *pcch, const char *pszTag)968 {969 /*970 * Validate input.971 */972 AssertPtr(pwszString);973 AssertPtr(ppsz);974 AssertPtrNull(pcch);975 976 /*977 * Validate the UTF-16 string and calculate the length of the Latin1 encoding of it.978 */979 size_t cchResult;980 int rc = rtUtf16CalcLatin1Length(pwszString, cwcString, &cchResult);981 if (RT_SUCCESS(rc))982 {983 if (pcch)984 *pcch = cchResult;985 986 /*987 * Check buffer size / Allocate buffer and recode it.988 */989 bool fShouldFree;990 char *pszResult;991 if (cch > 0 && *ppsz)992 {993 fShouldFree = false;994 if (cch <= cchResult)995 return VERR_BUFFER_OVERFLOW;996 pszResult = *ppsz;997 }998 else999 {1000 *ppsz = NULL;1001 fShouldFree = true;1002 cch = RT_MAX(cch, cchResult + 1);1003 pszResult = (char *)RTMemAllocTag(cch, pszTag);1004 }1005 if (pszResult)1006 {1007 rc = rtUtf16RecodeAsLatin1(pwszString, cwcString, pszResult, cch - 1);1008 if (RT_SUCCESS(rc))1009 {1010 *ppsz = pszResult;1011 return rc;1012 }1013 1014 if (fShouldFree)1015 RTMemFree(pszResult);1016 }1017 else1018 rc = VERR_NO_STR_MEMORY;1019 }1020 return rc;1021 }1022 RT_EXPORT_SYMBOL(RTUtf16ToLatin1ExTag);1023 1024 1025 RTDECL(size_t) RTUtf16CalcLatin1Len(PCRTUTF16 pwsz)1026 {1027 size_t cch;1028 int rc = rtUtf16CalcLatin1Length(pwsz, RTSTR_MAX, &cch);1029 return RT_SUCCESS(rc) ? cch : 0;1030 }1031 RT_EXPORT_SYMBOL(RTUtf16CalcLatin1Len);1032 1033 1034 RTDECL(int) RTUtf16CalcLatin1LenEx(PCRTUTF16 pwsz, size_t cwc, size_t *pcch)1035 {1036 size_t cch;1037 int rc = rtUtf16CalcLatin1Length(pwsz, cwc, &cch);1038 if (pcch)1039 *pcch = RT_SUCCESS(rc) ? cch : ~(size_t)0;1040 return rc;1041 }1042 RT_EXPORT_SYMBOL(RTUtf16CalcLatin1LenEx);1043 1044 1045 /**1046 * Calculates the UTF-16 length of a Latin1 string. In fact this is just the1047 * original length, but the function saves us nasty comments to that effect1048 * all over the place.1049 *1050 * @returns IPRT status code.1051 * @param psz Pointer to the Latin1 string.1052 * @param cch The max length of the string. (btw cch = cb)1053 * Use RTSTR_MAX if all of the string is to be examined.s1054 * @param pcwc Where to store the length of the UTF-16 string as a number of RTUTF16 characters.1055 */1056 static int rtLatin1CalcUtf16Length(const char *psz, size_t cch, size_t *pcwc)1057 {1058 *pcwc = RTStrNLen(psz, cch);1059 return VINF_SUCCESS;1060 }1061 1062 1063 /**1064 * Recodes a Latin1 string as UTF-16. This is just a case of expanding it to1065 * sixteen bits, as Unicode is a superset of Latin1.1066 *1067 * Since we know the input is valid, we do *not* perform length checks.1068 *1069 * @returns iprt status code.1070 * @param psz The Latin1 string to recode.1071 * @param cch The number of chars (the type char, so bytes if you like) to process of the Latin1 string.1072 * The recoding will stop when cch or '\\0' is reached. Pass RTSTR_MAX to process up to '\\0'.1073 * @param pwsz Where to store the UTF-16 string.1074 * @param cwc The number of RTUTF16 items the pwsz buffer can hold, excluding the terminator ('\\0').1075 */1076 static int rtLatin1RecodeAsUtf16(const char *psz, size_t cch, PRTUTF16 pwsz, size_t cwc)1077 {1078 int rc = VINF_SUCCESS;1079 const unsigned char *puch = (const unsigned char *)psz;1080 PRTUTF16 pwc = pwsz;1081 while (cch-- > 0)1082 {1083 /* read the next char and check for terminator. */1084 const unsigned char uch = *puch;1085 if (!uch)1086 break;1087 1088 /* check for output overflow */1089 if (RT_UNLIKELY(cwc < 1))1090 {1091 rc = VERR_BUFFER_OVERFLOW;1092 break;1093 }1094 1095 /* expand the code point */1096 *pwc++ = uch;1097 cwc--;1098 puch++;1099 }1100 1101 /* done */1102 *pwc = '\0';1103 return rc;1104 }1105 1106 1107 RTDECL(int) RTLatin1ToUtf16Tag(const char *pszString, PRTUTF16 *ppwszString, const char *pszTag)1108 {1109 /*1110 * Validate input.1111 */1112 Assert(VALID_PTR(ppwszString));1113 Assert(VALID_PTR(pszString));1114 *ppwszString = NULL;1115 1116 /*1117 * Validate the input and calculate the length of the UTF-16 string.1118 */1119 size_t cwc;1120 int rc = rtLatin1CalcUtf16Length(pszString, RTSTR_MAX, &cwc);1121 if (RT_SUCCESS(rc))1122 {1123 /*1124 * Allocate buffer.1125 */1126 PRTUTF16 pwsz = (PRTUTF16)RTMemAllocTag((cwc + 1) * sizeof(RTUTF16), pszTag);1127 if (pwsz)1128 {1129 /*1130 * Encode the UTF-16 string.1131 */1132 rc = rtLatin1RecodeAsUtf16(pszString, RTSTR_MAX, pwsz, cwc);1133 if (RT_SUCCESS(rc))1134 {1135 *ppwszString = pwsz;1136 return rc;1137 }1138 RTMemFree(pwsz);1139 }1140 else1141 rc = VERR_NO_UTF16_MEMORY;1142 }1143 return rc;1144 }1145 RT_EXPORT_SYMBOL(RTLatin1ToUtf16Tag);1146 1147 1148 RTDECL(int) RTLatin1ToUtf16ExTag(const char *pszString, size_t cchString,1149 PRTUTF16 *ppwsz, size_t cwc, size_t *pcwc, const char *pszTag)1150 {1151 /*1152 * Validate input.1153 */1154 Assert(VALID_PTR(pszString));1155 Assert(VALID_PTR(ppwsz));1156 Assert(!pcwc || VALID_PTR(pcwc));1157 1158 /*1159 * Validate the input and calculate the length of the UTF-16 string.1160 */1161 size_t cwcResult;1162 int rc = rtLatin1CalcUtf16Length(pszString, cchString, &cwcResult);1163 if (RT_SUCCESS(rc))1164 {1165 if (pcwc)1166 *pcwc = cwcResult;1167 1168 /*1169 * Check buffer size / Allocate buffer.1170 */1171 bool fShouldFree;1172 PRTUTF16 pwszResult;1173 if (cwc > 0 && *ppwsz)1174 {1175 fShouldFree = false;1176 if (cwc <= cwcResult)1177 return VERR_BUFFER_OVERFLOW;1178 pwszResult = *ppwsz;1179 }1180 else1181 {1182 *ppwsz = NULL;1183 fShouldFree = true;1184 cwc = RT_MAX(cwcResult + 1, cwc);1185 pwszResult = (PRTUTF16)RTMemAllocTag(cwc * sizeof(RTUTF16), pszTag);1186 }1187 if (pwszResult)1188 {1189 /*1190 * Encode the UTF-16 string.1191 */1192 rc = rtLatin1RecodeAsUtf16(pszString, cchString, pwszResult, cwc - 1);1193 if (RT_SUCCESS(rc))1194 {1195 *ppwsz = pwszResult;1196 return rc;1197 }1198 if (fShouldFree)1199 RTMemFree(pwszResult);1200 }1201 else1202 rc = VERR_NO_UTF16_MEMORY;1203 }1204 return rc;1205 }1206 RT_EXPORT_SYMBOL(RTLatin1ToUtf16ExTag);1207 1208 1209 RTDECL(size_t) RTLatin1CalcUtf16Len(const char *psz)1210 {1211 size_t cwc;1212 int rc = rtLatin1CalcUtf16Length(psz, RTSTR_MAX, &cwc);1213 return RT_SUCCESS(rc) ? cwc : 0;1214 }1215 RT_EXPORT_SYMBOL(RTLatin1CalcUtf16Len);1216 1217 1218 RTDECL(int) RTLatin1CalcUtf16LenEx(const char *psz, size_t cch, size_t *pcwc)1219 {1220 size_t cwc;1221 int rc = rtLatin1CalcUtf16Length(psz, cch, &cwc);1222 if (pcwc)1223 *pcwc = RT_SUCCESS(rc) ? cwc : ~(size_t)0;1224 return rc;1225 }1226 RT_EXPORT_SYMBOL(RTLatin1CalcUtf16LenEx); -
trunk/src/VBox/Runtime/common/string/utf-8-case.cpp
r48935 r51770 1 1 /* $Id$ */ 2 2 /** @file 3 * IPRT - UTF-8 Case Sensitivity and Folding .3 * IPRT - UTF-8 Case Sensitivity and Folding, Part 1. 4 4 */ 5 5 … … 339 339 RT_EXPORT_SYMBOL(RTStrToUpper); 340 340 341 342 RTDECL(bool) RTStrIsCaseFoldable(const char *psz)343 {344 /*345 * Loop the code points in the string, checking them one by one until we346 * find something that can be folded.347 */348 RTUNICP uc;349 do350 {351 int rc = RTStrGetCpEx(&psz, &uc);352 if (RT_SUCCESS(rc))353 {354 if (RTUniCpIsFoldable(uc))355 return true;356 }357 else358 {359 /* bad encoding, just skip it quietly (uc == RTUNICP_INVALID (!= 0)). */360 AssertRC(rc);361 }362 } while (uc != 0);363 364 return false;365 }366 RT_EXPORT_SYMBOL(RTStrIsCaseFoldable);367 368 369 RTDECL(bool) RTStrIsUpperCased(const char *psz)370 {371 /*372 * Check that there are no lower case chars in the string.373 */374 RTUNICP uc;375 do376 {377 int rc = RTStrGetCpEx(&psz, &uc);378 if (RT_SUCCESS(rc))379 {380 if (RTUniCpIsLower(uc))381 return false;382 }383 else384 {385 /* bad encoding, just skip it quietly (uc == RTUNICP_INVALID (!= 0)). */386 AssertRC(rc);387 }388 } while (uc != 0);389 390 return true;391 }392 RT_EXPORT_SYMBOL(RTStrIsUpperCased);393 394 395 RTDECL(bool) RTStrIsLowerCased(const char *psz)396 {397 /*398 * Check that there are no lower case chars in the string.399 */400 RTUNICP uc;401 do402 {403 int rc = RTStrGetCpEx(&psz, &uc);404 if (RT_SUCCESS(rc))405 {406 if (RTUniCpIsUpper(uc))407 return false;408 }409 else410 {411 /* bad encoding, just skip it quietly (uc == RTUNICP_INVALID (!= 0)). */412 AssertRC(rc);413 }414 } while (uc != 0);415 416 return true;417 }418 RT_EXPORT_SYMBOL(RTStrIsLowerCased);419
Note:
See TracChangeset
for help on using the changeset viewer.