Changeset 74733 in vbox for trunk/src/VBox/Runtime
- Timestamp:
- Oct 10, 2018 11:22:07 AM (6 years ago)
- svn:sync-xref-src-repo-rev:
- 125663
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/ldr/ldrMachO.cpp
r74727 r74733 3893 3893 void *pv = RTMemAllocZ(RT_ALIGN_Z(pThis->cbCodeSignature, 16)); 3894 3894 AssertReturn(pv, VERR_NO_MEMORY); 3895 int rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pv, pThis->cbCodeSignature, pThis->offCodeSignature); 3895 int rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pv, pThis->cbCodeSignature, 3896 pThis->offImage + pThis->offCodeSignature); 3896 3897 if (RT_SUCCESS(rc)) 3897 3898 { … … 4293 4294 4294 4295 /** @todo idPlatform values. */ 4295 4296 /** @todo Check for gaps if we know the version number? Alignment? */ 4297 4298 /* If first code directory, check that the code limit covers the whole image up to the signature data. */ 4299 if (pSignature->cCodeDirs == 0) 4300 { 4301 /** @todo verify the that the signature data is at the very end... */ 4302 if (cbCodeLimit32 != pThis->offCodeSignature) 4303 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4304 "Slot #%u: Unexpected code limit: %#x, expected %#x", 4305 iSlot, cbCodeLimit32, pThis->offCodeSignature); 4306 } 4307 /* Otherwise, check that the code limit matches the previous directories. */ 4308 else 4309 for (uint32_t i = 0; i < pSignature->cCodeDirs; i++) 4310 if (pSignature->aCodeDirs[i].pCodeDir->cbCodeLimit32 != pCodeDir->cbCodeLimit32) 4311 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4312 "Slot #%u: Code limit differs from previous directory: %#x, expected %#x", 4313 iSlot, cbCodeLimit32, RT_BE2H_U32(pSignature->aCodeDirs[i].pCodeDir->cbCodeLimit32)); 4296 4314 4297 4315 /* Commit the code dir entry: */ … … 4362 4380 4363 4381 /** 4382 * Worker for rtldrMachO_VerifySignatureValidatePkcs7Hashes that handles plists 4383 * with code directory hashes inside them. 4384 * 4385 * It is assumed that these plist files was invented to handle alternative code 4386 * directories. 4387 * 4388 * @note Putting an XML plist into the authenticated attribute list was 4389 * probably not such a great idea, given all the optional and 4390 * adjustable white-space padding. We should probably validate 4391 * everything very strictly, limiting the elements, require certain 4392 * attribute lists and even have strict expectations about the 4393 * white-space, but right now let just make sure it's xml and get the 4394 * data in the cdhashes array. 4395 */ 4396 static int rtldrMachO_VerifySignatureValidateCdHashesPlist(PRTLDRMACHOSIGNATURE pSignature, char *pszPlist, 4397 uint8_t *pbHash, uint32_t cbHash, PRTERRINFO pErrInfo) 4398 { 4399 const char * const pszStart = pszPlist; 4400 #define CHECK_AND_SKIP_OR_RETURN(a_szLead) \ 4401 do { \ 4402 if (!RTStrNICmp(pszPlist, RT_STR_TUPLE(a_szLead))) \ 4403 pszPlist += sizeof(a_szLead) - 1; \ 4404 else return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, \ 4405 "Expected '%s' found '%.16s...' at %#zu in plist", a_szLead, pszPlist, pszPlist - pszStart); \ 4406 } while (0) 4407 #define CHECK_CASE_AND_SKIP_OR_RETURN(a_szLead) \ 4408 do { \ 4409 if (!RTStrNCmp(pszPlist, RT_STR_TUPLE(a_szLead))) \ 4410 pszPlist += sizeof(a_szLead) - 1; \ 4411 else return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, \ 4412 "Expected '%s' found '%.16s...' at %#zu in plist", a_szLead, pszPlist, pszPlist - pszStart); \ 4413 } while (0) 4414 4415 /* <?xml version="1.0" encoding="UTF-8"?> */ 4416 CHECK_CASE_AND_SKIP_OR_RETURN("<?xml"); 4417 RT_NOREF(pSignature, pbHash, cbHash); 4418 return VERR_NOT_IMPLEMENTED; 4419 } 4420 4421 4422 /** 4364 4423 * Verifies the code directory hashes embedded in the PKCS\#7 data. 4365 4424 * … … 4370 4429 static int rtldrMachO_VerifySignatureValidatePkcs7Hashes(PRTLDRMACHOSIGNATURE pSignature, PRTERRINFO pErrInfo) 4371 4430 { 4372 RT_NOREF(pSignature, pErrInfo); 4373 return VERR_NOT_IMPLEMENTED; 4431 /* 4432 * Look thru the authenticated attributes in the signer info array. 4433 */ 4434 PRTCRPKCS7SIGNEDDATA pSignedData = pSignature->pSignedData; 4435 for (uint32_t iSignerInfo = 0; iSignerInfo < pSignedData->SignerInfos.cItems; iSignerInfo++) 4436 { 4437 PCRTCRPKCS7SIGNERINFO pSignerInfo = pSignedData->SignerInfos.papItems[iSignerInfo]; 4438 bool fMsgDigest = false; 4439 bool fPlist = false; 4440 for (uint32_t iAttrib = 0; iAttrib < pSignerInfo->AuthenticatedAttributes.cItems; iAttrib++) 4441 { 4442 PCRTCRPKCS7ATTRIBUTE pAttrib = pSignerInfo->AuthenticatedAttributes.papItems[iAttrib]; 4443 if (RTAsn1ObjId_CompareWithString(&pAttrib->Type, RTCR_PKCS9_ID_MESSAGE_DIGEST_OID) == 0) 4444 { 4445 /* 4446 * Validate the message digest while we're here. 4447 */ 4448 AssertReturn(pAttrib->uValues.pOctetStrings && pAttrib->uValues.pOctetStrings->cItems == 1, VERR_INTERNAL_ERROR_5); 4449 4450 RTCRDIGEST hDigest; 4451 int rc = RTCrDigestCreateByObjId(&hDigest, &pSignerInfo->DigestAlgorithm.Algorithm); 4452 if (RT_SUCCESS(rc)) 4453 { 4454 rc = RTCrDigestUpdate(hDigest, pSignature->aCodeDirs[0].pCodeDir, pSignature->aCodeDirs[0].cb); 4455 if (RT_SUCCESS(rc)) 4456 { 4457 if (!RTCrDigestMatch(hDigest, 4458 pAttrib->uValues.pOctetStrings->papItems[0]->Asn1Core.uData.pv, 4459 pAttrib->uValues.pOctetStrings->papItems[0]->Asn1Core.cb)) 4460 return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_MESSAGE_DIGEST_ATTRIB_MISMATCH, 4461 "Authenticated message-digest attribute mismatch:\n" 4462 "signed: %.*Rhxs\n" 4463 "our: %.*Rhxs\n", 4464 pAttrib->uValues.pOctetStrings->papItems[0]->Asn1Core.cb, 4465 pAttrib->uValues.pOctetStrings->papItems[0]->Asn1Core.uData.pv, 4466 RTCrDigestGetHashSize(hDigest), RTCrDigestGetHash(hDigest)); 4467 } 4468 else 4469 rc = RTErrInfoSetF(pErrInfo, rc, "RTCrDigestUpdate failed: %Rrc", rc); 4470 } 4471 else 4472 rc = RTErrInfoSetF(pErrInfo, rc, "Failed to create a digest for OID %s: %Rrc", 4473 pSignerInfo->DigestAlgorithm.Algorithm.szObjId, rc); 4474 if (RT_FAILURE(rc)) 4475 return rc; 4476 fMsgDigest = true; 4477 } 4478 else if (pAttrib->enmType == RTCRPKCS7ATTRIBUTETYPE_APPLE_MULTI_CD_PLIST) 4479 { 4480 /* 4481 * An XML (better be) property list with code directory hashes in it. 4482 */ 4483 if (!pAttrib->uValues.pOctetStrings || pAttrib->uValues.pOctetStrings->cItems != 1) 4484 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, "Bad authenticated plist attribute"); 4485 4486 uint32_t cch = pAttrib->uValues.pOctetStrings->papItems[0]->Asn1Core.cb; 4487 char const *pch = pAttrib->uValues.pOctetStrings->papItems[0]->Asn1Core.uData.pch; 4488 int rc = RTStrValidateEncodingEx(pch, cch, RTSTR_VALIDATE_ENCODING_EXACT_LENGTH); 4489 if (RT_FAILURE(rc)) 4490 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4491 "Authenticated plist attribute is not valid UTF-8: %Rrc", rc); 4492 uint32_t const cchMin = sizeof("<?xml?><plist><dict><key>cdhashes</key><array><data>hul2SSkDQFRXbGlt3AmCp25MU0Y=</data></array></dict></plist>") - 1; 4493 if (cch < cchMin) 4494 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4495 "Authenticated plist attribute is too short: %#x, min: %#x", cch, cchMin); 4496 if (cch > _64K) 4497 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4498 "Authenticated plist attribute is too long: %#x, max: 64KB", cch, cchMin); 4499 4500 /* Copy the plist into a buffer and zero terminate it. Also allocate room for decoding a hash. */ 4501 const uint32_t cbMaxHash = 128; 4502 char *pszTmp = (char *)RTMemTmpAlloc(cbMaxHash + cch + 3); 4503 if (!pszTmp) 4504 return VERR_NO_TMP_MEMORY; 4505 pszTmp[cbMaxHash + cch] = '\0'; 4506 pszTmp[cbMaxHash + cch + 1] = '\0'; 4507 pszTmp[cbMaxHash + cch + 2] = '\0'; 4508 rc = rtldrMachO_VerifySignatureValidateCdHashesPlist(pSignature, (char *)memcpy(pszTmp + cbMaxHash, pch, cch), 4509 (uint8_t *)pszTmp, cbMaxHash, pErrInfo); 4510 RTMemTmpFree(pszTmp); 4511 if (RT_FAILURE(rc)) 4512 return rc; 4513 fPlist = true; 4514 } 4515 } 4516 if (!fMsgDigest && pSignature->cCodeDirs > 1) 4517 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, "Missing authenticated message-digest attribute"); 4518 if (!fPlist && pSignature->cCodeDirs > 1) 4519 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, "Missing authenticated code directory hash plist attribute"); 4520 } 4521 if (pSignedData->SignerInfos.cItems < 1) 4522 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, "PKCS#7 signed data contains no signatures"); 4523 4524 return VINF_SUCCESS; 4374 4525 } 4375 4526 … … 4381 4532 * @param pThis The Mach-O module instance. 4382 4533 * @param pEntry The data entry for the code directory to validate. 4534 * @param pbBuf Read buffer. 4535 * @param cbBuf Buffer size. 4383 4536 * @param pErrInfo Where to supply extra error details. Optional. 4384 4537 */ 4385 static int rtldrMachO_VerifySignatureValidateCodeDir(PRTLDRMODMACHO pThis, PRTLDRMACHCODEDIR pEntry, PRTERRINFO pErrInfo) 4386 { 4387 RT_NOREF(pThis, pEntry, pErrInfo); 4388 return VERR_NOT_IMPLEMENTED; 4538 static int rtldrMachO_VerifySignatureValidateCodeDir(PRTLDRMODMACHO pThis, PRTLDRMACHCODEDIR pEntry, 4539 uint8_t *pbBuf, uint32_t cbBuf, PRTERRINFO pErrInfo) 4540 { 4541 RTCRDIGEST hDigest; 4542 int rc = RTCrDigestCreateByType(&hDigest, pEntry->enmDigest); 4543 if (RT_SUCCESS(rc)) 4544 { 4545 PCRTCRAPLCSCODEDIRECTORY pCodeDir = pEntry->pCodeDir; 4546 PRTLDRREADER const pRdr = pThis->Core.pReader; 4547 uint32_t cbCodeLimit = RT_BE2H_U32(pCodeDir->cbCodeLimit32); 4548 uint32_t const cbPage = RT_BIT_32(pCodeDir->cPageShift); 4549 uint32_t const cHashes = RT_BE2H_U32(pCodeDir->cCodeSlots); 4550 uint8_t const cbHash = pCodeDir->cbHash; 4551 uint8_t const *pbHash = (uint8_t const *)pCodeDir + RT_BE2H_U32(pCodeDir->offHashSlots); 4552 RTFOFF offFile = pThis->offImage; 4553 if ( RT_BE2H_U32(pCodeDir->uVersion) < RTCRAPLCS_VER_SUPPORTS_SCATTER 4554 || pCodeDir->offScatter == 0) 4555 { 4556 /* 4557 * Work the image in linear fashion. 4558 */ 4559 for (uint32_t iHash = 0; iHash < cHashes; iHash++, pbHash += cbHash, cbCodeLimit -= cbPage) 4560 { 4561 RTFOFF const offPage = offFile; 4562 4563 /* 4564 * Read and digest the data for the current hash page. 4565 */ 4566 rc = RTCrDigestReset(hDigest); 4567 AssertRCBreak(rc); 4568 Assert(cbCodeLimit > cbPage || iHash + 1 == cHashes); 4569 uint32_t cbLeft = iHash + 1 < cHashes ? cbPage : cbCodeLimit; 4570 while (cbLeft > 0) 4571 { 4572 uint32_t const cbToRead = RT_MIN(cbBuf, cbLeft); 4573 rc = pRdr->pfnRead(pRdr, pbBuf, cbToRead, offFile); 4574 AssertRCBreak(rc); 4575 4576 rc = RTCrDigestUpdate(hDigest, pbBuf, cbToRead); 4577 AssertRCBreak(rc); 4578 4579 offFile += cbToRead; 4580 cbLeft -= cbToRead; 4581 } 4582 AssertRCBreak(rc); 4583 rc = RTCrDigestFinal(hDigest, NULL, 0); 4584 AssertRCBreak(rc); 4585 4586 /* 4587 * Compare it. 4588 * Note! Don't use RTCrDigestMatch here as there is a truncated SHA-256 variant. 4589 */ 4590 if (memcmp(pbHash, RTCrDigestGetHash(hDigest), cbHash) != 0) 4591 { 4592 rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_PAGE_HASH_MISMATCH, 4593 "Hash #%u (@%RX64 LB %#x) mismatch in code dir #%u: %.*Rhxs, expected %.*Rhxs", 4594 iHash, offPage, cbPage, pEntry->uSlot, (int)cbHash, pbHash, 4595 (int)cbHash, RTCrDigestGetHash(hDigest)); 4596 break; 4597 } 4598 4599 } 4600 } 4601 /* 4602 * Work the image in scattered fashion. 4603 */ 4604 else 4605 rc = VERR_INTERNAL_ERROR_4; 4606 4607 RTCrDigestRelease(hDigest); 4608 } 4609 return rc; 4389 4610 } 4390 4611 … … 4400 4621 static int rtldrMachO_VerifySignatureValidateCodeDirs(PRTLDRMODMACHO pThis, PRTLDRMACHOSIGNATURE pSignature, PRTERRINFO pErrInfo) 4401 4622 { 4402 int rc = VERR_INTERNAL_ERROR_3; 4403 for (uint32_t i = 0; i < pSignature->cCodeDirs; i++) 4404 { 4405 rc = rtldrMachO_VerifySignatureValidateCodeDir(pThis, &pSignature->aCodeDirs[i], pErrInfo); 4406 if (RT_FAILURE(rc)) 4407 break; 4408 } 4409 return rc; 4623 void *pvBuf = RTMemTmpAllocZ(_4K); 4624 if (pvBuf) 4625 { 4626 int rc = VERR_INTERNAL_ERROR_3; 4627 for (uint32_t i = 0; i < pSignature->cCodeDirs; i++) 4628 { 4629 rc = rtldrMachO_VerifySignatureValidateCodeDir(pThis, &pSignature->aCodeDirs[i], (uint8_t *)pvBuf, _4K, pErrInfo); 4630 if (RT_FAILURE(rc)) 4631 break; 4632 } 4633 RTMemTmpFree(pvBuf); 4634 return rc; 4635 } 4636 return VERR_NO_TMP_MEMORY; 4410 4637 } 4411 4638
Note:
See TracChangeset
for help on using the changeset viewer.