SecurityPkg\Tcg2Pei: FV measure performance enhancement

1. Leverage Pre-Hashed FV PPI to reduce duplicated hash
2. Only measure BFV at the beginning. Other FVs are measured in FVinfo callback with nested
   FV check. https://bugzilla.tianocore.org/show_bug.cgi?id=662

Cc: Long Qin <qin.long@intel.com>
Cc: Yao Jiewen <jiewen.yao@intel.com>
Cc: Sean Brogan <sean.brogan@microsoft.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Chao Zhang <chao.b.zhang@intel.com>
Reviewed-by: Long Qin <qin.long@intel.com>
Reviewed-by: Yao Jiewen <jiewen.yao@intel.com>
This commit is contained in:
Zhang, Chao B 2017-07-27 14:22:00 +08:00
parent 53c6ff1803
commit d7c054f985
4 changed files with 253 additions and 73 deletions

View File

@ -0,0 +1,74 @@
/** @file
PPI to describe all hash digests for a given FV
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
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
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
/**
PPI to describe all hash digests for a given FV
Copyright (c) 2017, Microsoft Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**/
#ifndef __PEI_FIRMWARE_VOLUME_INFO_PREHASHED_FV_H__
#define __PEI_FIRMWARE_VOLUME_INFO_PREHASHED_FV_H__
#define EDKII_PEI_FIRMWARE_VOLUME_INFO_PREHASHED_FV_PPI_GUID \
{ 0x3ce1e631, 0x7008, 0x477c, { 0xad, 0xa7, 0x5d, 0xcf, 0xc7, 0xc1, 0x49, 0x4b } }
//
// HashAlgoId is TPM_ALG_ID in Tpm20.h
//
typedef struct _HASH_INFO {
UINT16 HashAlgoId;
UINT16 HashSize;
//UINT8 Hash[];
} HASH_INFO;
//
// This PPI carries prehashsed data for one FV. Platform should ensure 1:1 mapping between pre-hashed PPI and corresponding FV.
// The Count field in PPI is followed by Count number of FV hash info entries, which can be extended to PCR and logged to TCG event log directly by TCG modules.
// TCG module checks TPM required hash algorithms(PcdTpm2HashMask) with each pre-hased PPIs
// For each pre-hashed PPI
// If PPI carries hash generated by equivalent or larger algorithm set than TPM required, directly use PPI
// else, drops PPI data and cacluate all hash again
//
typedef struct {
UINT32 FvBase;
UINT32 FvLength;
UINT32 Count;
//HASH_INFO HashInfo[];
} EDKII_PEI_FIRMWARE_VOLUME_INFO_PREHASHED_FV_PPI;
extern EFI_GUID gEdkiiPeiFirmwareVolumeInfoPrehashedFvPpiGuid;
#endif

View File

@ -7,6 +7,7 @@
#
# Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
# (C) Copyright 2015 Hewlett Packard Enterprise Development LP <BR>
# Copyright (c) 2017, Microsoft Corporation. All rights reserved. <BR>
# 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
@ -222,6 +223,9 @@
## Include/Ppi/FirmwareVolumeInfoMeasurementExcluded.h
gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid = { 0x6e056ff9, 0xc695, 0x4364, { 0x9e, 0x2c, 0x61, 0x26, 0xf5, 0xce, 0xea, 0xae } }
## Include/Ppi/FirmwareVolumeInfoPrehashedFV.h
gEdkiiPeiFirmwareVolumeInfoPrehashedFvPpiGuid = { 0x3ce1e631, 0x7008, 0x477c, { 0xad, 0xa7, 0x5d, 0xcf, 0xc7, 0xc1, 0x49, 0x4b } }
#
# [Error.gEfiSecurityPkgTokenSpaceGuid]
# 0x80000001 | Invalid value provided.
@ -448,9 +452,10 @@
[PcdsDynamic, PcdsDynamicEx]
## This PCD indicates Hash mask for TPM 2.0.<BR><BR>
## This PCD indicates Hash mask for TPM 2.0. Bit definition strictly follows TCG Algorithm Registry.<BR><BR>
# If this bit is set, that means this algorithm is needed to extend to PCR.<BR>
# If this bit is clear, that means this algorithm is NOT needed to extend to PCR.<BR>
# If all the bits are clear, that means hash algorithm is determined by current Active PCR Banks.<BR>
# BIT0 - SHA1.<BR>
# BIT1 - SHA256.<BR>
# BIT2 - SHA384.<BR>

View File

@ -2,6 +2,7 @@
Initialize TPM2 device and measure FVs before handing off control to DXE.
Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2017, Microsoft Corporation. All rights reserved. <BR>
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
@ -22,6 +23,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Ppi/FirmwareVolume.h>
#include <Ppi/EndOfPeiPhase.h>
#include <Ppi/FirmwareVolumeInfoMeasurementExcluded.h>
#include <Ppi/FirmwareVolumeInfoPrehashedFV.h>
#include <Guid/TcgEventHob.h>
#include <Guid/MeasuredFvHob.h>
@ -133,7 +135,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
@ -215,6 +216,13 @@ SyncPcrAllocationsAndPcrMask (
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.
@ -459,42 +467,133 @@ MeasureFvImage (
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) {
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
//
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);
}
WriteUnaligned32(&DigestList.count, DigestCount);
break;
}
Instance++;
} while (!EFI_ERROR(Status));
//
// Init the log event for FV measurement
//
FvBlob.BlobBase = FvBase;
FvBlob.BlobLength = FvLength;
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));
TcgEventHdr.PCRIndex = 0;
TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB;
TcgEventHdr.EventSize = sizeof (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,
@ -502,6 +601,14 @@ MeasureFvImage (
&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.
@ -530,23 +637,22 @@ 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
// 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 (FvInstances, &VolumeHandle);
if (EFI_ERROR (Status)) {
break;
}
Status = PeiServicesFfsFindNextVolume (0, &VolumeHandle);
ASSERT_EFI_ERROR (Status);
//
// Measure and record the firmware volume that is dispatched by PeiCore
@ -562,15 +668,13 @@ MeasureMainBios (
NULL,
(VOID**)&FvPpi
);
if (!EFI_ERROR (Status)) {
MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize);
}
ASSERT_EFI_ERROR (Status);
Status = MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize);
FvInstances++;
}
PERF_END_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI + 1);
return EFI_SUCCESS;
return Status;
}
/**
@ -655,14 +759,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));
@ -673,6 +769,9 @@ PeimEntryMP (
}
Status = MeasureMainBios ();
if (EFI_ERROR(Status)) {
return Status;
}
//
// Post callbacks:

View File

@ -9,6 +9,7 @@
# This module will initialize TPM device, measure reported FVs and BIOS version.
#
# Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
# Copyright (c) 2017, Microsoft Corporation. All rights reserved. <BR>
# 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
@ -75,6 +76,7 @@
gPeiTpmInitializedPpiGuid ## SOMETIMES_PRODUCES
gPeiTpmInitializationDonePpiGuid ## PRODUCES
gEfiEndOfPeiSignalPpiGuid ## SOMETIMES_CONSUMES ## NOTIFY
gEdkiiPeiFirmwareVolumeInfoPrehashedFvPpiGuid ## SOMETIMES_CONSUMES
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString ## SOMETIMES_CONSUMES