diff --git a/MdePkg/Include/IndustryStandard/Tpm2Acpi.h b/MdePkg/Include/IndustryStandard/Tpm2Acpi.h index 879a6058d73..4288dba2d9e 100644 --- a/MdePkg/Include/IndustryStandard/Tpm2Acpi.h +++ b/MdePkg/Include/IndustryStandard/Tpm2Acpi.h @@ -24,19 +24,25 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #define EFI_TPM2_ACPI_TABLE_START_METHOD_SPECIFIC_PARAMETERS_MAX_SIZE_REVISION_5 16 #define EFI_TPM2_ACPI_TABLE_START_METHOD_SPECIFIC_PARAMETERS_MAX_SIZE EFI_TPM2_ACPI_TABLE_START_METHOD_SPECIFIC_PARAMETERS_MAX_SIZE_REVISION_5 -typedef struct { - EFI_ACPI_DESCRIPTION_HEADER Header; - // Flags field is replaced in version 4 and above - // BIT0~15: PlatformClass This field is only valid for version 4 and above - // BIT16~31: Reserved - UINT32 Flags; - UINT64 AddressOfControlArea; +// MU_CHANGE - [BEGIN] + +// Common fields shared across all TPM2 ACPI table revisions. +// Flags field is replaced in version 4 and above: +// BIT0~15: PlatformClass This field is only valid for version 4 and above +// BIT16~31: Reserved +// +#define EFI_TPM2_ACPI_TABLE_COMMON_FIELDS \ + EFI_ACPI_DESCRIPTION_HEADER Header; \ + UINT32 Flags; \ + UINT64 AddressOfControlArea; \ UINT32 StartMethod; - // UINT8 PlatformSpecificParameters[]; // size up to 16 - // UINT32 Laml; // Optional - // UINT64 Lasa; // Optional + +typedef struct { + EFI_TPM2_ACPI_TABLE_COMMON_FIELDS } EFI_TPM2_ACPI_TABLE; +// MU_CHANGE - [END] + #define EFI_TPM2_ACPI_TABLE_START_METHOD_ACPI 2 #define EFI_TPM2_ACPI_TABLE_START_METHOD_TIS 6 #define EFI_TPM2_ACPI_TABLE_START_METHOD_COMMAND_RESPONSE_BUFFER_INTERFACE 7 @@ -64,7 +70,8 @@ typedef struct { UINT32 Interrupt; UINT8 Flags; UINT8 OperationFlags; - UINT8 Reserved[2]; + UINT8 Attributes; // MU_CHANGE + UINT8 Reserved; // MU_CHANGE UINT32 SmcFunctionId; } EFI_TPM2_ACPI_START_METHOD_SPECIFIC_PARAMETERS_ARM_SMC; @@ -80,6 +87,48 @@ typedef struct { UINT8 Reserved[8]; } EFI_TPM2_ACPI_START_METHOD_SPECIFIC_PARAMETERS_ARM_FFA; +// MU_CHANGE - [BEGIN] + +typedef struct { + EFI_TPM2_ACPI_TABLE_COMMON_FIELDS + + // StartMethodSpecificParameters is variable in size and LAML/LASA are + // optional fields. It is the user's responsibility to access the + // Header.Length field to determine what is accessible in the table. + union { + UINT8 PlatformSpecificParameters[EFI_TPM2_ACPI_TABLE_START_METHOD_SPECIFIC_PARAMETERS_MAX_SIZE_REVISION_4]; + EFI_TPM2_ACPI_START_METHOD_SPECIFIC_PARAMETERS_ARM_SMC SmcParameters; + } StartMethodSpecificParameters; + + UINT32 Laml; // Optional + UINT64 Lasa; // Optional +} EFI_TPM2_ACPI_TABLE_V4; + +typedef struct { + EFI_TPM2_ACPI_TABLE_COMMON_FIELDS + + // StartMethodSpecificParameters is variable in size and LAML/LASA are + // optional fields. It is the user's responsibility to access the + // Header.Length field to determine what is accessible in the table. + union { + UINT8 PlatformSpecificParameters[EFI_TPM2_ACPI_TABLE_START_METHOD_SPECIFIC_PARAMETERS_MAX_SIZE_REVISION_5]; + EFI_TPM2_ACPI_START_METHOD_SPECIFIC_PARAMETERS_ARM_SMC SmcParameters; + EFI_TPM2_ACPI_START_METHOD_SPECIFIC_PARAMETERS_ARM_FFA FfaParameters; + } StartMethodSpecificParameters; + + UINT32 Laml; // Optional + UINT64 Lasa; // Optional +} EFI_TPM2_ACPI_TABLE_V5; + +typedef struct { + EFI_TPM2_ACPI_TABLE_COMMON_FIELDS + UINT8 PlatformSpecificParameters[EFI_TPM2_ACPI_TABLE_START_METHOD_SPECIFIC_PARAMETERS_MAX_SIZE]; + UINT32 Laml; // Optional + UINT64 Lasa; // Optional +} EFI_TPM2_ACPI_TABLE_TEMPLATE; + +// MU_CHANGE - [END] + #define EFI_TPM2_ACPI_TABLE_ARM_FFA_PARAMETER_FLAG_NOTIFICATION_SUPPORT BIT0 #define EFI_TPM2_ACPI_TABLE_ARM_FFA_PARAMETER_ATTR_MEM_TYPE_MASK 0x3 diff --git a/SecurityPkg/Include/Guid/Tcg2EventLogScaled.h b/SecurityPkg/Include/Guid/Tcg2EventLogScaled.h new file mode 100644 index 00000000000..1b3fb81cbf6 --- /dev/null +++ b/SecurityPkg/Include/Guid/Tcg2EventLogScaled.h @@ -0,0 +1,20 @@ +/** @file + Defines the GUID used to signal that the TCG event log has been dynamically + scaled. Consumers may register a notification callback on this event group + to react to the scaling event. + + Copyright (c), Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef TCG2_EVENT_LOG_SCALED_H_ +#define TCG2_EVENT_LOG_SCALED_H_ + +#define TCG2_EVENT_LOG_SCALED_GUID \ + { \ + 0x9b4f7c2a, 0x1d3e, 0x4a8b, { 0x9c, 0x6f, 0x5e, 0x8d, 0x2a, 0x1b, 0x4c, 0x7f } \ + } + +extern EFI_GUID gTcg2EventLogScaledGuid; + +#endif // TCG2_EVENT_LOG_SCALED_H_ diff --git a/SecurityPkg/SecurityPkg.dec b/SecurityPkg/SecurityPkg.dec index 70d70da0e7e..249187a5c01 100644 --- a/SecurityPkg/SecurityPkg.dec +++ b/SecurityPkg/SecurityPkg.dec @@ -202,6 +202,11 @@ ## Include/Guid/TcgEventHob.h gTcg800155PlatformIdEventHobGuid = { 0xe2c3bc69, 0x615c, 0x4b5b, { 0x8e, 0x5c, 0xa0, 0x33, 0xa9, 0xc2, 0x5e, 0xd6 }} + ## MU_CHANGE + ## GUID used to signal dynamic scaling of the TCG event log. + ## Include/Guid/Tcg2EventLogScaled.h + gTcg2EventLogScaledGuid = { 0x9b4f7c2a, 0x1d3e, 0x4a8b, { 0x9c, 0x6f, 0x5e, 0x8d, 0x2a, 0x1b, 0x4c, 0x7f }} + ## HOB GUID used to pass all PEI measured FV info to DXE Driver. # Include/Guid/MeasuredFvHob.h gMeasuredFvHobGuid = { 0xb2360b42, 0x7173, 0x420a, { 0x86, 0x96, 0x46, 0xca, 0x6b, 0xab, 0x10, 0x60 }} @@ -301,6 +306,14 @@ # Include/Protocol/MuTcg2Protocol.h gMuTcg2ProtocolExGuid = {0x227e7984, 0x1a77, 0x4762, { 0x96, 0x69, 0x57, 0x4c, 0xda, 0xd1, 0xa0, 0x1e }} ## MU_CHANGE - END - Add a new protocol to support Log-only events. + + ## MU_CHANGE - [BEGIN] + ## Protocol used to test dynamic TCG log scaling functionality. This is a private protocol with visibility to + ## only the TestApp and DXE driver. + # Tcg/TcgLogTest/TcgLogTest.h + gTcgLogTestProtocolGuid = {0xa3c12f80, 0x7d9e, 0x4b5a, { 0x91, 0xe4, 0x6c, 0xf8, 0x2d, 0xa1, 0xb7, 0x03 }} + ## MU_CHANGE - [END] + [Ppis] ## The PPI GUID for that TPM physical presence should be locked. # Include/Ppi/LockPhysicalPresence.h diff --git a/SecurityPkg/SecurityPkg.dsc b/SecurityPkg/SecurityPkg.dsc index 82dd0be714c..9029fa7a821 100644 --- a/SecurityPkg/SecurityPkg.dsc +++ b/SecurityPkg/SecurityPkg.dsc @@ -249,6 +249,16 @@ SecurityPkg/Applications/TpmShellApp/TpmShellApp.inf ## MU_CHANGE + ## MU_CHANGE - [BEGIN] + SecurityPkg/Tcg/TcgLogTest/TcgLogTestDxe.inf + SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.inf { + + UnitTestLib|UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf + UnitTestPersistenceLib|UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.inf + UnitTestResultReportLib|UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.inf + } + ## MU_CHANGE - [END] + # # TCG Storage. # diff --git a/SecurityPkg/Tcg/Tcg2Acpi/Tcg2Acpi.c b/SecurityPkg/Tcg/Tcg2Acpi/Tcg2Acpi.c index 87bd22cc93a..87e9c0d2027 100644 --- a/SecurityPkg/Tcg/Tcg2Acpi/Tcg2Acpi.c +++ b/SecurityPkg/Tcg/Tcg2Acpi/Tcg2Acpi.c @@ -74,7 +74,11 @@ SPDX-License-Identifier: BSD-2-Clause-Patent // #define MAX_PRS_INT_BUF_SIZE (15*4) -#pragma pack(1) +// MU_CHANGE - [BEGIN] + +#if 0 + + #pragma pack(1) typedef struct { EFI_ACPI_DESCRIPTION_HEADER Header; @@ -89,23 +93,13 @@ typedef struct { UINT64 Lasa; // Optional } EFI_TPM2_ACPI_TABLE_V4; -#pragma pack() + #pragma pack() -EFI_TPM2_ACPI_TABLE_V4 mTpm2AcpiTemplate = { - { - EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE, - sizeof (mTpm2AcpiTemplate), - EFI_TPM2_ACPI_TABLE_REVISION, - // - // Compiler initializes the remaining bytes to 0 - // These fields should be filled in in production - // - }, - 0, // BIT0~15: PlatformClass - // BIT16~31: Reserved - 0, // Control Area - EFI_TPM2_ACPI_TABLE_START_METHOD_TIS, // StartMethod -}; +#endif + +EFI_TPM2_ACPI_TABLE_TEMPLATE mTpm2AcpiTemplate; + +// MU_CHANGE - [END] TCG_NVS *mTcgNvs; @@ -793,6 +787,8 @@ PublishTpm2 ( UINT64 OemTableId; EFI_TPM2_ACPI_CONTROL_AREA *ControlArea; TPM2_PTP_INTERFACE_TYPE InterfaceType; + EFI_TPM2_ACPI_TABLE_V4 *Tpm2AcpiTableV4; // MU_CHANGE + EFI_TPM2_ACPI_TABLE_V5 *Tpm2AcpiTableV5; // MU_CHANGE // // Measure to PCR[0] with event EV_POST_CODE ACPI DATA. @@ -810,13 +806,14 @@ PublishTpm2 ( EV_POSTCODE_INFO_ACPI_DATA, ACPI_DATA_LEN, &mTpm2AcpiTemplate, - mTpm2AcpiTemplate.Header.Length + sizeof (EFI_TPM2_ACPI_TABLE_TEMPLATE) ); } // MU_CHANGE [END] - mTpm2AcpiTemplate.Header.Revision = PcdGet8 (PcdTpm2AcpiTableRev); + mTpm2AcpiTemplate.Header.Signature = EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE; // MU_CHANGE + mTpm2AcpiTemplate.Header.Revision = PcdGet8 (PcdTpm2AcpiTableRev); // MU_CHANGE DEBUG ((DEBUG_INFO, "Tpm2 ACPI table revision is %d\n", mTpm2AcpiTemplate.Header.Revision)); // @@ -829,17 +826,50 @@ PublishTpm2 ( DEBUG ((DEBUG_INFO, "Tpm2 ACPI table PlatformClass is %d\n", (mTpm2AcpiTemplate.Flags & 0x0000FFFF))); } - mTpm2AcpiTemplate.Laml = PcdGet32 (PcdTpm2AcpiTableLaml); - mTpm2AcpiTemplate.Lasa = PcdGet64 (PcdTpm2AcpiTableLasa); - if ((mTpm2AcpiTemplate.Header.Revision < EFI_TPM2_ACPI_TABLE_REVISION_4) || - (mTpm2AcpiTemplate.Laml == 0) || (mTpm2AcpiTemplate.Lasa == 0)) - { - // - // If version is smaller than 4 or Laml/Lasa is not valid, rollback to original Length. - // - mTpm2AcpiTemplate.Header.Length = sizeof (EFI_TPM2_ACPI_TABLE); + // MU_CHANGE - [BEGIN] + + switch (mTpm2AcpiTemplate.Header.Revision) { + case EFI_TPM2_ACPI_TABLE_REVISION_3: + mTpm2AcpiTemplate.Header.Length = sizeof (EFI_TPM2_ACPI_TABLE); + break; + + case EFI_TPM2_ACPI_TABLE_REVISION_4: + mTpm2AcpiTemplate.Header.Length = sizeof (EFI_TPM2_ACPI_TABLE_V4); + Tpm2AcpiTableV4 = (EFI_TPM2_ACPI_TABLE_V4 *)&mTpm2AcpiTemplate; + Tpm2AcpiTableV4->Laml = PcdGet32 (PcdTpm2AcpiTableLaml); + Tpm2AcpiTableV4->Lasa = PcdGet64 (PcdTpm2AcpiTableLasa); + + if ((Tpm2AcpiTableV4->Laml == 0) || (Tpm2AcpiTableV4->Lasa == 0)) { + // Remove LAML/LASA from the length if either is 0. + mTpm2AcpiTemplate.Header.Length -= (sizeof (UINT32) + sizeof (UINT64)); + } + + break; + + case EFI_TPM2_ACPI_TABLE_REVISION_5: + mTpm2AcpiTemplate.Header.Length = sizeof (EFI_TPM2_ACPI_TABLE_V5); + Tpm2AcpiTableV5 = (EFI_TPM2_ACPI_TABLE_V5 *)&mTpm2AcpiTemplate; + Tpm2AcpiTableV5->Laml = PcdGet32 (PcdTpm2AcpiTableLaml); + Tpm2AcpiTableV5->Lasa = PcdGet64 (PcdTpm2AcpiTableLasa); + + if ((Tpm2AcpiTableV5->Laml == 0) || (Tpm2AcpiTableV5->Lasa == 0)) { + // Remove LAML/LASA from the length if either is 0. + mTpm2AcpiTemplate.Header.Length -= (sizeof (UINT32) + sizeof (UINT64)); + } + + break; + + default: + mTpm2AcpiTemplate.Header.Length = sizeof (EFI_TPM2_ACPI_TABLE_TEMPLATE); + DEBUG ((DEBUG_ERROR, "TPM2 revision get error! %d\n", mTpm2AcpiTemplate.Header.Revision)); + ASSERT (FALSE); + break; } + DEBUG ((DEBUG_INFO, "Tpm2 ACPI table size %d\n", mTpm2AcpiTemplate.Header.Length)); + + // MU_CHANGE - [END] + InterfaceType = PcdGet8 (PcdActiveTpmInterfaceType); switch (InterfaceType) { case Tpm2PtpInterfaceCrb: @@ -853,9 +883,11 @@ PublishTpm2 ( break; case Tpm2PtpInterfaceFifo: case Tpm2PtpInterfaceTis: + mTpm2AcpiTemplate.StartMethod = EFI_TPM2_ACPI_TABLE_START_METHOD_TIS; // MU_CHANGE break; default: DEBUG ((DEBUG_ERROR, "TPM2 InterfaceType get error! %d\n", InterfaceType)); + ASSERT (FALSE); // MU_CHANGE break; } diff --git a/SecurityPkg/Tcg/Tcg2AcpiFfa/Tcg2AcpiFfa.c b/SecurityPkg/Tcg/Tcg2AcpiFfa/Tcg2AcpiFfa.c index c3ae72e6225..4eebc73e9fd 100644 --- a/SecurityPkg/Tcg/Tcg2AcpiFfa/Tcg2AcpiFfa.c +++ b/SecurityPkg/Tcg/Tcg2AcpiFfa/Tcg2AcpiFfa.c @@ -66,7 +66,11 @@ SPDX-License-Identifier: BSD-2-Clause-Patent // #define MAX_PRS_INT_BUF_SIZE (15*4) -#pragma pack(1) +// MU_CHANGE - [BEGIN] + +#if 0 + + #pragma pack(1) typedef struct { EFI_ACPI_DESCRIPTION_HEADER Header; @@ -81,23 +85,13 @@ typedef struct { UINT64 Lasa; // Optional } EFI_TPM2_ACPI_TABLE_V5; -#pragma pack() + #pragma pack() -EFI_TPM2_ACPI_TABLE_V5 mTpm2AcpiTemplate = { - { - EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE, - sizeof (mTpm2AcpiTemplate), - EFI_TPM2_ACPI_TABLE_REVISION, - // - // Compiler initializes the remaining bytes to 0 - // These fields should be filled in in production - // - }, - 0, // BIT0~15: PlatformClass - // BIT16~31: Reserved - 0, // Control Area - EFI_TPM2_ACPI_TABLE_START_METHOD_TIS, // StartMethod -}; +#endif + +EFI_TPM2_ACPI_TABLE_TEMPLATE mTpm2AcpiTemplate; + +// MU_CHANGE - [END] /** Patch version string of Physical Presence interface supported by platform. The initial string tag in TPM @@ -340,7 +334,7 @@ PublishTpm2 ( UINT64 OemTableId; EFI_TPM2_ACPI_CONTROL_AREA *ControlArea; TPM2_PTP_INTERFACE_TYPE InterfaceType; - UINT64 PartitionId; + EFI_TPM2_ACPI_TABLE_V5 *Tpm2AcpiTableV5; // MU_CHANGE STATIC_ASSERT ((FixedPcdGet64 (PcdTpmMaxAddress) - FixedPcdGet64 (PcdTpmBaseAddress)) == (FixedPcdGet32 (PcdTpmCrbRegionSize) - 1), "TPM CRB region size mismatch"); @@ -350,60 +344,70 @@ PublishTpm2 ( // Otherwise, the PCR record would be different after event log update // or the PCD configuration change. // - TpmMeasureAndLogData ( - 0, - EV_POST_CODE, - EV_POSTCODE_INFO_ACPI_DATA, - ACPI_DATA_LEN, - &mTpm2AcpiTemplate, - mTpm2AcpiTemplate.Header.Length - ); + // MU_CHANGE [BEGIN] + // Allow a platform to drop TCG ACPI measurements until we have a chance to make them more + // consistent and functional. + if (!FixedPcdGetBool (PcdSkipTcgSmmAcpiMeasurements)) { + TpmMeasureAndLogData ( + 0, + EV_POST_CODE, + EV_POSTCODE_INFO_ACPI_DATA, + ACPI_DATA_LEN, + &mTpm2AcpiTemplate, + sizeof (EFI_TPM2_ACPI_TABLE_TEMPLATE) + ); + } - mTpm2AcpiTemplate.Header.Revision = PcdGet8 (PcdTpm2AcpiTableRev); + mTpm2AcpiTemplate.Header.Signature = EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE; + mTpm2AcpiTemplate.Header.Length = sizeof (EFI_TPM2_ACPI_TABLE_V5); + mTpm2AcpiTemplate.Header.Revision = PcdGet8 (PcdTpm2AcpiTableRev); DEBUG ((DEBUG_INFO, "Tpm2 ACPI table revision is %d\n", mTpm2AcpiTemplate.Header.Revision)); + // FF-A is only supported in revisions 5 and up. if (mTpm2AcpiTemplate.Header.Revision < EFI_TPM2_ACPI_TABLE_REVISION_5) { - DEBUG ((DEBUG_ERROR, "%a The minimum revision supported for TPM over FFA table is 5, not %d.\n", __func__, mTpm2AcpiTemplate.Header.Revision)); + DEBUG ((DEBUG_ERROR, "The minimum revision supported for TPM over FF-A table is 5\n")); ASSERT (FALSE); return EFI_UNSUPPORTED; } - mTpm2AcpiTemplate.Flags = (mTpm2AcpiTemplate.Flags & 0xFFFF0000) | PcdGet8 (PcdTpmPlatformClass); - DEBUG ((DEBUG_INFO, "Tpm2 ACPI table PlatformClass is %d\n", (mTpm2AcpiTemplate.Flags & 0x0000FFFF))); - - mTpm2AcpiTemplate.Laml = PcdGet32 (PcdTpm2AcpiTableLaml); - mTpm2AcpiTemplate.Lasa = PcdGet64 (PcdTpm2AcpiTableLasa); - if ((mTpm2AcpiTemplate.Laml == 0) || (mTpm2AcpiTemplate.Lasa == 0)) { - // - // If version is smaller than 4 or Laml/Lasa is not valid, rollback to original Length. - // - mTpm2AcpiTemplate.Header.Length = sizeof (EFI_TPM2_ACPI_TABLE); - } - + // CRB over FF-A only supports the CRB interface type. InterfaceType = PcdGet8 (PcdActiveTpmInterfaceType); DEBUG ((DEBUG_INFO, "Tpm Active Interface Type %d\n", InterfaceType)); - - PartitionId = PcdGet16 (PcdTpmServiceFfaPartitionId); - ASSERT (PartitionId != 0); - if (InterfaceType == Tpm2PtpInterfaceCrb) { - mTpm2AcpiTemplate.StartMethod = EFI_TPM2_ACPI_TABLE_START_METHOD_COMMAND_RESPONSE_BUFFER_INTERFACE_WITH_FFA; - mTpm2AcpiTemplate.AddressOfControlArea = PcdGet64 (PcdTpmBaseAddress) + 0x40; - mTpm2AcpiTemplate.FfaParameters.Flags = 0x00; // Notifications Not Supported - mTpm2AcpiTemplate.FfaParameters.Attributes = (EFI_TPM2_ACPI_TABLE_ARM_FFA_PARAMETER_ATTR_CRB_REGION_SIZE_4KB << EFI_TPM2_ACPI_TABLE_ARM_FFA_PARAMETER_ATTR_CRB_REGION_SIZE_SHIFT) | - (EFI_TPM2_ACPI_TABLE_ARM_FFA_PARAMETER_ATTR_MEM_TYPE_NOT_CACHABLE << EFI_TPM2_ACPI_TABLE_ARM_FFA_PARAMETER_ATTR_MEM_TYPE_SHIFT); - mTpm2AcpiTemplate.FfaParameters.PartitionId = PartitionId; // Partition ID - ControlArea = (EFI_TPM2_ACPI_CONTROL_AREA *)(UINTN)mTpm2AcpiTemplate.AddressOfControlArea; - ControlArea->CommandSize = 0xF80; - ControlArea->ResponseSize = 0xF80; - ControlArea->Command = PcdGet64 (PcdTpmBaseAddress) + 0x80; - ControlArea->Response = PcdGet64 (PcdTpmBaseAddress) + 0x80; - } else { - DEBUG ((DEBUG_ERROR, "TPM2 InterfaceType get error! %d\n", InterfaceType)); + if (InterfaceType != Tpm2PtpInterfaceCrb) { + DEBUG ((DEBUG_ERROR, "TPM over FF-A only supports CRB interface\n")); return EFI_UNSUPPORTED; } + mTpm2AcpiTemplate.Flags = (mTpm2AcpiTemplate.Flags & 0xFFFF0000) | PcdGet8 (PcdTpmPlatformClass); + DEBUG ((DEBUG_INFO, "Tpm2 ACPI table PlatformClass is %d\n", (mTpm2AcpiTemplate.Flags & 0x0000FFFF))); + + Tpm2AcpiTableV5 = (EFI_TPM2_ACPI_TABLE_V5 *)&mTpm2AcpiTemplate; + Tpm2AcpiTableV5->Laml = PcdGet32 (PcdTpm2AcpiTableLaml); + Tpm2AcpiTableV5->Lasa = PcdGet64 (PcdTpm2AcpiTableLasa); + if ((Tpm2AcpiTableV5->Laml == 0) || (Tpm2AcpiTableV5->Lasa == 0)) { + // Remove LAML/LASA from the length if either is 0. + mTpm2AcpiTemplate.Header.Length -= (sizeof (UINT32) + sizeof (UINT64)); + } + DEBUG ((DEBUG_INFO, "Tpm2 ACPI table size %d\n", mTpm2AcpiTemplate.Header.Length)); + mTpm2AcpiTemplate.StartMethod = EFI_TPM2_ACPI_TABLE_START_METHOD_COMMAND_RESPONSE_BUFFER_INTERFACE_WITH_FFA; + mTpm2AcpiTemplate.AddressOfControlArea = PcdGet64 (PcdTpmBaseAddress) + 0x40; + ControlArea = (EFI_TPM2_ACPI_CONTROL_AREA *)(UINTN)mTpm2AcpiTemplate.AddressOfControlArea; + ControlArea->CommandSize = 0xF80; + ControlArea->ResponseSize = 0xF80; + ControlArea->Command = PcdGet64 (PcdTpmBaseAddress) + 0x80; + ControlArea->Response = PcdGet64 (PcdTpmBaseAddress) + 0x80; + + // Set the FF-A specific parameters. + Tpm2AcpiTableV5->StartMethodSpecificParameters.FfaParameters.Flags = 0x00; // Notifications Not Supported + Tpm2AcpiTableV5->StartMethodSpecificParameters.FfaParameters.Attributes = (EFI_TPM2_ACPI_TABLE_ARM_FFA_PARAMETER_ATTR_CRB_REGION_SIZE_4KB << EFI_TPM2_ACPI_TABLE_ARM_FFA_PARAMETER_ATTR_CRB_REGION_SIZE_SHIFT) | + (EFI_TPM2_ACPI_TABLE_ARM_FFA_PARAMETER_ATTR_MEM_TYPE_NOT_CACHABLE << EFI_TPM2_ACPI_TABLE_ARM_FFA_PARAMETER_ATTR_MEM_TYPE_SHIFT); + Tpm2AcpiTableV5->StartMethodSpecificParameters.FfaParameters.PartitionId = PcdGet16 (PcdTpmServiceFfaPartitionId); + ASSERT (Tpm2AcpiTableV5->StartMethodSpecificParameters.FfaParameters.PartitionId != 0); + + // MU_CHANGE [END] + CopyMem (mTpm2AcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTpm2AcpiTemplate.Header.OemId)); OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId); CopyMem (&mTpm2AcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64)); diff --git a/SecurityPkg/Tcg/Tcg2AcpiFfa/Tcg2AcpiFfa.inf b/SecurityPkg/Tcg/Tcg2AcpiFfa/Tcg2AcpiFfa.inf index 5d2e80af90a..75309c94f2f 100644 --- a/SecurityPkg/Tcg/Tcg2AcpiFfa/Tcg2AcpiFfa.inf +++ b/SecurityPkg/Tcg/Tcg2AcpiFfa/Tcg2AcpiFfa.inf @@ -66,6 +66,10 @@ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableLaml ## CONSUMES gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableLasa ## CONSUMES gEfiSecurityPkgTokenSpaceGuid.PcdTpmServiceFfaPartitionId ## CONSUMES + ## MU_CHANGE + # Allow a platform to drop TCG ACPI measurements until we have a chance to make them more + # consistent and functional. + gEfiSecurityPkgTokenSpaceGuid.PcdSkipTcgSmmAcpiMeasurements ## CONSUMES [FixedPcd] gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## CONSUMES diff --git a/SecurityPkg/Tcg/Tcg2Dxe/README.md b/SecurityPkg/Tcg/Tcg2Dxe/README.md new file mode 100644 index 00000000000..581c695697e --- /dev/null +++ b/SecurityPkg/Tcg/Tcg2Dxe/README.md @@ -0,0 +1,120 @@ +# Tcg2Dxe + +Tcg2Dxe is a DXE-phase UEFI driver that publishes the TCG2 protocol defined +by the [TCG EFI Protocol Specification](https://trustedcomputinggroup.org/resource/tcg-efi-protocol-specification/). +Its main responsibilites are to expose a standard interface to a TPM device, +measure components and events into PCRs, support measured boot, and enable +secure boot attestation. + +## Dynamic Event Log Scaling + +The TCG event log is initially allocated with a fixed size defined by a +PCD: PcdTcgLogAreaMinLen. As firmware components log measured boot +events the log fills up. Traditionally, when the log is full, subsequent events +are dropped and the log is marked as truncated. + +Tcg2Dxe extends this behavior with **dynamic scaling**: when the log is about +to overflow, the driver doubles its allocation, copies the existing log into +the new buffer, and frees the old one. This allows the log to grow as needed +and avoids losing events. + +### How It Works + +1. **Scaling check** — Before logging a TCG 2.0 event, + `TcgLogDynamicScalingNeeded` calculates whether the new event would exceed + the current allocation (`EventLogAreaStruct->Laml`). + +2. **Reallocation** — When scaling is needed, `TcgScaleEventLog` allocates a + new `EfiBootServicesData` region at twice the current size, copies the + existing log, updates the `Lasa`/`Laml` fields in the event log area + struct, and frees the old region. + +3. **Logging** — After scaling, the new event is logged into the resized buffer + via `TcgDxeLogEvent` inside a TPL-raised critical section. + +### NormalEventLog vs. FinalEventLog + +Tcg2Dxe maintains two distinct event log regions: + +| Log | Memory Type | Lifetime | Can Scale | +| --- | ----------- | -------- | --------- | +| **Normal log** | `EfiBootServicesData` | Available until `ExitBootServices` | Yes | +| **Final Events log** | `EfiACPIMemoryNVS` | Persistent | No | + +- The **Normal log** is the main log copy which is returned via `GetEventLog`. + It can grow dynamically via scaling. Note that previous calls to `GetEventLog` + could contain stale data if the log was scaled after. It is recommended to + call `GetEventLog` each time access is required. +- The **Final Events log** (`EFI_TCG2_FINAL_EVENTS_TABLE`) records events + logged after `GetEventLog` has been called. It is installed as a UEFI + configuration table so the OS can discover events that occurred between its + call to `GetEventLog` and `ExitBootServices`. Because the **Final Events log** + does not scale, it can become truncated. + +### Scale Limit + +The number of times the normal event log region may be dynamically scaled is +capped by `TCG_EVENT_LOG_MAX_SCALE_COUNT`. Each successful scale doubles the +allocation, so this caps total growth at `PcdTcgLogAreaMinLen << TCG_EVENT_LOG_MAX_SCALE_COUNT`. +Once the limit is reached: + +1. `TcgScaleEventLog` refuses to scale further and returns + `EFI_OUT_OF_RESOURCES`. +2. `EventLogAreaStruct->EventLogTruncated` is set to `TRUE`, so subsequent + `GetEventLog` callers see `EventLogTruncated == TRUE`. +3. `HashLogExtendEvent` returns `EFI_VOLUME_FULL` for events that would have + triggered the refused scale. + +### Scaling Notification (`gTcg2EventLogScaledGuid`) + +Each time the normal log is successfully resized, `TcgScaleEventLog` calls +`EfiEventGroupSignal (&gTcg2EventLogScaledGuid)` to notify interested parties +that the log moved in memory. + +Consumers that cache the log base address returned by `GetEventLog` (for +example, parsers walking the log incrementally) must invalidate their cache +on this signal and call `GetEventLog` again to get the current `Lasa`/last +entry. A typical consumer: + +```c +gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + OnTcgEventLogScaled, + Context, + &gTcg2EventLogScaledGuid, + &Event + ); +``` + +The event is declared in `gTcg2EventLogScaledGuid` (see +`SecurityPkg/Include/Guid/Tcg2EventLogScaled.h`) and listed in `Tcg2Dxe.inf`. + +## FinalEventLog Truncation Marker + +Because the **FinalEventLog** is fixed-size and cannot scale, it can fill +up before `ExitBootServices`. When the next event would overflow the log, +`TcgDxeLogEvent` calls `AppendTruncationMarker` which writes a final +`EV_NO_ACTION` event whose payload is the ASCII string +`TCG_LOG_TRUNCATION_EVENT_STRING`. The `NumberOfEvents` counter in +`EFI_TCG2_FINAL_EVENTS_TABLE` is incremented to include the marker, and +`EventLogTruncated` is set so subsequent attempts return `EFI_VOLUME_FULL` +without re-appending the marker. + +To guarantee the marker always fits, FinalEventLog initialization in +`SetupEventLog` subtracts `GetTruncationEventSize()` from the usable `Laml`: + +```c +mTcgDxeData.FinalEventLogAreaStruct[Index].Laml = + PcdGet32 (PcdTcg2FinalLogAreaLen) + - sizeof (EFI_TCG2_FINAL_EVENTS_TABLE) + - GetTruncationEventSize (); +``` + +`AppendTruncationMarker` temporarily restores this reserved space so +`TcgCommLogEvent` will accept the marker write. + +OS-side and pre-OS consumers can detect FinalEventLog truncation by: + +- walking `EFI_TCG2_FINAL_EVENTS_TABLE` and inspecting the last entry for an + `EV_NO_ACTION` event whose payload begins with `"TCG Event Log Truncated"`. diff --git a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c index c9e292159e3..600411cbb0a 100644 --- a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c +++ b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c @@ -11,10 +11,12 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include +#include // MU_CHANGE #include #include #include +#include // MU_CHANGE #include #include #include @@ -76,6 +78,17 @@ TCG2_EVENT_INFO_STRUCT mTcg2EventInfo[] = { #define TCG_EVENT_LOG_AREA_COUNT_MAX 2 +// MU_CHANGE - [BEGIN] + +// Maximum number of times the TCG event log can be dynamically scaled +// before the log is considered truncated. +#define TCG_EVENT_LOG_MAX_SCALE_COUNT 4 + +// Payload written as the last event of the FinalEventLog when it becomes truncated. +#define TCG_LOG_TRUNCATION_EVENT_STRING "TCG Event Log Truncated" + +// MU_CHANGE - [END] + typedef struct { EFI_TCG2_EVENT_LOG_FORMAT EventLogFormat; EFI_PHYSICAL_ADDRESS Lasa; @@ -85,6 +98,7 @@ typedef struct { BOOLEAN EventLogStarted; BOOLEAN EventLogTruncated; UINTN Next800155EventOffset; + UINTN ScaleCount; // MU_CHANGE } TCG_EVENT_LOG_AREA_STRUCT; // Mapping of TPM return status to BIOS/OS TPM support and related flags (TPMPresentFlag, TpmUpdateFlag) @@ -132,7 +146,12 @@ VARIABLE_TYPE mVariableType[] = { { EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid }, }; +// MU_CHANGE - [BEGIN] + EFI_HANDLE mImageHandle; +BOOLEAN mReadyToBoot = FALSE; + +// MU_CHANGE - [END] /** Measure PE image into TPM log based on the authenticode image hashing in @@ -894,7 +913,6 @@ TcgCommLogEvent ( DEBUG ((DEBUG_INFO, " NewLogSize - 0x%x\n", NewLogSize)); DEBUG ((DEBUG_INFO, " LogSize - 0x%x\n", EventLogAreaStruct->EventLogSize)); DEBUG ((DEBUG_INFO, "TcgCommLogEvent - %r\n", EFI_OUT_OF_RESOURCES)); - ASSERT (FALSE); // MU_CHANGE: Assert to catch systematic TCG log truncation during DEBUG testing. return EFI_OUT_OF_RESOURCES; } @@ -942,6 +960,130 @@ TcgCommLogEvent ( return EFI_SUCCESS; } +// MU_CHANGE - [BEGIN] + +/** + Get TPML_DIGEST_VALUES compact binary buffer size. + + @param[in] DigestListBin TPML_DIGEST_VALUES compact binary buffer. + + @return TPML_DIGEST_VALUES compact binary buffer size. +**/ +UINT32 +GetDigestListBinSize ( + IN VOID *DigestListBin + ) +{ + UINTN Index; + UINT16 DigestSize; + UINT32 TotalSize; + UINT32 Count; + TPMI_ALG_HASH HashAlg; + + Count = ReadUnaligned32 (DigestListBin); + TotalSize = sizeof (Count); + DigestListBin = (UINT8 *)DigestListBin + sizeof (Count); + for (Index = 0; Index < Count; Index++) { + HashAlg = ReadUnaligned16 (DigestListBin); + TotalSize += sizeof (HashAlg); + DigestListBin = (UINT8 *)DigestListBin + sizeof (HashAlg); + + DigestSize = GetHashSizeFromAlgo (HashAlg); + TotalSize += DigestSize; + DigestListBin = (UINT8 *)DigestListBin + DigestSize; + } + + return TotalSize; +} + +/** + Build the EV_NO_ACTION truncation marker event. + + @param[out] EventHdr TCG_PCR_EVENT2 header initialized for the + truncation marker. + @param[out] EventHdrSize Size in bytes of the serialized header + (excluding the payload string). +**/ +STATIC +VOID +BuildTruncationEvent ( + OUT TCG_PCR_EVENT2_HDR *EventHdr, + OUT UINT32 *EventHdrSize + ) +{ + InitNoActionEvent (EventHdr, sizeof (TCG_LOG_TRUNCATION_EVENT_STRING)); + *EventHdrSize = (UINT32)(sizeof (EventHdr->PCRIndex) + + sizeof (EventHdr->EventType) + + GetDigestListBinSize (&EventHdr->Digests) + + sizeof (EventHdr->EventSize)); +} + +/** + Compute the total size in bytes of the EV_NO_ACTION truncation marker event + (header for the active PCR banks + truncation payload). + + Used to reserve headroom in the Final Events log so the marker is always + guaranteed to fit when truncation occurs. + + @return Size in bytes of the truncation marker event. +**/ +STATIC +UINTN +GetTruncationEventSize ( + VOID + ) +{ + TCG_PCR_EVENT2_HDR NoActionEvent; + UINT32 EventHdrSize; + + BuildTruncationEvent (&NoActionEvent, &EventHdrSize); + + return EventHdrSize + sizeof (TCG_LOG_TRUNCATION_EVENT_STRING); +} + +/** + Append an EV_NO_ACTION truncation marker as the final entry of the Final + Events log. The marker is written into the headroom reserved at log + initialization (see Final log Laml setup in SetupEventLog) so it is always + guaranteed to fit even when the log is otherwise full. + + @param[in,out] EventLogAreaStruct Final Events log area. + + @retval EFI_SUCCESS The truncation marker was logged. + @retval Other TcgCommLogEvent failed; nothing was logged. +**/ +STATIC +EFI_STATUS +AppendTruncationMarker ( + IN OUT TCG_EVENT_LOG_AREA_STRUCT *EventLogAreaStruct + ) +{ + EFI_STATUS Status; + TCG_PCR_EVENT2_HDR TruncationHdr; + UINT32 TruncationHdrSize; + + BuildTruncationEvent (&TruncationHdr, &TruncationHdrSize); + + // Restore the reserved space so TcgCommLogEvent accepts the marker. + EventLogAreaStruct->Laml += TruncationHdrSize + sizeof (TCG_LOG_TRUNCATION_EVENT_STRING); + + Status = TcgCommLogEvent ( + EventLogAreaStruct, + &TruncationHdr, + TruncationHdrSize, + (UINT8 *)TCG_LOG_TRUNCATION_EVENT_STRING, + sizeof (TCG_LOG_TRUNCATION_EVENT_STRING) + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to log truncation marker - %r\n", __func__, Status)); + } + + return Status; +} + +// MU_CHANGE - [END] + /** Add a new entry to the Event Log. @@ -1027,6 +1169,15 @@ TcgDxeLogEvent ( NewEventSize ); if (Status == EFI_OUT_OF_RESOURCES) { + // MU_CHANGE - [BEGIN] + + Status = AppendTruncationMarker (EventLogAreaStruct); + if (!EFI_ERROR (Status)) { + (mTcgDxeData.FinalEventsTable[Index])->NumberOfEvents++; + } + + // MU_CHANGE - [END] + EventLogAreaStruct->EventLogTruncated = TRUE; return EFI_VOLUME_FULL; } else if (Status == EFI_SUCCESS) { @@ -1043,6 +1194,10 @@ TcgDxeLogEvent ( return Status; } +// MU_CHANGE - [BEGIN] + +#if 0 + /** Get TPML_DIGEST_VALUES compact binary buffer size. @@ -1077,6 +1232,10 @@ GetDigestListBinSize ( return TotalSize; } +#endif + +// MU_CHANGE - [END] + /** Copy TPML_DIGEST_VALUES compact binary into a buffer @@ -1133,6 +1292,159 @@ CopyDigestListBinToBuffer ( return Buffer; } +// MU_CHANGE - [BEGIN] + +/** + Dynamically scale the TCG event log, this should only occur when the + log is filled/truncated. + + @param[in, out] EventLogAreaStruct The event log area data structure. + + @retval EFI_SUCCESS Log was successfully scaled. + @retval EFI_OUT_OF_RESOURCES Allocation failed. + @retval EFI_VOLUME_FULL EventLog truncated. + +**/ +STATIC +EFI_STATUS +TcgScaleEventLog ( + IN OUT TCG_EVENT_LOG_AREA_STRUCT *EventLogAreaStruct + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS NewLasa; + UINT64 NewLaml; + EFI_PHYSICAL_ADDRESS OldLasa; + UINT64 OldLaml; + EFI_TPL OldTpl; + + // Make sure EventLogAreaStruct is valid. + if (EventLogAreaStruct == NULL) { + return EFI_INVALID_PARAMETER; + } + + // If the log was scaled the maximum number of times, mark it as truncated. + if (EventLogAreaStruct->ScaleCount >= TCG_EVENT_LOG_MAX_SCALE_COUNT) { + DEBUG ((DEBUG_ERROR, "%a: Scale limit reached (%u), truncating log\n", __func__, TCG_EVENT_LOG_MAX_SCALE_COUNT)); + EventLogAreaStruct->EventLogTruncated = TRUE; + return EFI_VOLUME_FULL; + } + + NewLaml = EventLogAreaStruct->Laml * 2; + if (NewLaml <= EventLogAreaStruct->Laml) { + DEBUG ((DEBUG_ERROR, "%a: Laml overflow (0x%lx * 2)\n", __func__, EventLogAreaStruct->Laml)); + EventLogAreaStruct->EventLogTruncated = TRUE; + return EFI_OUT_OF_RESOURCES; + } + + Status = gBS->AllocatePages ( + AllocateAnyPages, + EfiBootServicesData, + EFI_SIZE_TO_PAGES ((UINTN)NewLaml), + &NewLasa + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to allocate new TCG event log\n")); + return EFI_OUT_OF_RESOURCES; + } + + // Enter a critical section, we do not want to be interrupted while copying. + OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); + + // Copy the data from the old event log to the new event log. + CopyMem ((VOID *)(UINTN)NewLasa, (VOID *)(UINTN)EventLogAreaStruct->Lasa, EventLogAreaStruct->EventLogSize); + + // Store the old Lasa and Laml before updating. + OldLasa = EventLogAreaStruct->Lasa; + OldLaml = EventLogAreaStruct->Laml; + + DEBUG ((DEBUG_INFO, "OldLasa: 0x%lx, OldLaml: 0x%lx\n", OldLasa, OldLaml)); + DEBUG ((DEBUG_INFO, "NewLasa: 0x%lx, NewLaml: 0x%lx\n", NewLasa, NewLaml)); + + // Update the EventLogAreaStruct. + EventLogAreaStruct->Lasa = NewLasa; + EventLogAreaStruct->Laml = NewLaml; + + // Update the LastEvent pointer. LastEvent = Lasa + Offset. To calculate + // the offset we can do: Offset = LastEvent - Lasa. + EventLogAreaStruct->LastEvent = (UINT8 *)(UINTN)NewLasa + ((UINTN)EventLogAreaStruct->LastEvent - (UINTN)OldLasa); + + // Track the number of times we've scaled. + EventLogAreaStruct->ScaleCount++; + + // Exit the critical section once we finish copying/updated the struct. + gBS->RestoreTPL (OldTpl); + + // Free the old log region. + gBS->FreePages (OldLasa, EFI_SIZE_TO_PAGES ((UINTN)OldLaml)); + + // Notify that the event log was scaled. + EfiEventGroupSignal (&gTcg2EventLogScaledGuid); + + return Status; +} + +/** + Check if the TCG log needs to be dynamically scaled. + + @param[in] EventLogAreaStruct Pointer to the event log area structure. + @param[in] NewEventHdrSize New event header size. + @param[in] NewEventSize New event data size. + + @retval TRUE Dynamic scaling needed. + @retval FALSE Dynamic scaling not needed. + +**/ +STATIC +BOOLEAN +TcgLogDynamicScalingNeeded ( + IN TCG_EVENT_LOG_AREA_STRUCT *EventLogAreaStruct, + IN UINT32 NewEventHdrSize, + IN UINT32 NewEventSize + ) +{ + UINTN NewLogSize; + + // Make sure EventLogAreaStruct is valid. + if (EventLogAreaStruct == NULL) { + return FALSE; + } + + // Validate NewEventSize + NewEventHdrSize doesn't cause an overflow. + if (NewEventSize > MAX_ADDRESS - NewEventHdrSize) { + ASSERT (FALSE); + return FALSE; + } + + NewLogSize = NewEventHdrSize + NewEventSize; + + // Validate EventLogSize + NewLogSize doesn't cause an overflow. + if (NewLogSize > MAX_ADDRESS - EventLogAreaStruct->EventLogSize) { + ASSERT (FALSE); + return FALSE; + } + + // Determine if dynamic scaling is needed. + if (NewLogSize + EventLogAreaStruct->EventLogSize > EventLogAreaStruct->Laml) { + DEBUG ((DEBUG_INFO, " Laml - 0x%lx\n", EventLogAreaStruct->Laml)); + DEBUG ((DEBUG_INFO, " NewLogSize - 0x%lx\n", NewLogSize)); + DEBUG ((DEBUG_INFO, " LogSize - 0x%lx\n", EventLogAreaStruct->EventLogSize)); + DEBUG ((DEBUG_ERROR, "Dynamic scaling required! Recommended to update your TCG log size!\n")); + + // Log an error if we attempt to scale post ReadyToBoot. + if (mReadyToBoot) { + DEBUG ((DEBUG_ERROR, "Unexpected dynamic scaling occurring post ReadyToBoot!\n")); + } + + return TRUE; + } + + return FALSE; +} + +// MU_CHANGE - [END] + /** Add a new entry to the Event Log. @@ -1150,6 +1462,8 @@ TcgDxeLogHashEvent ( IN UINT8 *NewEventData ) { + // MU_CHANGE - [BEGIN] + EFI_STATUS Status; EFI_TPL OldTpl; UINTN Index; @@ -1157,6 +1471,9 @@ TcgDxeLogHashEvent ( TCG_PCR_EVENT2 TcgPcrEvent2; UINT8 *DigestBuffer; UINT32 *EventSizePtr; + BOOLEAN DynamicScalingNeeded; + + // MU_CHANGE - [END] RetStatus = EFI_SUCCESS; for (Index = 0; Index < sizeof (mTcg2EventInfo)/sizeof (mTcg2EventInfo[0]); Index++) { @@ -1195,6 +1512,30 @@ TcgDxeLogHashEvent ( EventSizePtr = CopyDigestListToBuffer (DigestBuffer, DigestList, mTcgDxeData.BsCap.ActivePcrBanks); CopyMem (EventSizePtr, &NewEventHdr->EventSize, sizeof (NewEventHdr->EventSize)); + // MU_CHANGE - [BEGIN] + + // Continually scale until we have enough space to log. We need to dynamically + // scale the TCG log before we enter a critical region. + while (TRUE) { + DynamicScalingNeeded = TcgLogDynamicScalingNeeded ( + &mTcgDxeData.EventLogAreaStruct[Index], + sizeof (TcgPcrEvent2.PCRIndex) + sizeof (TcgPcrEvent2.EventType) + GetDigestListBinSize (DigestBuffer) + sizeof (TcgPcrEvent2.EventSize), + NewEventHdr->EventSize + ); + + if (!DynamicScalingNeeded) { + break; + } + + Status = TcgScaleEventLog (&mTcgDxeData.EventLogAreaStruct[Index]); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Unable to scale the TCG event log!\n")); + return Status; + } + } + + // MU_CHANGE - [END] + // // Enter critical region // @@ -1702,21 +2043,18 @@ SetupEventLog ( for (Index = 0; Index < sizeof (mTcg2EventInfo)/sizeof (mTcg2EventInfo[0]); Index++) { if ((mTcgDxeData.BsCap.SupportedEventLogs & mTcg2EventInfo[Index].LogFormat) != 0) { mTcgDxeData.EventLogAreaStruct[Index].EventLogFormat = mTcg2EventInfo[Index].LogFormat; - if (PcdGet8 (PcdTpm2AcpiTableRev) >= 4) { - Status = gBS->AllocatePages ( - AllocateAnyPages, - EfiACPIMemoryNVS, - EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcgLogAreaMinLen)), - &Lasa - ); - } else { - Status = gBS->AllocatePages ( - AllocateAnyPages, - EfiBootServicesData, - EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcgLogAreaMinLen)), - &Lasa - ); - } + + // MU_CHANGE - [BEGIN] + + // Always allocate BootServicesData + Status = gBS->AllocatePages ( + AllocateAnyPages, + EfiBootServicesData, + EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcgLogAreaMinLen)), + &Lasa + ); + + // MU_CHANGE - [END] if (EFI_ERROR (Status)) { return Status; @@ -1725,7 +2063,9 @@ SetupEventLog ( mTcgDxeData.EventLogAreaStruct[Index].Lasa = Lasa; mTcgDxeData.EventLogAreaStruct[Index].Laml = PcdGet32 (PcdTcgLogAreaMinLen); mTcgDxeData.EventLogAreaStruct[Index].Next800155EventOffset = 0; + mTcgDxeData.EventLogAreaStruct[Index].ScaleCount = 0; // MU_CHANGE + /* MU_CHANGE if ((PcdGet8 (PcdTpm2AcpiTableRev) >= 4) || (mTcg2EventInfo[Index].LogFormat == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)) { @@ -1736,6 +2076,7 @@ SetupEventLog ( PcdSet32S (PcdTpm2AcpiTableLaml, (UINT32)mTcgDxeData.EventLogAreaStruct[Index].Laml); PcdSet64S (PcdTpm2AcpiTableLasa, mTcgDxeData.EventLogAreaStruct[Index].Lasa); } + */ // // To initialize them as 0xFF is recommended @@ -1886,6 +2227,16 @@ SetupEventLog ( for (Index = 0; Index < sizeof (mTcg2EventInfo)/sizeof (mTcg2EventInfo[0]); Index++) { if ((mTcgDxeData.BsCap.SupportedEventLogs & mTcg2EventInfo[Index].LogFormat) != 0) { if (mTcg2EventInfo[Index].LogFormat == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) { + // MU_CHANGE - [BEGIN] + // PcdTcg2FinalLogAreaLen is platform-configurable; ensure it has room for both the + // EFI_TCG2_FINAL_EVENTS_TABLE header and the EV_NO_ACTION truncation marker event. + if (PcdGet32 (PcdTcg2FinalLogAreaLen) < sizeof (EFI_TCG2_FINAL_EVENTS_TABLE) + GetTruncationEventSize ()) { + DEBUG ((DEBUG_ERROR, "Insufficient FinalEventLogArea length\n")); + return EFI_INVALID_PARAMETER; + } + + // MU_CHANGE - [END] + Status = gBS->AllocatePages ( AllocateAnyPages, EfiACPIMemoryNVS, @@ -1905,9 +2256,11 @@ SetupEventLog ( (mTcgDxeData.FinalEventsTable[Index])->Version = EFI_TCG2_FINAL_EVENTS_TABLE_VERSION; (mTcgDxeData.FinalEventsTable[Index])->NumberOfEvents = 0; - mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogFormat = mTcg2EventInfo[Index].LogFormat; - mTcgDxeData.FinalEventLogAreaStruct[Index].Lasa = Lasa + sizeof (EFI_TCG2_FINAL_EVENTS_TABLE); - mTcgDxeData.FinalEventLogAreaStruct[Index].Laml = PcdGet32 (PcdTcg2FinalLogAreaLen) - sizeof (EFI_TCG2_FINAL_EVENTS_TABLE); + mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogFormat = mTcg2EventInfo[Index].LogFormat; + mTcgDxeData.FinalEventLogAreaStruct[Index].Lasa = Lasa + sizeof (EFI_TCG2_FINAL_EVENTS_TABLE); + // MU_CHANGE + // Reserve space in the FinalEventLog for the EV_NO_ACTION truncation marker event. + mTcgDxeData.FinalEventLogAreaStruct[Index].Laml = PcdGet32 (PcdTcg2FinalLogAreaLen) - sizeof (EFI_TCG2_FINAL_EVENTS_TABLE) - GetTruncationEventSize (); mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogSize = 0; mTcgDxeData.FinalEventLogAreaStruct[Index].LastEvent = (VOID *)(UINTN)mTcgDxeData.FinalEventLogAreaStruct[Index].Lasa; mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogStarted = FALSE; @@ -2596,6 +2949,8 @@ OnReadyToBoot ( PERF_FUNCTION_BEGIN (); + mReadyToBoot = TRUE; // MU_CHANGE + // MU_CHANGE_23086 // MU_CHANGE [BEGIN] - Call OEM init hook. Status = OemTpm2InitDxeReadyToBootEvent (mBootAttempts); diff --git a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf index 74877e13dbe..98b4921a441 100644 --- a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf +++ b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf @@ -99,6 +99,7 @@ gTpm2StartupLocalityHobGuid ## SOMETIMES_CONSUMES ## HOB gTcg800155PlatformIdEventHobGuid ## SOMETIMES_CONSUMES ## HOB gEfiDeviceSignatureDatabaseGuid + gTcg2EventLogScaledGuid ## SOMETIMES_PRODUCES ## Event # MU_CHANGE [Protocols] gEfiTcg2ProtocolGuid ## PRODUCES @@ -118,8 +119,8 @@ gEfiSecurityPkgTokenSpaceGuid.PcdTcgLogAreaMinLen ## CONSUMES gEfiSecurityPkgTokenSpaceGuid.PcdTcg2FinalLogAreaLen ## CONSUMES gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableRev ## CONSUMES - gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableLaml ## PRODUCES - gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableLasa ## PRODUCES + # gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableLaml ## PRODUCES # MU_CHANGE + # gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableLasa ## PRODUCES # MU_CHANGE gEfiMdeModulePkgTokenSpaceGuid.PcdTcgPfpMeasurementRevision ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdEnableSpdmDeviceAuthentication ## CONSUMES gEfiSecurityPkgTokenSpaceGuid.TcgMeasureBootStringsInPcr4 ## CONSUMES # MU_CHANGE diff --git a/SecurityPkg/Tcg/TcgLogTest/README.md b/SecurityPkg/Tcg/TcgLogTest/README.md new file mode 100644 index 00000000000..c5387aa6a54 --- /dev/null +++ b/SecurityPkg/Tcg/TcgLogTest/README.md @@ -0,0 +1,279 @@ +# TcgLogTest + +TcgLogTest validates the dynamic event log scaling functionality implemented +by `Tcg2Dxe`. It consists of a DXE driver (`TcgLogTestDxe`) and a UEFI shell +unit test application (`TcgLogTestApp`) that coordinate across multiple boots +to exercise scaling both before and after `ReadyToBoot`. + +## Components + +### TcgLogTestDxe (DXE_DRIVER) + +A DXE driver that runs pre-ReadyToBoot scaling tests on demand. It installs +the `TCG_LOG_TEST_PROTOCOL` which allows the test application to enable/disable +the tests and retrieve results. + +**Entry flow:** + +1. Installs the `TCG_LOG_TEST_PROTOCOL` on a new handle. +2. Checks the NV variable `TcgLogTestEnable` (existence-based: present = + enabled, absent = disabled). +3. If disabled: + - Returns immediately. The protocol is still available for the test app + to call `Enable` on. +4. If enabled: + - Deletes the enable variable. This makes it so the test only runs once. + - Locates `EFI_TCG2_PROTOCOL`. + - Runs `TestPreReadyToBootScaling`. + - Records results in an internal log buffer which can be acquired via + `GetLog`. + +#### Protocol + +The `TCG_LOG_TEST_PROTOCOL` provides the following function(s): + +| Function | Description | +| -------- | ----------- | +| `GetLog` | Returns a pointer to the DXE driver's internal ASCII log buffer and its size. Returns `EFI_NOT_STARTED` if the test did not run this boot. | +| `Enable` | Creates or deletes the `TcgLogTestEnable` NV variable to enable or disable the DXE test for the next boot. | + +The `TCG_LOG_TEST_PROTOCOL` GUID is defined in `TcgLogTest.h` and declared +in `SecurityPkg.dec`. + +```code +#define TCG_LOG_TEST_PROTOCOL_GUID \ + { 0xA3C12F80, 0x7D9E, 0x4B5A, { 0x91, 0xE4, 0x6C, 0xF8, 0x2D, 0xA1, 0xB7, 0x03 } } +``` + +#### NV Variable + +The enable/disable mechanism uses an NV variable rather than UnitTest saved +context because the DXE driver and the test application are separate binaries. +The DXE driver does not use `UnitTestLib` and cannot access the framework's +persisted state. An NV variable is the standard cross-module communication +channel in UEFI. + +| Attribute | Value | +| --------- | ----- | +| Name | `TcgLogTestEnable` | +| Vendor GUID | `gTcgLogTestProtocolGuid` | +| Attributes | `NV + BS` | +| Semantics | Existence-based: variable present = enabled, variable absent = disabled | + +#### Test: TestPreReadyToBootScaling + +Executed before `ReadyToBoot` when the NV variable is present indicating the +test was enabled. Exercises dynamic scaling before `ReadyToBoot` has fired. + +1. Calls `TcgLogTestLogEventsUntilScaled` to repeatedly log `EV_NO_ACTION` + events to PCR 8. Internally, the helper registers a notification callback + on `gTcg2EventLogScaledGuid` and stops as soon as `Tcg2Dxe` signals that + GUID, indicating the event log was dynamically scaled. +2. Writes `PASS` or `FAIL` (with details) to the internal log buffer. + +### TcgLogTestApp (UEFI_APPLICATION) + +A UnitTest framework shell application that runs post-ReadyToBoot scaling tests. + +The suite registers five test cases. Each case shares a `LocateProtocols` +prerequisite that resolves `EFI_TCG2_PROTOCOL` and `TCG_LOG_TEST_PROTOCOL`. + +| # | Test Case (Class Name) | Function | Cleanup | +| - | ---------------------- | -------- | ------- | +| 1 | `PostRtbScaling` | `TestPostReadyToBootScaling` | none | +| 2 | `ScaleLimitTruncates` | `TestScaleLimitTruncatesLog` | `EnableDxeTestAndReboot` | +| 3 | `SnapshotPlusFinalMatches` | `TestSnapshotPlusFinalMatchesEventLog` | none | +| 4 | `FinalEventLogTruncates` | `TestFinalEventLogTruncationMarker` | none | +| 5 | `PreRtbResults` | `TestPreReadyToBootScaling` | `SaveAndReboot` | + +#### Test: TestPostReadyToBootScaling + +Executed after `ReadyToBoot` in the UEFI shell. Exercises dynamic scaling +after `ReadyToBoot` has fired. + +1. Calls `TcgLogTestLogEventsUntilScaled` to repeatedly log `EV_NO_ACTION` + events to PCR 8. Internally, the helper registers a notification callback + on `gTcg2EventLogScaledGuid` and stops as soon as `Tcg2Dxe` signals that + GUID, indicating the event log was dynamically scaled. + +#### Test: TestScaleLimitTruncatesLog + +Verifies that the normal event log can only be dynamically scaled up to +`TCG_EVENT_LOG_MAX_SCALE_COUNT` times, after which scaling is refused and +`GetEventLog` reports the log as truncated. + +1. `TestPostReadyToBootScaling` already consumed one scale, so this test + calls `TcgLogTestLogEventsUntilScaled` repeatedly to exhaust the remaining + `TCG_EVENT_LOG_MAX_SCALE_COUNT - 1` scales. +2. Calls `TcgLogTestLogEventsUntilScaled` once more and asserts it returns + an error and reports `Scaled = FALSE`. +3. Calls `GetEventLog` and asserts the `Truncated` flag is `TRUE`. + +#### Test: TestSnapshotPlusFinalMatchesEventLog + +Validates the relationship between the normal event log and the +`FinalEventLog`: after the first `GetEventLog` call activates FinalEventLog +logging, every newly logged event must be appended to **both** the normal +log and the FinalEventLog. Therefore: + +```text +Snapshot1 + FinalEventLog_entries == Snapshot2 +``` + +1. Calls `GetEventLog` to capture `Snapshot1` (and activate FinalEventLog + logging). +2. Calls `TcgLogTestLogSingleEvent` `MAX_NUM_EXTRA_EVENTS` times so the new + entries are small enough to avoid triggering scaling. +3. Locates `EFI_TCG2_FINAL_EVENTS_TABLE` from the system configuration table + and asserts `NumberOfEvents == MAX_NUM_EXTRA_EVENTS`. +4. Walks the FinalEventLog entries to compute their combined byte size. +5. Calls `GetEventLog` again to capture `Snapshot2`. +6. Asserts `Snapshot2 == Snapshot1 || FinalEventLog_entries` byte-for-byte. + +#### Test: TestFinalEventLogTruncationMarker + +Verifies that when the `FinalEventLog` fills up, `Tcg2Dxe` appends a final +`EV_NO_ACTION` event carrying the `TCG_LOG_TRUNCATION_EVENT_STRING` marker +(`"TCG Event Log Truncated"`) so consumers can recognise the truncated state. + +1. Calls `GetEventLog` to activate FinalEventLog logging and assert it is + not yet truncated. +2. Calls `TcgLogTestLogEventsUntilScaled` in a loop until `HashLogExtendEvent` + returns `EFI_VOLUME_FULL`, signalling FinalEventLog truncation. (The normal + log can still scale; the FinalEventLog cannot.) +3. Locates `EFI_TCG2_FINAL_EVENTS_TABLE` and walks all `NumberOfEvents` entries + to land on the last entry. +4. Asserts the last entry is `EV_NO_ACTION` and its payload begins with the + ASCII bytes of `TCG_LOG_TRUNCATION_EVENT_STRING`. + +#### Test: TestPreReadyToBootScaling Results + +Verifies the DXE driver's pre-ReadyToBoot results. + +1. Locates `TCG_LOG_TEST_PROTOCOL` and calls `GetLog`. +2. Dumps the DXE driver's log for visibility. +3. Asserts the log contains `"PASS"` and does not contain `"FAIL"`. + +## Three-Boot Reboot Flow + +The tests require three boots to complete because scaling must be tested in +two different phases of the boot process, and each phase requires a separate +boot. The final boot should guarantee that the TCG event log is not polluted +with the test `NO_ACTION_EVENT` events used to scale the log. + +```text +Boot 1 (Post-ReadyToBoot scaling + truncation) +├── TcgLogTestDxe: +│ ├── Installs TCG_LOG_TEST_PROTOCOL. +│ ├── NV variable absent → Test not enabled → SKIPPED. +├── TcgLogTestApp: +│ ├── Launched from UEFI shell. (UnitTest Framework) +│ ├── Test Prerequisites: +│ │ └── Calls LocateProtocols() to locate the TCG2 and TcgLogTest protocols. +│ ├── TestPostReadyToBootScaling(): +│ │ ├── Calls TcgLogTestLogEventsUntilScaled() to scale the event log once. +│ │ └── PASS. +│ ├── TestScaleLimitTruncatesLog(): +│ │ ├── Scales the remaining (TCG_EVENT_LOG_MAX_SCALE_COUNT - 1) times. +│ │ ├── Attempts one more scale and asserts it fails. +│ │ ├── Calls GetEventLog() and asserts Truncated == TRUE. +│ │ └── PASS. +│ └── Test Cleanup (for TestScaleLimitTruncatesLog): +│ └── Calls EnableDxeTestAndReboot(). +│ ├── Calls Enable (TRUE) to create the NV variable. +│ └── Calls SaveAndReboot() to SaveFrameworkState + EfiResetCold. +│ +Boot 2 (DXE pre-ReadyToBoot test + FinalEventLog tests + DXE results) +├── TcgLogTestDxe: +│ ├── Installs TCG_LOG_TEST_PROTOCOL. +│ ├── NV variable present → Test enabled → Deletes the NV variable → Runs. +│ ├── Calls TestPreReadyToBootScaling(): +│ │ ├── Calls TcgLogTestLogEventsUntilScaled() to scale the event log. +│ │ ├── PASS. +│ │ └── Logs results into internal buffer for later access via GetLog(). +├── TcgLogTestApp: +│ ├── Resumes execution from UEFI shell. (UnitTest Framework) +│ ├── TestPostReadyToBootScaling() → already PASSED → SKIPPED. +│ ├── TestScaleLimitTruncatesLog() → already PASSED → SKIPPED. +│ ├── TestSnapshotPlusFinalMatchesEventLog(): +│ │ ├── Captures Snapshot1 of the normal log and activates FinalEventLog. +│ │ ├── Logs MAX_NUM_EXTRA_EVENTS individual events. +│ │ ├── Reads FinalEventsTable and asserts NumberOfEvents matches. +│ │ ├── Captures Snapshot2 and asserts Snapshot1 || FinalEntries == Snapshot2. +│ │ └── PASS. +│ ├── TestFinalEventLogTruncationMarker(): +│ │ ├── Logs events until HashLogExtendEvent returns EFI_VOLUME_FULL. +│ │ ├── Walks FinalEventsTable to the last entry. +│ │ ├── Asserts the entry is EV_NO_ACTION carrying TCG_LOG_TRUNCATION_EVENT_STRING. +│ │ └── PASS. +│ ├── TestPreReadyToBootScaling() (DXE results): +│ │ ├── Calls GetLog() to acquire the TcgLogTestDxe log. +│ │ ├── Verifies PASS in TcgLogTestDxe log. +│ │ └── PASS. +│ └── Test Cleanup (for TestPreReadyToBootScaling): +│ └── Calls SaveAndReboot() to SaveFrameworkState + EfiResetCold. +│ +Boot 3 (Final Report/Results) +├── TcgLogTestDxe: +│ ├── Installs TCG_LOG_TEST_PROTOCOL. +│ ├── NV variable absent → Test not enabled → Exit. +├── TcgLogTestApp: +│ ├── Resumes execution from UEFI shell. (UnitTest Framework) +│ ├── All tests already PASSED → SKIPPED. +│ └── Reports final results, cleans up framework state. +``` + +## Shared Code (TcgLogTestCommon) + +Common functions compiled into both binaries: + +| Function | Description | +| -------- | ----------- | +| `TcgLogTestAdvanceEvent` | Parses one TCG 2.0 event entry, advancing the pointer to the next event. Handles SHA-1/256/384/512/SM3 digest algorithms. | +| `TcgLogTestLogEventsUntilScaled` | Builds a test event and logs it repeatedly via `HashLogExtendEvent` until `Tcg2Dxe` signals `gTcg2EventLogScaledGuid` (indicating the event log was dynamically scaled) or `HashLogExtendEvent` returns an error. | +| `TcgLogTestLogSingleEvent` | Builds and logs exactly one fixed test event via `HashLogExtendEvent`. Used by tests that need to add a small, deterministic number of events without triggering scaling. | + +## Truncation Marker Event + +When the `FinalEventLog` fills up and `Tcg2Dxe` can no longer append new +entries, it writes a final `EV_NO_ACTION` event whose data payload is the +ASCII string `"TCG Event Log Truncated"` (`TCG_LOG_TRUNCATION_EVENT_STRING`). +`TestFinalEventLogTruncationMarker` exercises this code path and verifies the +marker is present as the last entry of the table. The string constant in the +test sources must stay in sync with the definition in `Tcg2Dxe.c`. + +## Platform Integration + +### DSC + +Add both modules to the platform DSC under the `[Components]` section, +typically gated behind a TPM enable flag: + +```ini +!if $(TPM2_ENABLE) == TRUE + SecurityPkg/Tcg/TcgLogTest/TcgLogTestDxe.inf + SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.inf +!endif +``` + +### FDF + +Add both modules to the platform FDF so they are included in the firmware +volume, typically gated behind a TPM enable flag. The DXE driver must be in +the DXE FV so it loads during DXE dispatch. The test application can be in +the same FV or a separate one accessible from the UEFI shell: + +```ini +!if $(TPM2_ENABLE) == TRUE + INF SecurityPkg/Tcg/TcgLogTest/TcgLogTestDxe.inf + INF SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.inf +!endif +``` + +### Running the Test + +1. Boot to the UEFI shell. +2. Run the test application: `TcgLogTestApp.efi` +3. The system will automatically reboot twice more to complete the three-boot + flow. +4. On the third boot, the framework reports final results to the shell. diff --git a/SecurityPkg/Tcg/TcgLogTest/TcgLogTest.h b/SecurityPkg/Tcg/TcgLogTest/TcgLogTest.h new file mode 100644 index 00000000000..ee5795cc41c --- /dev/null +++ b/SecurityPkg/Tcg/TcgLogTest/TcgLogTest.h @@ -0,0 +1,67 @@ +/** @file + TCG Log Test protocol definition. + + Defines the protocol produced by TcgLogTestDxe that allows the TcgLogTestApp + to retrieve pre-ReadyToBoot test results and to enable/disable the DXE test + via an NV variable. + + Copyright (c), Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef TCG_LOG_TEST_H_ +#define TCG_LOG_TEST_H_ + +#include + +#define TCG_LOG_TEST_PROTOCOL_GUID \ + { 0xA3C12F80, 0x7D9E, 0x4B5A, { 0x91, 0xE4, 0x6C, 0xF8, 0x2D, 0xA1, 0xB7, 0x03 } } + +#define TCG_LOG_TEST_ENABLE_VARIABLE_NAME L"TcgLogTestEnable" + +typedef struct _TCG_LOG_TEST_PROTOCOL TCG_LOG_TEST_PROTOCOL; + +/** + Retrieve the pre-ReadyToBoot test log produced by TcgLogTestDxe. + + @param[in] This Protocol instance. + @param[out] LogBuffer Pointer to the internal log buffer (NULL-terminated). + @param[out] LogSize Number of valid bytes in LogBuffer (including NULL). + + @retval EFI_SUCCESS Log data returned. + @retval EFI_NOT_STARTED The DXE test did not run this boot. + @retval EFI_INVALID_PARAMETER NULL pointer supplied. +**/ +typedef +EFI_STATUS +(EFIAPI *TCG_LOG_TEST_GET_LOG)( + IN TCG_LOG_TEST_PROTOCOL *This, + OUT CHAR8 **LogBuffer, + OUT UINTN *LogSize + ); + +/** + Enable or disable the DXE pre-ReadyToBoot test for the next boot by + writing an NV variable. + + @param[in] This Protocol instance. + @param[in] Enable TRUE to enable the test on next boot, FALSE to disable. + + @retval EFI_SUCCESS Variable written successfully. + @retval Other SetVariable failure. +**/ +typedef +EFI_STATUS +(EFIAPI *TCG_LOG_TEST_ENABLE)( + IN TCG_LOG_TEST_PROTOCOL *This, + IN BOOLEAN Enable + ); + +struct _TCG_LOG_TEST_PROTOCOL { + TCG_LOG_TEST_GET_LOG GetLog; + TCG_LOG_TEST_ENABLE Enable; +}; + +extern EFI_GUID gTcgLogTestProtocolGuid; + +#endif // TCG_LOG_TEST_H_ diff --git a/SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.c b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.c new file mode 100644 index 00000000000..aacc6f07647 --- /dev/null +++ b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.c @@ -0,0 +1,544 @@ +/** @file + UEFI Shell UnitTest application that validates TCG2 event log dynamic + scaling after ReadyToBoot. + + This application locates the TcgLogTestProtocol produced by TcgLogTestDxe to + retrieve pre-ReadyToBoot test logs, then exercises post-ReadyToBoot scaling. + + Copyright (c), Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TcgLogTest.h" +#include "TcgLogTestCommon.h" + +#define UNIT_TEST_NAME "TCG Log Scaling Test" +#define UNIT_TEST_VERSION "1.0" + +// Must match TCG_EVENT_LOG_MAX_SCALE_COUNT in Tcg2Dxe.c. +#define TCG_EVENT_LOG_MAX_SCALE_COUNT 4 + +// Must match TCG_LOG_TRUNCATION_EVENT_STRING in Tcg2Dxe.c. +#define TCG_LOG_TRUNCATION_EVENT_STRING "TCG Event Log Truncated" + +// Number of extra events to log +#define MAX_NUM_EXTRA_EVENTS 8 + +STATIC EFI_TCG2_PROTOCOL *mTcg2Protocol = NULL; +STATIC TCG_LOG_TEST_PROTOCOL *mTcgLogTestProtocol = NULL; + +/** + Test that the DXE driver ran and its pre-ReadyToBoot log contains PASS. + + This runs on the second boot after TestPostReadyToBootScaling enabled the + DXE driver and rebooted. The DXE driver ran before ReadyToBoot on this + boot, so results are available via the protocol. + + @param[in] Context Unit test context (unused). + + @retval UNIT_TEST_PASSED Log contains PASS and no FAIL. + @retval UNIT_TEST_ERROR_TEST_FAILED Assertion failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestPreReadyToBootScaling ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + CHAR8 *LogBuffer; + UINTN LogSize; + + // The prerequisite is skipped on resume from a reboot, so locate the + // protocol here if it was not already set. + if (mTcgLogTestProtocol == NULL) { + Status = gBS->LocateProtocol (&gTcgLogTestProtocolGuid, NULL, (VOID **)&mTcgLogTestProtocol); + UT_ASSERT_NOT_EFI_ERROR (Status); + } + + Status = mTcgLogTestProtocol->GetLog (mTcgLogTestProtocol, &LogBuffer, &LogSize); + if (EFI_ERROR (Status)) { + UT_LOG_ERROR ("GetLog failed: %r\n", Status); + return UNIT_TEST_ERROR_TEST_FAILED; + } + + // Dump the DXE driver's log for visibility. + UT_LOG_INFO ("TcgLogTestDxe Log (%u bytes):\n%a\n", LogSize, LogBuffer); + + // Verify the log contains "PASS". + UT_ASSERT_NOT_NULL (AsciiStrStr (LogBuffer, "PASS")); + + // Verify the log does not contain "FAIL". + UT_ASSERT_TRUE (AsciiStrStr (LogBuffer, "FAIL") == NULL); + + return UNIT_TEST_PASSED; +} + +/** + Test post-ReadyToBoot scaling: log events until the log scales. + + @param[in] Context Unit test context (unused). + + @retval UNIT_TEST_PASSED Scaling verified. + @retval UNIT_TEST_ERROR_TEST_FAILED Assertion failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestPostReadyToBootScaling ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + BOOLEAN Scaled; + + Status = TcgLogTestLogEventsUntilScaled (mTcg2Protocol, &Scaled); + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_TRUE (Scaled); + + UT_LOG_INFO ("Post-ReadyToBoot scaling succeeded\n"); + + return UNIT_TEST_PASSED; +} + +/** + Test that the TCG event log can only be dynamically scaled up to + TCG_EVENT_LOG_MAX_SCALE_COUNT times, after which the log is marked as + truncated. + + TestPostReadyToBootScaling already consumed one scale in this boot, so this + test exhausts the remaining (TCG_EVENT_LOG_MAX_SCALE_COUNT - 1) scales and + then verifies the next attempt fails and the log is marked truncated. + + @param[in] Context Unit test context (unused). + + @retval UNIT_TEST_PASSED Scaling limit and truncation verified. + @retval UNIT_TEST_ERROR_TEST_FAILED Assertion failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestScaleLimitTruncatesLog ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + BOOLEAN Scaled; + BOOLEAN Truncated; + UINTN ScaleCount; + EFI_PHYSICAL_ADDRESS LogBase; + EFI_PHYSICAL_ADDRESS LastEntry; + + // TestPostReadyToBootScaling scaled once, scale the remaining amount. + for (ScaleCount = 1; ScaleCount < TCG_EVENT_LOG_MAX_SCALE_COUNT; ScaleCount++) { + Scaled = FALSE; + Status = TcgLogTestLogEventsUntilScaled (mTcg2Protocol, &Scaled); + UT_LOG_INFO ("Scale %u/%u: status=%r scaled=%d\n", ScaleCount + 1, TCG_EVENT_LOG_MAX_SCALE_COUNT, Status, Scaled); + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_TRUE (Scaled); + } + + // Attempt to scale once more which should fail. + Scaled = FALSE; + Status = TcgLogTestLogEventsUntilScaled (mTcg2Protocol, &Scaled); + UT_LOG_INFO ("Scale beyond limit: status=%r scaled=%d\n", Status, Scaled); + UT_ASSERT_TRUE (EFI_ERROR (Status)); + UT_ASSERT_FALSE (Scaled); + + // Verify GetEventLog reports the log as truncated. + Status = mTcg2Protocol->GetEventLog ( + mTcg2Protocol, + EFI_TCG2_EVENT_LOG_FORMAT_TCG_2, + &LogBase, + &LastEntry, + &Truncated + ); + + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_TRUE (Truncated); + + UT_LOG_INFO ("Test scaling limit succeeded\n"); + + return UNIT_TEST_PASSED; +} + +/** + Test that an EV_NO_ACTION truncation marker is appended to the + FinalEventLog when it becomes truncated. + + Activates FinalEventLog via GetEventLog, then logs events until + HashLogExtendEvent reports an error. Because the FinalEventLog does not scale + it is possible to truncate at which point the truncation marker is appended + as the final entry. The test then walks the table and verifies the last entry + is an EV_NO_ACTION carrying the truncation marker string. + + @param[in] Context Unit test context (unused). + + @retval UNIT_TEST_PASSED Truncation marker located and verified. + @retval UNIT_TEST_ERROR_TEST_FAILED Assertion failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestFinalEventLogTruncationMarker ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS LogBase; + EFI_PHYSICAL_ADDRESS LastEntry; + BOOLEAN Truncated; + BOOLEAN Scaled; + EFI_TCG2_FINAL_EVENTS_TABLE *FinalTable; + UINT8 *CurrentEvent; + UINT32 EventType; + UINT32 EventSize; + UINT8 *EventData; + UINT64 Index; + + // Activate FinalEventLog logging. + Status = mTcg2Protocol->GetEventLog ( + mTcg2Protocol, + EFI_TCG2_EVENT_LOG_FORMAT_TCG_2, + &LogBase, + &LastEntry, + &Truncated + ); + + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_FALSE (Truncated); + + // Log events until HashLogExtendEvent reports an error. When the + // FinalEventLog becomes truncated, HashLogExtendEvent will return + // EFI_VOLUME_FULL. + Scaled = FALSE; + do { + Status = TcgLogTestLogEventsUntilScaled (mTcg2Protocol, &Scaled); + } while (!EFI_ERROR (Status)); + + UT_LOG_INFO ("Log events stopped: status=%r", Status); + UT_ASSERT_TRUE (Status == EFI_VOLUME_FULL); + + // Walk the FinalEventsTable and verify the last entry is the truncation marker. + FinalTable = NULL; + Status = EfiGetSystemConfigurationTable (&gEfiTcg2FinalEventsTableGuid, (VOID **)&FinalTable); + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_NOT_NULL (FinalTable); + + UT_LOG_INFO ("FinalEventsTable: Version=%lu NumberOfEvents=%lu\n", FinalTable->Version, FinalTable->NumberOfEvents); + UT_ASSERT_TRUE (FinalTable->NumberOfEvents > 0); + + CurrentEvent = (UINT8 *)(FinalTable + 1); + EventType = 0; + EventSize = 0; + EventData = NULL; + + for (Index = 0; Index < FinalTable->NumberOfEvents; Index++) { + if (!TcgLogTestAdvanceEvent ( + &CurrentEvent, + (UINT8 *)(UINTN)MAX_ADDRESS, + NULL, + &EventType, + &EventSize, + &EventData + )) + { + UT_LOG_ERROR ("AdvanceEvent failed at index %lu\n", Index); + return UNIT_TEST_ERROR_TEST_FAILED; + } + } + + UT_LOG_INFO ("Last FinalEventLog entry: type=0x%x size=%u\n", EventType, EventSize); + UT_ASSERT_EQUAL (EventType, EV_NO_ACTION); + UT_ASSERT_NOT_NULL (EventData); + UT_ASSERT_TRUE (EventSize >= sizeof (TCG_LOG_TRUNCATION_EVENT_STRING)); + UT_ASSERT_MEM_EQUAL (EventData, TCG_LOG_TRUNCATION_EVENT_STRING, sizeof (TCG_LOG_TRUNCATION_EVENT_STRING)); + + return UNIT_TEST_PASSED; +} + +/** + Test that a snapshot of the event log plus the FinalEventLog entries + exactly reconstructs a later snapshot of the event log. + + After Tcg2Dxe begins maintaining the FinalEventLog (triggered by the first + call to GetEventLog), every subsequent event is appended to both the normal + event log and the FinalEventLog. Therefore: + + Snapshot1 + FinalEventLog_entries == Snapshot2 + + where Snapshot1 is the normal log captured immediately after the first + GetEventLog call and Snapshot2 is the normal log captured after additional + events have been logged. + + @param[in] Context Unit test context (unused). + + @retval UNIT_TEST_PASSED Reconstruction matches. + @retval UNIT_TEST_ERROR_TEST_FAILED Assertion failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestSnapshotPlusFinalMatchesEventLog ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS LogLocation1; + EFI_PHYSICAL_ADDRESS LastEntry1; + EFI_PHYSICAL_ADDRESS LogLocation2; + EFI_PHYSICAL_ADDRESS LastEntry2; + BOOLEAN Truncated; + EFI_TCG2_FINAL_EVENTS_TABLE *FinalTable; + UINT8 *Snapshot; + UINTN SnapshotSize1; + UINTN SnapshotSize2; + UINTN FinalEntriesSize; + UINT8 *FinalEntriesStart; + UINT8 *LogPtr; + UINT64 Index; + + // First snapshot. Also activates FinalEventLog logging. + Status = mTcg2Protocol->GetEventLog ( + mTcg2Protocol, + EFI_TCG2_EVENT_LOG_FORMAT_TCG_2, + &LogLocation1, + &LastEntry1, + &Truncated + ); + + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_FALSE (Truncated); + + // Snapshot length runs from LogLocation1 to one byte past LastEntry1. + LogPtr = (UINT8 *)(UINTN)LastEntry1; + if (!TcgLogTestAdvanceEvent ( + &LogPtr, + (UINT8 *)(UINTN)MAX_ADDRESS, + NULL, + NULL, + NULL, + NULL + )) + { + UT_LOG_ERROR ("AdvanceEvent failed past LastEntry1\n"); + return UNIT_TEST_ERROR_TEST_FAILED; + } + + SnapshotSize1 = (UINTN)LogPtr - (UINTN)LogLocation1; + UT_LOG_INFO ("Snapshot1: base=0x%lx size=%u\n", LogLocation1, SnapshotSize1); + + Snapshot = AllocateCopyPool (SnapshotSize1, (VOID *)(UINTN)LogLocation1); + UT_ASSERT_NOT_NULL (Snapshot); + + // Log a small number of additional events. Few enough not to trigger + // scaling, but enough to make the test meaningful. + for (Index = 0; Index < MAX_NUM_EXTRA_EVENTS; Index++) { + Status = TcgLogTestLogSingleEvent (mTcg2Protocol); + if (EFI_ERROR (Status)) { + UT_LOG_ERROR ("LogSingleEvent %u failed: %r\n", Index, Status); + FreePool (Snapshot); + return UNIT_TEST_ERROR_TEST_FAILED; + } + } + + // Retrieve the FinalEventLog from the system configuration table. + FinalTable = NULL; + Status = EfiGetSystemConfigurationTable (&gEfiTcg2FinalEventsTableGuid, (VOID **)&FinalTable); + if (EFI_ERROR (Status) || (FinalTable == NULL)) { + UT_LOG_ERROR ("FinalEventsTable lookup failed: %r\n", Status); + FreePool (Snapshot); + return UNIT_TEST_ERROR_TEST_FAILED; + } + + UT_LOG_INFO ("FinalEventsTable: NumberOfEvents=%lu\n", FinalTable->NumberOfEvents); + UT_ASSERT_EQUAL (FinalTable->NumberOfEvents, MAX_NUM_EXTRA_EVENTS); + + // Walk all FinalEventLog entries to compute their combined byte size. + FinalEntriesStart = (UINT8 *)(FinalTable + 1); + LogPtr = FinalEntriesStart; + for (Index = 0; Index < FinalTable->NumberOfEvents; Index++) { + if (!TcgLogTestAdvanceEvent ( + &LogPtr, + (UINT8 *)(UINTN)MAX_ADDRESS, + NULL, + NULL, + NULL, + NULL + )) + { + UT_LOG_ERROR ("AdvanceEvent failed at FinalEventLog index %lu\n", Index); + FreePool (Snapshot); + return UNIT_TEST_ERROR_TEST_FAILED; + } + } + + FinalEntriesSize = (UINTN)LogPtr - (UINTN)FinalEntriesStart; + UT_LOG_INFO ("FinalEventLog entries total bytes: %u\n", FinalEntriesSize); + + // Second snapshot. + Status = mTcg2Protocol->GetEventLog ( + mTcg2Protocol, + EFI_TCG2_EVENT_LOG_FORMAT_TCG_2, + &LogLocation2, + &LastEntry2, + &Truncated + ); + + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_FALSE (Truncated); + + LogPtr = (UINT8 *)(UINTN)LastEntry2; + if (!TcgLogTestAdvanceEvent ( + &LogPtr, + (UINT8 *)(UINTN)MAX_ADDRESS, + NULL, + NULL, + NULL, + NULL + )) + { + UT_LOG_ERROR ("AdvanceEvent failed past LastEntry2\n"); + FreePool (Snapshot); + return UNIT_TEST_ERROR_TEST_FAILED; + } + + SnapshotSize2 = (UINTN)LogPtr - (UINTN)LogLocation2; + UT_LOG_INFO ("Snapshot2: base=0x%lx size=%u\n", LogLocation2, SnapshotSize2); + + // Snapshot2 must be exactly Snapshot1 followed by the FinalEventLog entries. + UT_ASSERT_EQUAL (SnapshotSize2, SnapshotSize1 + FinalEntriesSize); + UT_ASSERT_MEM_EQUAL ((VOID *)(UINTN)LogLocation2, Snapshot, SnapshotSize1); + UT_ASSERT_MEM_EQUAL ((VOID *)((UINTN)LogLocation2 + SnapshotSize1), FinalEntriesStart, FinalEntriesSize); + + FreePool (Snapshot); + return UNIT_TEST_PASSED; +} + +/** + Save the unit test framework state and perform a cold reboot. + + @param[in] Context Unit test context (unused). +**/ +STATIC +VOID +EFIAPI +SaveAndReboot ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SaveFrameworkState (NULL, 0); + gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL); +} + +/** + Cleanup for TestPostReadyToBootScaling: enable the DXE pre-ReadyToBoot test + for the next boot, then save and reboot so the DXE driver runs before + ReadyToBoot on the second boot. + + @param[in] Context Unit test context (unused). +**/ +STATIC +VOID +EFIAPI +EnableDxeTestAndReboot ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + + if (mTcgLogTestProtocol != NULL) { + Status = mTcgLogTestProtocol->Enable (mTcgLogTestProtocol, TRUE); + DEBUG ((DEBUG_INFO, "%a: Enable (TRUE) - %r\n", __func__, Status)); + } else { + DEBUG ((DEBUG_ERROR, "%a: mTcgLogTestProtocol is NULL, cannot enable\n", __func__)); + } + + SaveAndReboot (Context); +} + +/** + Prerequisite: locate the TCG2 and TcgLogTest protocols. + + @param[in] Context Unit test context (unused). + + @retval UNIT_TEST_PASSED Protocols located. + @retval UNIT_TEST_ERROR_PREREQUISITE_NOT_MET Protocol not found. +**/ +UNIT_TEST_STATUS +EFIAPI +LocateProtocols ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + + Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **)&mTcg2Protocol); + if (EFI_ERROR (Status)) { + return UNIT_TEST_ERROR_PREREQUISITE_NOT_MET; + } + + Status = gBS->LocateProtocol (&gTcgLogTestProtocolGuid, NULL, (VOID **)&mTcgLogTestProtocol); + if (EFI_ERROR (Status)) { + return UNIT_TEST_ERROR_PREREQUISITE_NOT_MET; + } + + return UNIT_TEST_PASSED; +} + +/** + Entry point for TcgLogTestApp. + + @param[in] ImageHandle Image handle. + @param[in] SystemTable Pointer to the System Table. + + @retval EFI_SUCCESS Tests dispatched and framework freed. + @retval Other Framework initialization failed. +**/ +EFI_STATUS +EFIAPI +TcgLogTestAppEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + UNIT_TEST_FRAMEWORK_HANDLE Framework; + UNIT_TEST_SUITE_HANDLE Suite; + + Framework = NULL; + + Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: InitUnitTestFramework failed: %r\n", __func__, Status)); + return Status; + } + + Status = CreateUnitTestSuite (&Suite, Framework, "TCG Log Scaling Tests", "TcgLogTest", NULL, NULL); + if (EFI_ERROR (Status)) { + goto Done; + } + + AddTestCase (Suite, "Post-ReadyToBoot scaling succeeds", "PostRtbScaling", TestPostReadyToBootScaling, LocateProtocols, NULL, NULL); + AddTestCase (Suite, "Scaling occurs X times before truncating", "ScaleLimitTruncates", TestScaleLimitTruncatesLog, LocateProtocols, EnableDxeTestAndReboot, NULL); + AddTestCase (Suite, "Snapshot plus FinalEventLog matches full log", "SnapshotPlusFinalMatches", TestSnapshotPlusFinalMatchesEventLog, LocateProtocols, NULL, NULL); + AddTestCase (Suite, "FinalEventLog gets truncation marker", "FinalEventLogTruncates", TestFinalEventLogTruncationMarker, LocateProtocols, NULL, NULL); + AddTestCase (Suite, "Pre-ReadyToBoot DXE results contain PASS", "PreRtbResults", TestPreReadyToBootScaling, LocateProtocols, SaveAndReboot, NULL); + + Status = RunAllTestSuites (Framework); + +Done: + if (Framework != NULL) { + FreeUnitTestFramework (Framework); + } + + return Status; +} diff --git a/SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.inf b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.inf new file mode 100644 index 00000000000..96bcd9c38ef --- /dev/null +++ b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.inf @@ -0,0 +1,46 @@ +## @file +# UEFI Shell application that validates TCG2 event log dynamic scaling +# after ReadyToBoot using the UnitTest framework. +# +# Copyright (c), Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = TcgLogTestApp + FILE_GUID = 1F3A9C52-6E8B-4D07-B2A3-8C4E7F1D5E90 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = TcgLogTestAppEntry + +[Sources] + TcgLogTestApp.c + TcgLogTestCommon.c + TcgLogTestCommon.h + TcgLogTest.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + MemoryAllocationLib + UefiApplicationEntryPoint + UefiBootServicesTableLib + UefiLib + UefiRuntimeServicesTableLib + UnitTestLib + +[Protocols] + gEfiTcg2ProtocolGuid ## CONSUMES + gTcgLogTestProtocolGuid ## CONSUMES + gEfiTcg2FinalEventsTableGuid ## CONSUMES ## SystemTable + +[Guids] + gTcg2EventLogScaledGuid ## CONSUMES ## Event diff --git a/SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.c b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.c new file mode 100644 index 00000000000..60f44bec6e1 --- /dev/null +++ b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.c @@ -0,0 +1,372 @@ +/** @file + TCG Log Test common implementation shared by TcgLogTestDxe and TcgLogTestApp. + + Copyright (c), Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TcgLogTestCommon.h" + +#define TCG_LOG_TEST_PCR_INDEX 8 +#define TCG_LOG_TEST_EVENT_TYPE EV_NO_ACTION +#define TCG_LOG_TEST_EVENT_PAYLOAD "TcgLogTestDxeEvent" + +/** + Allocate and initialize an EFI_TCG2_EVENT structure with a fixed payload. + + @param[out] Event On success, pointer to the allocated event. Caller must + free with FreePool(). + + @retval EFI_SUCCESS Event allocated and initialized. + @retval EFI_OUT_OF_RESOURCES Allocation failed. +**/ +STATIC +EFI_STATUS +TcgLogTestBuildEvent ( + OUT EFI_TCG2_EVENT **Event + ) +{ + UINT32 PayloadSize; + UINT32 TotalSize; + EFI_TCG2_EVENT *TestEvent; + + PayloadSize = (UINT32)sizeof (TCG_LOG_TEST_EVENT_PAYLOAD); + TotalSize = (UINT32)(sizeof (EFI_TCG2_EVENT) - sizeof (TestEvent->Event) + PayloadSize); + + TestEvent = AllocateZeroPool (TotalSize); + if (TestEvent == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + TestEvent->Size = TotalSize; + TestEvent->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER); + TestEvent->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION; + TestEvent->Header.PCRIndex = TCG_LOG_TEST_PCR_INDEX; + TestEvent->Header.EventType = TCG_LOG_TEST_EVENT_TYPE; + + CopyMem (TestEvent->Event, TCG_LOG_TEST_EVENT_PAYLOAD, PayloadSize); + + *Event = TestEvent; + return EFI_SUCCESS; +} + +/** + Log a single event via the TCG2 protocol. + + @param[in] Tcg2Protocol TCG2 protocol instance. + @param[in] Event Pre-built TCG2 event structure. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. +**/ +STATIC +EFI_STATUS +TcgLogTestLogEvent ( + IN EFI_TCG2_PROTOCOL *Tcg2Protocol, + IN EFI_TCG2_EVENT *Event + ) +{ + return Tcg2Protocol->HashLogExtendEvent ( + Tcg2Protocol, + 0, + (EFI_PHYSICAL_ADDRESS)(UINTN)(CONST CHAR8 *)TCG_LOG_TEST_EVENT_PAYLOAD, + sizeof (TCG_LOG_TEST_EVENT_PAYLOAD), + Event + ); +} + +/** + Advance one entry in the event log. + + @param[in,out] CurrentEvent On entry, points to the start of the event (PCRIndex). + On success, updated to point to the next event. + @param[in] LogEnd One byte past the end of the log buffer. + @param[out] PcrIndex PCRIndex of the parsed event. + @param[out] EventType EventType of the parsed event. + @param[out] EventSize Size of the event data payload. + @param[out] EventData Pointer to the event data payload. + + @retval TRUE Event parsed successfully and CurrentEvent updated. + @retval FALSE Invalid pointers, buffer, or digest algorithm. +**/ +BOOLEAN +TcgLogTestAdvanceEvent ( + IN OUT UINT8 **CurrentEvent, + IN UINT8 *LogEnd, + OUT UINT32 *PcrIndex OPTIONAL, + OUT UINT32 *EventType OPTIONAL, + OUT UINT32 *EventSize OPTIONAL, + OUT UINT8 **EventData OPTIONAL + ) +{ + UINT32 DigestCount; + UINT32 DigestIndex; + UINT16 AlgId; + UINT32 DigestLen; + UINT32 Size; + UINT8 *EventPtr; + + // Verify the required pointers are valid + if ((CurrentEvent == NULL) || (LogEnd == NULL)) { + DEBUG ((DEBUG_ERROR, "%a: Invalid input parameters\n", __func__)); + return FALSE; + } + + // Start on the current event. + EventPtr = *CurrentEvent; + + // Verify there are 8 bytes (PCRIndex (4 bytes) + EventType (4 bytes)) + // in the log before attempting to read. + if ((UINTN)(LogEnd - EventPtr) < sizeof (UINT32) + sizeof (UINT32)) { + DEBUG ((DEBUG_ERROR, "%a: PCRIndex & EventType invalid\n", __func__)); + return FALSE; + } + + // Store the PCRIndex, if provided. + if (PcrIndex != NULL) { + *PcrIndex = ReadUnaligned32 ((UINT32 *)EventPtr); + } + + // Store the EventType, if provided. + if (EventType != NULL) { + *EventType = ReadUnaligned32 ((UINT32 *)(EventPtr + sizeof (UINT32))); + } + + // Move the pointer past the PcrIndex and EventType. + EventPtr += sizeof (UINT32) + sizeof (UINT32); + + // Verify there are 4 bytes (DigestCount (4 bytes)) in the log before + // attempting to read. + // TPML_DIGEST_VALUES = DigestCount followed by (AlgId + Digest) pairs. + if ((UINTN)(LogEnd - EventPtr) < sizeof (UINT32)) { + DEBUG ((DEBUG_ERROR, "%a: DigestCount invalid\n", __func__)); + return FALSE; + } + + // Acquire the DigestCount. + DigestCount = ReadUnaligned32 ((UINT32 *)EventPtr); + + // Move the pointer past the DigestCount. + EventPtr += sizeof (UINT32); + + // Loop through the number of digests. + for (DigestIndex = 0; DigestIndex < DigestCount; DigestIndex++) { + // Verify there are 2 bytes (AlgId (2 bytes)) in the log + // before attempting to read. + if ((UINTN)(LogEnd - EventPtr) < sizeof (UINT16)) { + DEBUG ((DEBUG_ERROR, "%a: AlgId invalid\n", __func__)); + return FALSE; + } + + // Acquire the AlgId. + AlgId = ReadUnaligned16 ((UINT16 *)EventPtr); + + // Move the pointer past the AlgId. + EventPtr += sizeof (UINT16); + + // DigestLen depends on the AlgId. + switch (AlgId) { + case TPM_ALG_SHA1: + DigestLen = SHA1_DIGEST_SIZE; + break; + case TPM_ALG_SHA256: + DigestLen = SHA256_DIGEST_SIZE; + break; + case TPM_ALG_SHA384: + DigestLen = SHA384_DIGEST_SIZE; + break; + case TPM_ALG_SHA512: + DigestLen = SHA512_DIGEST_SIZE; + break; + case TPM_ALG_SM3_256: + DigestLen = SM3_256_DIGEST_SIZE; + break; + default: + DEBUG ((DEBUG_ERROR, "%a: Unknown AlgId 0x%x\n", __func__, AlgId)); + return FALSE; + } + + // Verify there are DigestLen bytes in the log. + if ((UINTN)(LogEnd - EventPtr) < DigestLen) { + DEBUG ((DEBUG_ERROR, "%a: DigestLen invalid\n", __func__)); + return FALSE; + } + + // Move the pointer past the Digest based on the DigestLen. + EventPtr += DigestLen; + } + + // Verify there are 4 bytes (EventSize (4 bytes)) in the log + // before attempting to read. + if ((UINTN)(LogEnd - EventPtr) < sizeof (UINT32)) { + DEBUG ((DEBUG_ERROR, "%a: EventSize invalid\n", __func__)); + return FALSE; + } + + // Acquire the size of the event. + Size = ReadUnaligned32 ((UINT32 *)EventPtr); + + // Move the pointer past the event size + EventPtr += sizeof (UINT32); + + // Verify there are EventSize bytes in the log. + if ((UINTN)(LogEnd - EventPtr) < Size) { + DEBUG ((DEBUG_ERROR, "%a: Size of event invalid\n", __func__)); + return FALSE; + } + + // Store the EventSize, if provided. + if (EventSize != NULL) { + *EventSize = Size; + } + + // Store the EventData, if provided. + if (EventData != NULL) { + *EventData = EventPtr; + } + + // Move the pointer to next Event. + EventPtr += Size; + + // Update the current event pointer. + *CurrentEvent = EventPtr; + + return TRUE; +} + +/** + Notification callback registered on gTcg2EventLogScaledGuid. Sets the BOOLEAN + pointed to by Context to TRUE. + + @param[in] Event Event handle (unused). + @param[in] Context Pointer to a BOOLEAN to flip when the event fires. +**/ +STATIC +VOID +EFIAPI +TcgLogTestScaleNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + if (Context != NULL) { + *(BOOLEAN *)Context = TRUE; + } +} + +/** + Log events until Tcg2Dxe signals that the event log was dynamically scaled + or until an error is returned. + + @param[in] Tcg2Protocol TCG2 protocol instance. + @param[out] Scaled TRUE if scaling was detected. + + @retval EFI_SUCCESS Scaling detected and events logged successfully. + @retval EFI_INVALID_PARAMETER One or more invalid parameters. +**/ +EFI_STATUS +TcgLogTestLogEventsUntilScaled ( + IN EFI_TCG2_PROTOCOL *Tcg2Protocol, + OUT BOOLEAN *Scaled + ) +{ + EFI_STATUS Status; + EFI_EVENT ScaleEvent; + EFI_TCG2_EVENT *Event; + BOOLEAN LogScaled; + + // Validate the input parameters. + if ((Tcg2Protocol == NULL) || (Scaled == NULL)) { + return EFI_INVALID_PARAMETER; + } + + *Scaled = FALSE; + LogScaled = FALSE; + Event = NULL; + + // Build a test event. + Status = TcgLogTestBuildEvent (&Event); + if (EFI_ERROR (Status)) { + return Status; + } + + // Register a notification callback for when the TCG log gets scaled. + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + TcgLogTestScaleNotify, + &LogScaled, + &gTcg2EventLogScaledGuid, + &ScaleEvent + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: CreateEventEx failed - %r\n", __func__, Status)); + goto Exit; + } + + // Log events until the scale callback fires or LogEvent returns an error. + while (!LogScaled) { + Status = TcgLogTestLogEvent (Tcg2Protocol, Event); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: LogEvent failed - %r\n", __func__, Status)); + break; + } + } + + gBS->CloseEvent (ScaleEvent); + + if (LogScaled) { + *Scaled = TRUE; + DEBUG ((DEBUG_INFO, "%a: Log scaled\n", __func__)); + Status = EFI_SUCCESS; + } + +Exit: + FreePool (Event); + return Status; +} + +/** + Log a single fixed test event via the TCG2 protocol. + + @param[in] Tcg2Protocol TCG2 protocol instance. + + @retval EFI_SUCCESS Event logged. + @retval EFI_INVALID_PARAMETER NULL argument. + @retval EFI_OUT_OF_RESOURCES Allocation failed. + @retval Other HashLogExtendEvent failure. +**/ +EFI_STATUS +TcgLogTestLogSingleEvent ( + IN EFI_TCG2_PROTOCOL *Tcg2Protocol + ) +{ + EFI_STATUS Status; + EFI_TCG2_EVENT *Event; + + if (Tcg2Protocol == NULL) { + return EFI_INVALID_PARAMETER; + } + + Event = NULL; + Status = TcgLogTestBuildEvent (&Event); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = TcgLogTestLogEvent (Tcg2Protocol, Event); + FreePool (Event); + return Status; +} diff --git a/SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.h b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.h new file mode 100644 index 00000000000..93b1370fcbe --- /dev/null +++ b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.h @@ -0,0 +1,70 @@ +/** @file + TCG Log Test common function declarations shared by TcgLogTestDxe and + TcgLogTestApp. + + Copyright (c), Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef TCG_LOG_TEST_COMMON_H_ +#define TCG_LOG_TEST_COMMON_H_ + +#include +#include +#include + +/** + Advance one entry in the event log. + + @param[in,out] CurrentEvent On entry, points to the start of the event (PCRIndex). + On success, updated to point to the next event. + @param[in] LogEnd One byte past the end of the log buffer. + @param[out] PcrIndex PCRIndex of the parsed event. + @param[out] EventType EventType of the parsed event. + @param[out] EventSize Size of the event data payload. + @param[out] EventData Pointer to the event data payload. + + @retval TRUE Event parsed successfully and CurrentEvent updated. + @retval FALSE Invalid pointers, buffer, or digest algorithm. +**/ +BOOLEAN +TcgLogTestAdvanceEvent ( + IN OUT UINT8 **CurrentEvent, + IN UINT8 *LogEnd, + OUT UINT32 *PcrIndex OPTIONAL, + OUT UINT32 *EventType OPTIONAL, + OUT UINT32 *EventSize OPTIONAL, + OUT UINT8 **EventData OPTIONAL + ); + +/** + Log events via TCG2 until the event log base address changes (dynamic + scaling) or an error is returned. + + @param[in] Tcg2 TCG2 protocol instance. + @param[out] Scaled TRUE if scaling was detected. + + @retval EFI_SUCCESS Scaling detected. + @retval EFI_INVALID_PARAMETER NULL argument. +**/ +EFI_STATUS +TcgLogTestLogEventsUntilScaled ( + IN EFI_TCG2_PROTOCOL *Tcg2, + OUT BOOLEAN *Scaled + ); + +/** + Log a single fixed test event via the TCG2 protocol. + + @param[in] Tcg2 TCG2 protocol instance. + + @retval EFI_SUCCESS Event logged. + @retval EFI_INVALID_PARAMETER NULL argument. + @retval Other HashLogExtendEvent failure. +**/ +EFI_STATUS +TcgLogTestLogSingleEvent ( + IN EFI_TCG2_PROTOCOL *Tcg2 + ); + +#endif // TCG_LOG_TEST_COMMON_H_ diff --git a/SecurityPkg/Tcg/TcgLogTest/TcgLogTestDxe.c b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestDxe.c new file mode 100644 index 00000000000..f27be3672ca --- /dev/null +++ b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestDxe.c @@ -0,0 +1,261 @@ +/** @file + DXE driver that validates TCG2 event log dynamic scaling before ReadyToBoot. + + On entry the driver checks the NV variable TcgLogTestEnable. If not set, + the driver installs the protocol (with SetEnabled only) and returns without + running any tests. When the variable is set, the driver runs the + pre-ReadyToBoot scaling test, logs results into an internal buffer, clears + the variable, and installs the protocol so TcgLogTestApp can retrieve logs. + + Copyright (c), Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TcgLogTest.h" +#include "TcgLogTestCommon.h" + +#define TCG_LOG_TEST_MAX_LOG_SIZE 4096 + +STATIC CHAR8 mLogBuffer[TCG_LOG_TEST_MAX_LOG_SIZE]; +STATIC UINTN mLogOffset = 0; +STATIC EFI_TCG2_PROTOCOL *mTcg2Protocol = NULL; +STATIC EFI_HANDLE mTcgLogTestHandle = NULL; + +/** + Append a formatted message to the internal log buffer. + + @param[in] Format Printf-style format string. + @param[in] ... Variable arguments for the format string. +**/ +STATIC +VOID +EFIAPI +LogAppend ( + IN CONST CHAR8 *Format, + ... + ) +{ + VA_LIST Args; + UINTN Remaining; + UINTN Written; + + if (mLogOffset >= TCG_LOG_TEST_MAX_LOG_SIZE - 1) { + return; + } + + Remaining = TCG_LOG_TEST_MAX_LOG_SIZE - mLogOffset - 1; + + VA_START (Args, Format); + Written = AsciiVSPrint (mLogBuffer + mLogOffset, Remaining, Format, Args); + VA_END (Args); + + mLogOffset += Written; +} + +/** + Protocol function: retrieve the pre-ReadyToBoot test log. + + @param[in] This Protocol instance. + @param[out] LogBuffer On success, pointer to the internal log buffer. + @param[out] LogSize On success, size of the log data in bytes. + + @retval EFI_SUCCESS Log retrieved. + @retval EFI_INVALID_PARAMETER LogBuffer or LogSize is NULL. + @retval EFI_NOT_STARTED The test has not run this boot. +**/ +STATIC +EFI_STATUS +EFIAPI +TcgLogTestGetLog ( + IN TCG_LOG_TEST_PROTOCOL *This, + OUT CHAR8 **LogBuffer, + OUT UINTN *LogSize + ) +{ + if ((LogBuffer == NULL) || (LogSize == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (mLogOffset == 0) { + DEBUG ((DEBUG_ERROR, "%a: Log is empty.\n", __func__)); + return EFI_NOT_STARTED; + } + + *LogBuffer = mLogBuffer; + *LogSize = mLogOffset + 1; + return EFI_SUCCESS; +} + +/** + Protocol function: enable or disable the DXE test for the next boot. + + @param[in] This Protocol instance. + @param[in] Enable TRUE to enable, FALSE to disable. + + @retval EFI_SUCCESS Variable updated successfully. + @retval Other SetVariable failure. +**/ +STATIC +EFI_STATUS +EFIAPI +TcgLogTestEnable ( + IN TCG_LOG_TEST_PROTOCOL *This, + IN BOOLEAN Enable + ) +{ + BOOLEAN Dummy; + + if (Enable) { + Dummy = TRUE; + // Create the variable to signal the test should run. + return gRT->SetVariable ( + TCG_LOG_TEST_ENABLE_VARIABLE_NAME, + &gTcgLogTestProtocolGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof (Dummy), + &Dummy + ); + } else { + // Delete the variable entirely. + return gRT->SetVariable ( + TCG_LOG_TEST_ENABLE_VARIABLE_NAME, + &gTcgLogTestProtocolGuid, + 0, + 0, + NULL + ); + } +} + +STATIC TCG_LOG_TEST_PROTOCOL mTcgLogTestProtocol = { + TcgLogTestGetLog, + TcgLogTestEnable +}; + +/** + Check whether the NV enable variable exists. + + @retval TRUE Variable exists (test is enabled). + @retval FALSE Variable absent. +**/ +STATIC +BOOLEAN +IsTestEnabled ( + VOID + ) +{ + EFI_STATUS Status; + BOOLEAN Value; + UINTN Size; + + Size = sizeof (Value); + Status = gRT->GetVariable ( + TCG_LOG_TEST_ENABLE_VARIABLE_NAME, + &gTcgLogTestProtocolGuid, + NULL, + &Size, + &Value + ); + + if (EFI_ERROR (Status)) { + return FALSE; + } + + return TRUE; +} + +/** + Exercise dynamic scaling before ReadyToBoot. Verifies that scaling occurs + (Tcg2Dxe signals gTcg2EventLogScaledGuid). +**/ +STATIC +VOID +TestPreReadyToBootScaling ( + VOID + ) +{ + EFI_STATUS Status; + BOOLEAN Scaled; + + Status = TcgLogTestLogEventsUntilScaled (mTcg2Protocol, &Scaled); + if (EFI_ERROR (Status) || !Scaled) { + DEBUG ((DEBUG_ERROR, "%a: LogEventsUntilScaled failed - %r, Scaled=%d\n", __func__, Status, Scaled)); + LogAppend ("FAIL: Pre-ReadyToBoot: LogEventsUntilScaled - %r\n", Status); + return; + } + + DEBUG ((DEBUG_INFO, "%a: Pre-ReadyToBoot scaling succeeded\n", __func__)); + LogAppend ("PASS: Pre-ReadyToBoot scaling succeeded\n"); +} + +/** + Entry point for TcgLogTestDxe. + + @param[in] ImageHandle Image handle. + @param[in] SystemTable Pointer to the System Table. + + @retval EFI_SUCCESS Driver initialized and protocol installed. +**/ +EFI_STATUS +EFIAPI +TcgLogTestDxeEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // Install the protocol so the TcgLogTestApp can enable the test and/or acquire the logs. + Status = gBS->InstallProtocolInterface ( + &mTcgLogTestHandle, + &gTcgLogTestProtocolGuid, + EFI_NATIVE_INTERFACE, + &mTcgLogTestProtocol + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: InstallProtocolInterface failed: %r\n", __func__, Status)); + return Status; + } + + DEBUG ((DEBUG_INFO, "%a: Protocol installed, checking enable state\n", __func__)); + + // Only run the test if it has been enabled. + if (!IsTestEnabled ()) { + DEBUG ((DEBUG_INFO, "%a: Test not enabled, skipping\n", __func__)); + return EFI_SUCCESS; + } + + DEBUG ((DEBUG_INFO, "%a: Test enabled, running pre-ReadyToBoot test\n", __func__)); + + // Clear the enable variable so we don't re-run on the next boot. + Status = TcgLogTestEnable (&mTcgLogTestProtocol, FALSE); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to clear enable variable: %r\n", __func__, Status)); + } + + Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **)&mTcg2Protocol); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to locate TCG2 protocol: %r\n", __func__, Status)); + LogAppend ("FAIL: TCG2 protocol not found - %r\n", Status); + return EFI_SUCCESS; + } + + // Run the pre-ReadyToBoot scaling test. + TestPreReadyToBootScaling (); + + return EFI_SUCCESS; +} diff --git a/SecurityPkg/Tcg/TcgLogTest/TcgLogTestDxe.inf b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestDxe.inf new file mode 100644 index 00000000000..ead24bcd120 --- /dev/null +++ b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestDxe.inf @@ -0,0 +1,50 @@ +## @file +# DXE driver that validates TCG2 event log dynamic scaling before ReadyToBoot. +# +# Checks an NV variable to determine whether to run. If enabled, exercises +# pre-ReadyToBoot log scaling and records results via a local protocol that +# TcgLogTestApp retrieves post-boot. +# +# Copyright (c), Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = TcgLogTestDxe + FILE_GUID = B4D2F8A7-3E16-4C9B-A1F0-7D5E9B2C4A81 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = TcgLogTestDxeEntry + +[Sources] + TcgLogTestDxe.c + TcgLogTestCommon.c + TcgLogTestCommon.h + TcgLogTest.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + MemoryAllocationLib + PrintLib + UefiDriverEntryPoint + UefiBootServicesTableLib + UefiLib + UefiRuntimeServicesTableLib + +[Protocols] + gEfiTcg2ProtocolGuid ## CONSUMES + gTcgLogTestProtocolGuid ## PRODUCES + +[Guids] + gTcg2EventLogScaledGuid ## CONSUMES ## Event + +[Depex] + gEfiVariableArchProtocolGuid AND gEfiTcg2ProtocolGuid