123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424 |
- /** @file
- This driver verifies and reports OBB FVs.
- Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "FvReportPei.h"
- STATIC CONST HASH_ALG_INFO mHashAlgInfo[] = {
- {TPM_ALG_SHA256, SHA256_DIGEST_SIZE, Sha256Init, Sha256Update, Sha256Final, Sha256HashAll}, // 000B
- {TPM_ALG_SHA384, SHA384_DIGEST_SIZE, Sha384Init, Sha384Update, Sha384Final, Sha384HashAll}, // 000C
- {TPM_ALG_SHA512, SHA512_DIGEST_SIZE, Sha512Init, Sha512Update, Sha512Final, Sha512HashAll}, // 000D
- };
- /**
- Find hash algorithm information from mHashAlgInfo according to given ID.
- @param[in] HashAlgId Hash algorithm type id.
- @retval Pointer to HASH_ALG_INFO if given hash algorithm is supported.
- @retval NULL if given algorithm is not supported.
- **/
- STATIC
- CONST
- HASH_ALG_INFO *
- FindHashAlgInfo (
- IN UINT16 HashAlgId
- )
- {
- UINTN Index;
- for (Index = 0; Index < ARRAY_SIZE (mHashAlgInfo); ++Index) {
- if (mHashAlgInfo[Index].HashAlgId == HashAlgId) {
- return &mHashAlgInfo[Index];
- }
- }
- return NULL;
- }
- /**
- Install a EDKII_PEI_FIRMWARE_VOLUME_INFO_PREHASHED_FV_PPI instance so that
- TCG driver may use to extend PCRs.
- @param[in] FvBuffer Buffer containing the whole FV.
- @param[in] FvLength Length of the FV.
- @param[in] HashAlgoId Hash algorithm type id.
- @param[in] HashSize Hash size.
- @param[in] HashValue Hash value buffer.
- **/
- STATIC
- VOID
- InstallPreHashFvPpi (
- IN VOID *FvBuffer,
- IN UINTN FvLength,
- IN UINT16 HashAlgoId,
- IN UINT16 HashSize,
- IN UINT8 *HashValue
- )
- {
- EFI_STATUS Status;
- EFI_PEI_PPI_DESCRIPTOR *FvInfoPpiDescriptor;
- EDKII_PEI_FIRMWARE_VOLUME_INFO_PREHASHED_FV_PPI *PreHashedFvPpi;
- UINTN PpiSize;
- HASH_INFO *HashInfo;
- PpiSize = sizeof (EDKII_PEI_FIRMWARE_VOLUME_INFO_PREHASHED_FV_PPI)
- + sizeof (sizeof (HASH_INFO))
- + HashSize;
- PreHashedFvPpi = AllocatePool (PpiSize);
- ASSERT (PreHashedFvPpi != NULL);
- PreHashedFvPpi->FvBase = (UINT32)(UINTN)FvBuffer;
- PreHashedFvPpi->FvLength = (UINT32)FvLength;
- PreHashedFvPpi->Count = 1;
- HashInfo = HASH_INFO_PTR (PreHashedFvPpi);
- HashInfo->HashAlgoId = HashAlgoId;
- HashInfo->HashSize = HashSize;
- CopyMem (HASH_VALUE_PTR (HashInfo), HashValue, HashSize);
- FvInfoPpiDescriptor = AllocatePool (sizeof (EFI_PEI_PPI_DESCRIPTOR));
- ASSERT (FvInfoPpiDescriptor != NULL);
- FvInfoPpiDescriptor->Guid = &gEdkiiPeiFirmwareVolumeInfoPrehashedFvPpiGuid;
- FvInfoPpiDescriptor->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;
- FvInfoPpiDescriptor->Ppi = (VOID *) PreHashedFvPpi;
- Status = PeiServicesInstallPpi (FvInfoPpiDescriptor);
- ASSERT_EFI_ERROR (Status);
- }
- /**
- Calculate and verify hash value for given FV.
- @param[in] HashInfo Hash information of the FV.
- @param[in] FvInfo Information of FV used for verification.
- @param[in] FvNumber Length of the FV.
- @param[in] BootMode Length of the FV.
- @retval EFI_SUCCESS The given FV is integrate.
- @retval EFI_VOLUME_CORRUPTED The given FV is corrupted (hash mismatch).
- @retval EFI_UNSUPPORTED The hash algorithm is not supported.
- **/
- STATIC
- EFI_STATUS
- VerifyHashedFv (
- IN FV_HASH_INFO *HashInfo,
- IN HASHED_FV_INFO *FvInfo,
- IN UINTN FvNumber,
- IN EFI_BOOT_MODE BootMode
- )
- {
- UINTN FvIndex;
- CONST HASH_ALG_INFO *AlgInfo;
- UINT8 *HashValue;
- UINT8 *FvHashValue;
- VOID *FvBuffer;
- EFI_STATUS Status;
- if (HashInfo == NULL ||
- HashInfo->HashSize == 0 ||
- HashInfo->HashAlgoId == TPM_ALG_NULL) {
- DEBUG ((DEBUG_INFO, "Bypass FV hash verification\r\n"));
- return EFI_SUCCESS;
- }
- AlgInfo = FindHashAlgInfo (HashInfo->HashAlgoId);
- if (AlgInfo == NULL || AlgInfo->HashSize != HashInfo->HashSize) {
- DEBUG ((DEBUG_ERROR, "Unsupported or wrong hash algorithm: %04X (size=%d)\r\n",
- HashInfo->HashAlgoId, HashInfo->HashSize));
- return EFI_UNSUPPORTED;
- }
- ASSERT (FvInfo != NULL);
- ASSERT (FvNumber > 0);
- //
- // We need a hash value for each FV as well as one for all FVs.
- //
- HashValue = AllocateZeroPool (AlgInfo->HashSize * (FvNumber + 1));
- ASSERT (HashValue != NULL);
- //
- // Calculate hash value for each FV first.
- //
- FvHashValue = HashValue;
- for (FvIndex = 0; FvIndex < FvNumber; ++FvIndex) {
- //
- // FV must be meant for verified boot and/or measured boot.
- //
- ASSERT ((FvInfo[FvIndex].Flag & HASHED_FV_FLAG_VERIFIED_BOOT) != 0 ||
- (FvInfo[FvIndex].Flag & HASHED_FV_FLAG_MEASURED_BOOT) != 0);
- //
- // Skip any FV not meant for current boot mode.
- //
- if ((FvInfo[FvIndex].Flag & HASHED_FV_FLAG_SKIP_BOOT_MODE (BootMode)) != 0) {
- DEBUG ((DEBUG_INFO, "Skip FV[%016lX] for boot mode[%d]\r\n",
- FvInfo[FvIndex].Base, BootMode));
- continue;
- }
- DEBUG ((
- DEBUG_INFO,
- "Pre-hashed[alg=%04X,size=%d,flag=%016lX] FV: 0x%016lX (%08lX) (Flag=%016lX)\r\n",
- HashInfo->HashAlgoId,
- HashInfo->HashSize,
- HashInfo->HashFlag,
- FvInfo[FvIndex].Base,
- FvInfo[FvIndex].Length,
- FvInfo[FvIndex].Flag
- ));
- //
- // Copy FV to permanent memory to avoid potential TOC/TOU.
- //
- FvBuffer = AllocatePages (EFI_SIZE_TO_PAGES((UINTN)FvInfo[FvIndex].Length));
- ASSERT (FvBuffer != NULL);
- CopyMem (FvBuffer, (CONST VOID *)(UINTN)FvInfo[FvIndex].Base, (UINTN)FvInfo[FvIndex].Length);
- if (!AlgInfo->HashAll (FvBuffer, (UINTN)FvInfo[FvIndex].Length, FvHashValue)) {
- Status = EFI_ABORTED;
- goto Done;
- }
- //
- // Report the FV measurement.
- //
- if ((FvInfo[FvIndex].Flag & HASHED_FV_FLAG_MEASURED_BOOT) != 0) {
- InstallPreHashFvPpi (
- FvBuffer,
- (UINTN)FvInfo[FvIndex].Length,
- HashInfo->HashAlgoId,
- HashInfo->HashSize,
- FvHashValue
- );
- }
- //
- // Don't keep the hash value of current FV if we don't need to verify it.
- //
- if ((FvInfo[FvIndex].Flag & HASHED_FV_FLAG_VERIFIED_BOOT) != 0) {
- FvHashValue += AlgInfo->HashSize;
- }
- //
- // Use memory copy of the FV from now on.
- //
- FvInfo[FvIndex].Base = (UINT64)(UINTN)FvBuffer;
- }
- //
- // Check final hash for all FVs.
- //
- if (FvHashValue == HashValue ||
- (AlgInfo->HashAll (HashValue, FvHashValue - HashValue, FvHashValue) &&
- CompareMem (HashInfo->Hash, FvHashValue, AlgInfo->HashSize) == 0)) {
- Status = EFI_SUCCESS;
- } else {
- Status = EFI_VOLUME_CORRUPTED;
- }
- Done:
- FreePool (HashValue);
- return Status;
- }
- /**
- Report FV to PEI and/or DXE core for dispatch.
- @param[in] FvInfo Information of a FV.
- **/
- STATIC
- VOID
- ReportHashedFv (
- IN HASHED_FV_INFO *FvInfo
- )
- {
- CONST EFI_GUID *FvFormat;
- if ((FvInfo->Flag & HASHED_FV_FLAG_REPORT_FV_HOB) != 0) {
- //
- // Require DXE core to process this FV.
- //
- BuildFvHob (
- (EFI_PHYSICAL_ADDRESS)FvInfo->Base,
- FvInfo->Length
- );
- DEBUG ((DEBUG_INFO, "Reported FV HOB: %016lX (%08lX)\r\n", FvInfo->Base, FvInfo->Length));
- }
- if ((FvInfo->Flag & HASHED_FV_FLAG_REPORT_FV_INFO_PPI) != 0) {
- //
- // Require PEI core to process this FV.
- //
- FvFormat = &((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvInfo->Base)->FileSystemGuid;
- PeiServicesInstallFvInfoPpi (
- FvFormat,
- (VOID *)(UINTN)FvInfo->Base,
- (UINT32)FvInfo->Length,
- NULL,
- NULL
- );
- DEBUG ((DEBUG_INFO, "Reported FV PPI: %016lX (%08lX)\r\n", FvInfo->Base, FvInfo->Length));
- }
- }
- /**
- Verify and report pre-hashed FVs.
- Doing this must be at post-memory to make sure there's enough memory to hold
- all FVs to be verified. This is necessary for mitigating TOCTOU issue.
- This function will never return if the verification is failed.
- @param[in] StoredHashFvPpi Pointer to PPI containing hash information.
- @param[in] BootMode Current boot mode.
- @retval Pointer to structure containing valid hash information for current boot mode.
- @retval NULL if there's no hash associated with current boot mode.
- **/
- STATIC
- FV_HASH_INFO *
- GetHashInfo (
- IN EDKII_PEI_FIRMWARE_VOLUME_INFO_STORED_HASH_FV_PPI *StoredHashFvPpi,
- IN EFI_BOOT_MODE BootMode
- )
- {
- FV_HASH_INFO *HashInfo;
- if ((StoredHashFvPpi->HashInfo.HashFlag & FV_HASH_FLAG_BOOT_MODE (BootMode)) != 0) {
- HashInfo = &StoredHashFvPpi->HashInfo;
- } else {
- HashInfo = NULL;
- }
- return HashInfo;
- }
- /**
- Verify and report pre-hashed FVs.
- Doing this must be at post-memory to make sure there's enough memory to hold
- all FVs to be verified. This is necessary for mitigating TOCTOU issue.
- This function will never return if the verification is failed.
- @param[in] PeiServices General purpose services available to every PEIM.
- @param[in] BootMode Current boot mode.
- @retval EFI_SUCCESS The function completed successfully.
- **/
- STATIC
- EFI_STATUS
- CheckStoredHashFv (
- IN CONST EFI_PEI_SERVICES **PeiServices,
- IN EFI_BOOT_MODE BootMode
- )
- {
- EFI_STATUS Status;
- EDKII_PEI_FIRMWARE_VOLUME_INFO_STORED_HASH_FV_PPI *StoredHashFvPpi;
- FV_HASH_INFO *HashInfo;
- UINTN FvIndex;
- //
- // Check pre-hashed FV list
- //
- StoredHashFvPpi = NULL;
- Status = PeiServicesLocatePpi (
- &gEdkiiPeiFirmwareVolumeInfoStoredHashFvPpiGuid,
- 0,
- NULL,
- (VOID**)&StoredHashFvPpi
- );
- if (!EFI_ERROR(Status) && StoredHashFvPpi != NULL && StoredHashFvPpi->FvNumber > 0) {
- HashInfo = GetHashInfo (StoredHashFvPpi, BootMode);
- Status = VerifyHashedFv (HashInfo, StoredHashFvPpi->FvInfo,
- StoredHashFvPpi->FvNumber, BootMode);
- if (!EFI_ERROR (Status)) {
- //
- // Report the FVs to PEI core and/or DXE core.
- //
- for (FvIndex = 0; FvIndex < StoredHashFvPpi->FvNumber; ++FvIndex) {
- if ((StoredHashFvPpi->FvInfo[FvIndex].Flag
- & HASHED_FV_FLAG_SKIP_BOOT_MODE (BootMode)) == 0) {
- ReportHashedFv (&StoredHashFvPpi->FvInfo[FvIndex]);
- }
- }
- REPORT_STATUS_CODE (
- EFI_PROGRESS_CODE,
- PcdGet32 (PcdStatusCodeFvVerificationPass)
- );
- } else {
- DEBUG ((DEBUG_ERROR, "ERROR: Failed to verify OBB FVs (%r)\r\n", Status));
- REPORT_STATUS_CODE_EX (
- EFI_PROGRESS_CODE,
- PcdGet32 (PcdStatusCodeFvVerificationFail),
- 0,
- NULL,
- &gEdkiiPeiFirmwareVolumeInfoStoredHashFvPpiGuid,
- StoredHashFvPpi,
- sizeof (*StoredHashFvPpi)
- );
- ASSERT_EFI_ERROR (Status);
- }
- } else {
- DEBUG ((DEBUG_ERROR, "ERROR: No/invalid StoredHashFvPpi located\r\n"));
- ASSERT_EFI_ERROR (Status);
- ASSERT (StoredHashFvPpi != NULL && StoredHashFvPpi->FvNumber > 0);
- Status = EFI_NOT_FOUND;
- }
- return Status;
- }
- /**
- Main entry for FvReport PEIM.
- @param[in] FileHandle Handle of the file being invoked.
- @param[in] PeiServices Pointer to PEI Services table.
- @retval EFI_SUCCESS If all FVs reported by StoredHashFvPpi are verified.
- **/
- EFI_STATUS
- EFIAPI
- FvReportEntryPoint (
- IN EFI_PEI_FILE_HANDLE FileHandle,
- IN CONST EFI_PEI_SERVICES **PeiServices
- )
- {
- EFI_STATUS Status;
- EFI_BOOT_MODE BootMode;
- Status = PeiServicesGetBootMode (&BootMode);
- ASSERT_EFI_ERROR (Status);
- Status = CheckStoredHashFv (PeiServices, BootMode);
- if (EFI_ERROR (Status)) {
- //
- // Never pass control to left part of BIOS if any error.
- //
- CpuDeadLoop ();
- }
- return Status;
- }
|