X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=SecurityPkg%2FTcg%2FTcg2Pei%2FTcg2Pei.c;h=3758fc6a41fbdbb64416d37cc9428503409cb188;hp=a72b8d9bda1f56077abcb53b826185e228d714f8;hb=a39e72267034d0cae72be8741fff37f37e5da920;hpb=f5e34e37e018034bc8ce7a2fb9ecb176d948b143 diff --git a/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c b/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c index a72b8d9bda..3758fc6a41 100644 --- a/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c +++ b/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c @@ -1,7 +1,8 @@ /** @file Initialize TPM2 device and measure FVs before handing off control to DXE. -Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.
+Copyright (c) 2017, Microsoft Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -17,11 +18,11 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include -#include #include #include #include #include +#include #include #include @@ -41,7 +42,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include -#include +#include #define PERF_ID_TCG2_PEI 0x3080 @@ -132,7 +133,6 @@ EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList[] = { } }; -EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI *mMeasurementExcludedFvPpi; /** Record all measured Firmware Volum Information into a Guid Hob @@ -190,60 +190,87 @@ EndofPeiSignalNotifyCallBack ( } /** - Set Tpm2HashMask PCD value according to TPM2 PCR bank. + Make sure that the current PCR allocations, the TPM supported PCRs, + and the PcdTpm2HashMask are all in agreement. **/ VOID -SetTpm2HashMask ( +SyncPcrAllocationsAndPcrMask ( VOID ) { - EFI_STATUS Status; - UINT32 ActivePcrBanks; - TPML_PCR_SELECTION Pcrs; - UINTN Index; + EFI_STATUS Status; + EFI_TCG2_EVENT_ALGORITHM_BITMAP TpmHashAlgorithmBitmap; + UINT32 TpmActivePcrBanks; + UINT32 NewTpmActivePcrBanks; + UINT32 Tpm2PcrMask; + UINT32 NewTpm2PcrMask; - DEBUG ((EFI_D_ERROR, "SetTpm2HashMask!\n")); + DEBUG ((EFI_D_ERROR, "SyncPcrAllocationsAndPcrMask!\n")); - Status = Tpm2GetCapabilityPcrs (&Pcrs); - if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityPcrs fail!\n")); - ActivePcrBanks = EFI_TCG2_BOOT_HASH_ALG_SHA1; - } else { - DEBUG ((EFI_D_INFO, "Tpm2GetCapabilityPcrs Count - %08x\n", Pcrs.count)); - ActivePcrBanks = 0; - for (Index = 0; Index < Pcrs.count; Index++) { - DEBUG ((EFI_D_INFO, "hash - %x\n", Pcrs.pcrSelections[Index].hash)); - switch (Pcrs.pcrSelections[Index].hash) { - case TPM_ALG_SHA1: - if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) { - ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA1; - } - break; - case TPM_ALG_SHA256: - if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) { - ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA256; - } - break; - case TPM_ALG_SHA384: - if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) { - ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA384; - } - break; - case TPM_ALG_SHA512: - if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) { - ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA512; - } - break; - case TPM_ALG_SM3_256: - if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) { - ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SM3_256; - } - break; + // + // Determine the current TPM support and the Platform PCR mask. + // + Status = Tpm2GetCapabilitySupportedAndActivePcrs (&TpmHashAlgorithmBitmap, &TpmActivePcrBanks); + ASSERT_EFI_ERROR (Status); + + Tpm2PcrMask = PcdGet32 (PcdTpm2HashMask); + if (Tpm2PcrMask == 0) { + // + // if PcdTPm2HashMask is zero, use ActivePcr setting + // + PcdSet32S (PcdTpm2HashMask, TpmActivePcrBanks); + Tpm2PcrMask = TpmActivePcrBanks; + } + + // + // Find the intersection of Pcd support and TPM support. + // If banks are missing from the TPM support that are in the PCD, update the PCD. + // If banks are missing from the PCD that are active in the TPM, reallocate the banks and reboot. + // + + // + // If there are active PCR banks that are not supported by the Platform mask, + // update the TPM allocations and reboot the machine. + // + if ((TpmActivePcrBanks & Tpm2PcrMask) != TpmActivePcrBanks) { + NewTpmActivePcrBanks = TpmActivePcrBanks & Tpm2PcrMask; + + DEBUG ((EFI_D_INFO, "%a - Reallocating PCR banks from 0x%X to 0x%X.\n", __FUNCTION__, TpmActivePcrBanks, NewTpmActivePcrBanks)); + if (NewTpmActivePcrBanks == 0) { + DEBUG ((EFI_D_ERROR, "%a - No viable PCRs active! Please set a less restrictive value for PcdTpm2HashMask!\n", __FUNCTION__)); + ASSERT (FALSE); + } else { + Status = Tpm2PcrAllocateBanks (NULL, (UINT32)TpmHashAlgorithmBitmap, NewTpmActivePcrBanks); + if (EFI_ERROR (Status)) { + // + // We can't do much here, but we hope that this doesn't happen. + // + DEBUG ((EFI_D_ERROR, "%a - Failed to reallocate PCRs!\n", __FUNCTION__)); + ASSERT_EFI_ERROR (Status); } + // + // Need reset system, since we just called Tpm2PcrAllocateBanks(). + // + ResetCold(); } } - Status = PcdSet32S (PcdTpm2HashMask, ActivePcrBanks); - ASSERT_EFI_ERROR (Status); + + // + // If there are any PCRs that claim support in the Platform mask that are + // not supported by the TPM, update the mask. + // + if ((Tpm2PcrMask & TpmHashAlgorithmBitmap) != Tpm2PcrMask) { + NewTpm2PcrMask = Tpm2PcrMask & TpmHashAlgorithmBitmap; + + DEBUG ((EFI_D_INFO, "%a - Updating PcdTpm2HashMask from 0x%X to 0x%X.\n", __FUNCTION__, Tpm2PcrMask, NewTpm2PcrMask)); + if (NewTpm2PcrMask == 0) { + DEBUG ((EFI_D_ERROR, "%a - No viable PCRs supported! Please set a less restrictive value for PcdTpm2HashMask!\n", __FUNCTION__)); + ASSERT (FALSE); + } + + Status = PcdSet32S (PcdTpm2HashMask, NewTpm2PcrMask); + ASSERT_EFI_ERROR (Status); + } } /** @@ -296,6 +323,10 @@ LogHashEvent ( } break; case EFI_TCG2_EVENT_LOG_FORMAT_TCG_2: + // + // Use GetDigestListSize (DigestList) in the GUID HOB DataLength calculation + // to reserve enough buffer to hold TPML_DIGEST_VALUES compact binary. + // HobData = BuildGuidHob ( &gTcgEvent2EntryHobGuid, sizeof(TcgPcrEvent2->PCRIndex) + sizeof(TcgPcrEvent2->EventType) + GetDigestListSize (DigestList) + sizeof(TcgPcrEvent2->EventSize) + NewEventHdr->EventSize @@ -430,53 +461,152 @@ MeasureFvImage ( IN UINT64 FvLength ) { - UINT32 Index; - EFI_STATUS Status; - EFI_PLATFORM_FIRMWARE_BLOB FvBlob; - TCG_PCR_EVENT_HDR TcgEventHdr; + UINT32 Index; + EFI_STATUS Status; + EFI_PLATFORM_FIRMWARE_BLOB FvBlob; + TCG_PCR_EVENT_HDR TcgEventHdr; + UINT32 Instance; + UINT32 Tpm2HashMask; + TPML_DIGEST_VALUES DigestList; + UINT32 DigestCount; + EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI *MeasurementExcludedFvPpi; + EDKII_PEI_FIRMWARE_VOLUME_INFO_PREHASHED_FV_PPI *PrehashedFvPpi; + HASH_INFO *PreHashInfo; + UINT32 HashAlgoMask; // - // Check if it is in Excluded FV list + // Check Excluded FV list // - if (mMeasurementExcludedFvPpi != NULL) { - for (Index = 0; Index < mMeasurementExcludedFvPpi->Count; Index ++) { - if (mMeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase) { - DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei starts at: 0x%x\n", FvBase)); - DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei has the size: 0x%x\n", FvLength)); - return EFI_SUCCESS; + Instance = 0; + do { + Status = PeiServicesLocatePpi( + &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid, + Instance, + NULL, + (VOID**)&MeasurementExcludedFvPpi + ); + if (!EFI_ERROR(Status)) { + for (Index = 0; Index < MeasurementExcludedFvPpi->Count; Index ++) { + if (MeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase + && MeasurementExcludedFvPpi->Fv[Index].FvLength == FvLength) { + DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei starts at: 0x%x\n", FvBase)); + DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei has the size: 0x%x\n", FvLength)); + return EFI_SUCCESS; + } } + + Instance++; } - } + } while (!EFI_ERROR(Status)); // - // Check whether FV is in the measured FV list. + // Check measured FV list // for (Index = 0; Index < mMeasuredBaseFvIndex; Index ++) { - if (mMeasuredBaseFvInfo[Index].BlobBase == FvBase) { + if (mMeasuredBaseFvInfo[Index].BlobBase == FvBase && mMeasuredBaseFvInfo[Index].BlobLength == FvLength) { + DEBUG ((DEBUG_INFO, "The FV which is already measured by Tcg2Pei starts at: 0x%x\n", FvBase)); + DEBUG ((DEBUG_INFO, "The FV which is already measured by Tcg2Pei has the size: 0x%x\n", FvLength)); return EFI_SUCCESS; } } - + // - // Measure and record the FV to the TPM + // Check pre-hashed FV list // - FvBlob.BlobBase = FvBase; - FvBlob.BlobLength = FvLength; + Instance = 0; + Tpm2HashMask = PcdGet32 (PcdTpm2HashMask); + do { + Status = PeiServicesLocatePpi ( + &gEdkiiPeiFirmwareVolumeInfoPrehashedFvPpiGuid, + Instance, + NULL, + (VOID**)&PrehashedFvPpi + ); + if (!EFI_ERROR(Status) && PrehashedFvPpi->FvBase == FvBase && PrehashedFvPpi->FvLength == FvLength) { + ZeroMem (&DigestList, sizeof(TPML_DIGEST_VALUES)); + + // + // The FV is prehashed, check against TPM hash mask + // + PreHashInfo = (HASH_INFO *)(PrehashedFvPpi + 1); + for (Index = 0, DigestCount = 0; Index < PrehashedFvPpi->Count; Index++) { + DEBUG((DEBUG_INFO, "Hash Algo ID in PrehashedFvPpi=0x%x\n", PreHashInfo->HashAlgoId)); + HashAlgoMask = GetHashMaskFromAlgo(PreHashInfo->HashAlgoId); + if ((Tpm2HashMask & HashAlgoMask) != 0 ) { + // + // Hash is required, copy it to DigestList + // + WriteUnaligned16(&(DigestList.digests[DigestCount].hashAlg), PreHashInfo->HashAlgoId); + CopyMem ( + &DigestList.digests[DigestCount].digest, + PreHashInfo + 1, + PreHashInfo->HashSize + ); + DigestCount++; + // + // Clean the corresponding Hash Algo mask bit + // + Tpm2HashMask &= ~HashAlgoMask; + } + PreHashInfo = (HASH_INFO *)((UINT8 *)(PreHashInfo + 1) + PreHashInfo->HashSize); + } - DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei starts at: 0x%x\n", FvBlob.BlobBase)); - DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei has the size: 0x%x\n", FvBlob.BlobLength)); + WriteUnaligned32(&DigestList.count, DigestCount); - TcgEventHdr.PCRIndex = 0; + break; + } + Instance++; + } while (!EFI_ERROR(Status)); + + // + // Init the log event for FV measurement + // + FvBlob.BlobBase = FvBase; + FvBlob.BlobLength = FvLength; + TcgEventHdr.PCRIndex = 0; TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB; TcgEventHdr.EventSize = sizeof (FvBlob); - Status = HashLogExtendEvent ( - 0, - (UINT8*) (UINTN) FvBlob.BlobBase, - (UINTN) FvBlob.BlobLength, - &TcgEventHdr, - (UINT8*) &FvBlob - ); + if (Tpm2HashMask == 0) { + // + // FV pre-hash algos comply with current TPM hash requirement + // Skip hashing step in measure, only extend DigestList to PCR and log event + // + Status = Tpm2PcrExtend( + 0, + &DigestList + ); + + if (!EFI_ERROR(Status)) { + Status = LogHashEvent (&DigestList, &TcgEventHdr, (UINT8*) &FvBlob); + DEBUG ((DEBUG_INFO, "The pre-hashed FV which is extended & logged by Tcg2Pei starts at: 0x%x\n", FvBlob.BlobBase)); + DEBUG ((DEBUG_INFO, "The pre-hashed FV which is extended & logged by Tcg2Pei has the size: 0x%x\n", FvBlob.BlobLength)); + } else if (Status == EFI_DEVICE_ERROR) { + BuildGuidHob (&gTpmErrorHobGuid,0); + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR) + ); + } + } else { + // + // Hash the FV, extend digest to the TPM and log TCG event + // + Status = HashLogExtendEvent ( + 0, + (UINT8*) (UINTN) FvBlob.BlobBase, + (UINTN) FvBlob.BlobLength, + &TcgEventHdr, + (UINT8*) &FvBlob + ); + DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei starts at: 0x%x\n", FvBlob.BlobBase)); + DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei has the size: 0x%x\n", FvBlob.BlobLength)); + } + + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "The FV which failed to be measured starts at: 0x%x\n", FvBase)); + return Status; + } // // Add new FV into the measured FV list. @@ -505,47 +635,44 @@ MeasureMainBios ( ) { EFI_STATUS Status; - UINT32 FvInstances; EFI_PEI_FV_HANDLE VolumeHandle; EFI_FV_INFO VolumeInfo; EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi; PERF_START_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI); - FvInstances = 0; - while (TRUE) { - // - // Traverse all firmware volume instances of Static Core Root of Trust for Measurement - // (S-CRTM), this firmware volume measure policy can be modified/enhanced by special - // platform for special CRTM TPM measuring. - // - Status = PeiServicesFfsFindNextVolume (FvInstances, &VolumeHandle); - if (EFI_ERROR (Status)) { - break; - } - - // - // Measure and record the firmware volume that is dispatched by PeiCore - // - Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo); - ASSERT_EFI_ERROR (Status); - // - // Locate the corresponding FV_PPI according to founded FV's format guid - // - Status = PeiServicesLocatePpi ( - &VolumeInfo.FvFormat, - 0, - NULL, - (VOID**)&FvPpi - ); - if (!EFI_ERROR (Status)) { - MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize); - } - FvInstances++; - } + // + // Only measure BFV at the very beginning. Other parts of Static Core Root of + // Trust for Measurement(S-CRTM) will be measured later on FvInfoNotify. + // BFV is processed without installing FV Info Ppi. Other FVs either inside BFV or + // reported by platform will be installed with Fv Info Ppi + // This firmware volume measure policy can be modified/enhanced by special + // platform for special CRTM TPM measuring. + // + Status = PeiServicesFfsFindNextVolume (0, &VolumeHandle); + ASSERT_EFI_ERROR (Status); + + // + // Measure and record the firmware volume that is dispatched by PeiCore + // + Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo); + ASSERT_EFI_ERROR (Status); + // + // Locate the corresponding FV_PPI according to founded FV's format guid + // + Status = PeiServicesLocatePpi ( + &VolumeInfo.FvFormat, + 0, + NULL, + (VOID**)&FvPpi + ); + ASSERT_EFI_ERROR (Status); + + Status = MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize); + PERF_END_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI + 1); - return EFI_SUCCESS; + return Status; } /** @@ -630,14 +757,6 @@ PeimEntryMP ( { EFI_STATUS Status; - Status = PeiServicesLocatePpi ( - &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid, - 0, - NULL, - (VOID**)&mMeasurementExcludedFvPpi - ); - // Do not check status, because it is optional - mMeasuredBaseFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported)); ASSERT (mMeasuredBaseFvInfo != NULL); mMeasuredChildFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported)); @@ -648,6 +767,9 @@ PeimEntryMP ( } Status = MeasureMainBios (); + if (EFI_ERROR(Status)) { + return Status; + } // // Post callbacks: @@ -711,7 +833,7 @@ PeimEntryMA ( if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid) || CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){ - DEBUG ((EFI_D_ERROR, "No TPM2 instance required!\n")); + DEBUG ((DEBUG_INFO, "No TPM2 instance required!\n")); return EFI_UNSUPPORTED; } @@ -767,7 +889,7 @@ PeimEntryMA ( // // Update Tpm2HashMask according to PCR bank. // - SetTpm2HashMask (); + SyncPcrAllocationsAndPcrMask (); if (S3ErrorReport) { //