From b1dd1c5fa6ad21772186ab151c3d71cf5c336e75 Mon Sep 17 00:00:00 2001 From: rdiaz Date: Fri, 8 May 2026 18:49:25 +0000 Subject: [PATCH 1/8] Implemented dynamic TCG log scaling in Tcg2Dxe. When the log would become truncated it instead now dynamically scales doubling the size each time. An ERROR log is reported that an increase to your base log size should occur such that scaling is not necessary. This is a precaution against platforms that log a lot and the addition of new hashing algorithms for PQC. The log is allocated in BootServices memory. The ACPI log is created on ReadyToBoot with logs being added to both until they would need to scale. In this instance a truncation event is added to the ACPI log to indicate that the log is no longer valid and/or may not contain the entirety of the log. This ACPI table is allocated in NVS memory. If the ACPI table was already allocated at the time of the ACPI log creation, it is uninstalled and reinstalled with the updated LAML and LASA PCDs. Tests were added via TcgLogTest which includes a DXE driver and a UEFI shelld UnitTest app. The DXE driver handles pre-ReadyToBoot tests while the TestApp handles post-ReadyToBoot tests as well as gathering the test results from the DXE driver. Markdown documents were created to detail the changes. --- SecurityPkg/SecurityPkg.dec | 7 + SecurityPkg/Tcg/Tcg2Dxe/README.md | 82 +++ SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c | 472 +++++++++++++++++- SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf | 2 + SecurityPkg/Tcg/TcgLogTest/README.md | 207 ++++++++ SecurityPkg/Tcg/TcgLogTest/TcgLogTest.h | 67 +++ SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.c | 383 ++++++++++++++ SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.inf | 43 ++ SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.c | 414 +++++++++++++++ SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.h | 74 +++ SecurityPkg/Tcg/TcgLogTest/TcgLogTestDxe.c | 268 ++++++++++ SecurityPkg/Tcg/TcgLogTest/TcgLogTestDxe.inf | 47 ++ 12 files changed, 2044 insertions(+), 22 deletions(-) create mode 100644 SecurityPkg/Tcg/Tcg2Dxe/README.md create mode 100644 SecurityPkg/Tcg/TcgLogTest/README.md create mode 100644 SecurityPkg/Tcg/TcgLogTest/TcgLogTest.h create mode 100644 SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.c create mode 100644 SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.inf create mode 100644 SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.c create mode 100644 SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.h create mode 100644 SecurityPkg/Tcg/TcgLogTest/TcgLogTestDxe.c create mode 100644 SecurityPkg/Tcg/TcgLogTest/TcgLogTestDxe.inf diff --git a/SecurityPkg/SecurityPkg.dec b/SecurityPkg/SecurityPkg.dec index 70d70da0e7e..3280ad887a5 100644 --- a/SecurityPkg/SecurityPkg.dec +++ b/SecurityPkg/SecurityPkg.dec @@ -301,6 +301,13 @@ # 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] + ## TCG Log Test protocol produced by TcgLogTestDxe. + # 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/Tcg/Tcg2Dxe/README.md b/SecurityPkg/Tcg/Tcg2Dxe/README.md new file mode 100644 index 00000000000..f6c80b79db4 --- /dev/null +++ b/SecurityPkg/Tcg/Tcg2Dxe/README.md @@ -0,0 +1,82 @@ +# Tcg2Dxe + +Tcg2Dxe is a DXE-phase UEFI driver that publishes the TCG2 protocol defined +by the TCG EFI Protocol Specification. It's 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 (plus a + reserved truncation marker) would exceed the current allocation + (`EventLogAreaStruct->Laml`). Space is reserved for the truncation marker + as long as the ACPI log has not yet been marked truncated. + +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. + +### Normal Log vs. ACPI Log vs. Final Events Log + +Tcg2Dxe maintains three distinct event log regions: + +| Log | Memory Type | Lifetime | Can Scale | +| --- | ----------- | -------- | --------- | +| **Normal log** | `EfiBootServicesData` | Available until `ExitBootServices` | Yes | +| **ACPI log** | `EfiACPIMemoryNVS` | Persistent | No | +| **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 **ACPI log** is created at `ReadyToBoot` by `GenerateAcpiLog`. It + allocates an `EfiACPIMemoryNVS` region equal to the **Normal log** size at that + point, copies the log contents, and updates the TPM2 ACPI table's + `LAML`/`LASA` fields so the OS can find it. If the TPM2 table was already + installed via Tcg2Acpi/Tcg2AcpiFfa, `GenerateAcpiLog` will uninstall and + reinstall the ACPI table with the updated LAML and LASA pointing to the + newly allocated NVS region. +- 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. + +After `ReadyToBoot`, every new event is also appended to the ACPI log. Because +the ACPI log's NVS allocation is fixed (the OS may already be referencing its +address), it cannot be reallocated. + +### Post-ReadyToBoot Truncation + +When dynamic scaling is triggered after `ReadyToBoot`: + +1. A `NO_ACTION` event with the payload `"TCG Event Log Truncated"` is + appended to the **ACPI log** to notify the OS that the ACPI-visible log is + now incomplete. +2. The ACPI log is marked truncated (`EventLogTruncated = TRUE`) so no further + events are written to it and no additional space is reserved for the + truncation marker. +3. The **normal log** is scaled as usual — it continues to grow and accept new + events. + +This means the normal log accessed via `GetEventLog` always has the complete +set of events, while the ACPI log visible to the OS may be truncated with a +marker at the end. diff --git a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c index c9e292159e3..24f498dc7f0 100644 --- a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c +++ b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c @@ -28,6 +28,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include // MU_CHANGE - Add a new protocol to support Log-only events. #include #include +#include // MU_CHANGE +#include // MU_CHANGE #include #include @@ -134,6 +136,31 @@ VARIABLE_TYPE mVariableType[] = { EFI_HANDLE mImageHandle; +// MU_CHANGE - [BEGIN] + +BOOLEAN mReadyToBoot = FALSE; +TCG_EVENT_LOG_AREA_STRUCT mAcpiEventLog; + +// String logged as a NO_ACTION event to mark the ACPI-visible TCG +// log as truncated when dynamic scaling occurs post ReadyToBoot. +#define TCG_LOG_TRUNCATION_EVENT_STRING "TCG Event Log Truncated" + +#pragma pack(1) + +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Flags; + UINT64 AddressOfControlArea; + UINT32 StartMethod; + UINT8 PlatformSpecificParameters[12]; + UINT32 Laml; + UINT64 Lasa; +} EFI_TPM2_ACPI_TABLE_V4; + +#pragma pack() + +// MU_CHANGE - [END] + /** Measure PE image into TPM log based on the authenticode image hashing in PE/COFF Specification 8.0 Appendix A. @@ -1002,6 +1029,32 @@ TcgDxeLogEvent ( EventLogAreaStruct->EventLogStarted = TRUE; } + // MU_CHANGE - [BEGIN] + + // + // Record to the ACPI event log + // + EventLogAreaStruct = &mAcpiEventLog; + + if (mReadyToBoot && !EventLogAreaStruct->EventLogTruncated) { + Status = TcgCommLogEvent ( + EventLogAreaStruct, + NewEventHdr, + NewEventHdrSize, + NewEventData, + NewEventSize + ); + + if (Status == EFI_OUT_OF_RESOURCES) { + EventLogAreaStruct->EventLogTruncated = TRUE; + return EFI_VOLUME_FULL; + } else if (Status == EFI_SUCCESS) { + EventLogAreaStruct->EventLogStarted = TRUE; + } + } + + // MU_CHANGE - [END] + // // If GetEventLog is called, record to FinalEventsTable, too. // @@ -1133,6 +1186,151 @@ 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. + +**/ +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; + + // Make sure EventLogAreaStruct is valid. + if (EventLogAreaStruct == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Double the length of the TCG log. + NewLaml = EventLogAreaStruct->Laml * 2; + Status = gBS->AllocatePages ( + AllocateAnyPages, + EfiBootServicesData, + EFI_SIZE_TO_PAGES (NewLaml), + &NewLasa + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to allocate new TCG event log\n")); + return EFI_OUT_OF_RESOURCES; + } + + // 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%x\n", OldLasa, OldLaml)); + DEBUG ((DEBUG_INFO, "NewLasa: 0x%lx, NewLaml: 0x%x\n", NewLasa, NewLaml)); + + // Update the EventLogAreaStruct. + EventLogAreaStruct->Lasa = NewLasa; + EventLogAreaStruct->Laml = NewLaml; + + // Once we reach ReadyToBoot, we do not want to free the old log regions, this is + // due to the ACPI table containing the old log pointer, we do not want to + // invalidate this memory. + gBS->FreePages (OldLasa, EFI_SIZE_TO_PAGES (OldLaml)); + + 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; + TCG_PCR_EVENT2_HDR NoActionEvent; + UINT32 EventHdrSize; + UINTN EventSize; + + // Make sure EventLogAreaStruct is valid. + if (EventLogAreaStruct == NULL) { + return FALSE; + } + + // Validate NewEventSize + NewEventHdrSize doesn't cause an overflow. + if (NewEventSize > MAX_ADDRESS - NewEventHdrSize) { + return FALSE; + } + + NewLogSize = NewEventHdrSize + NewEventSize; + + // Reserve space for the truncation NO_ACTION_EVENT so that the log can never + // fill past the point where the truncation marker would not fit. We only need + // to continue to reserve space as long as the ACPI event log is not truncated. + if (!mAcpiEventLog.EventLogTruncated) { + InitNoActionEvent (&NoActionEvent, sizeof (TCG_LOG_TRUNCATION_EVENT_STRING)); + EventHdrSize = (UINT32)(sizeof (NoActionEvent.PCRIndex) + + sizeof (NoActionEvent.EventType) + + GetDigestListBinSize ((UINT8 *)&NoActionEvent.Digests) + + sizeof (NoActionEvent.EventSize)); + EventSize = EventHdrSize + sizeof (TCG_LOG_TRUNCATION_EVENT_STRING); + + // Validate the NO_ACTION_EVENT doesn't cause an overflow. + if (EventSize > MAX_ADDRESS - NewLogSize) { + return FALSE; + } + + NewLogSize += EventSize; + } + + // Validate EventLogSize + NewLogSize doesn't cause an overflow. + if (NewLogSize > MAX_ADDRESS - EventLogAreaStruct->EventLogSize) { + 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, "Scaling post ReadyToBoot is invalid!\n")); + } + + return TRUE; + } + + return FALSE; +} + +// MU_CHANGE - [END] + /** Add a new entry to the Event Log. @@ -1150,13 +1348,20 @@ TcgDxeLogHashEvent ( IN UINT8 *NewEventData ) { - EFI_STATUS Status; - EFI_TPL OldTpl; - UINTN Index; - EFI_STATUS RetStatus; - TCG_PCR_EVENT2 TcgPcrEvent2; - UINT8 *DigestBuffer; - UINT32 *EventSizePtr; + // MU_CHANGE - [BEGIN] + + EFI_STATUS Status; + EFI_TPL OldTpl; + UINTN Index; + EFI_STATUS RetStatus; + TCG_PCR_EVENT2 TcgPcrEvent2; + UINT8 *DigestBuffer; + UINT32 *EventSizePtr; + BOOLEAN DynamicScalingNeeded; + TCG_PCR_EVENT2_HDR NoActionEvent; + UINT32 EventHdrSize; + + // MU_CHANGE - [END] RetStatus = EFI_SUCCESS; for (Index = 0; Index < sizeof (mTcg2EventInfo)/sizeof (mTcg2EventInfo[0]); Index++) { @@ -1195,6 +1400,54 @@ TcgDxeLogHashEvent ( EventSizePtr = CopyDigestListToBuffer (DigestBuffer, DigestList, mTcgDxeData.BsCap.ActivePcrBanks); CopyMem (EventSizePtr, &NewEventHdr->EventSize, sizeof (NewEventHdr->EventSize)); + // MU_CHANGE - [BEGIN] + + // Need to dynamically scale the TCG log before we enter a critical region. + DynamicScalingNeeded = TcgLogDynamicScalingNeeded ( + &mTcgDxeData.EventLogAreaStruct[Index], + sizeof (TcgPcrEvent2.PCRIndex) + sizeof (TcgPcrEvent2.EventType) + GetDigestListBinSize (DigestBuffer) + sizeof (TcgPcrEvent2.EventSize), + NewEventHdr->EventSize + ); + + // If scaling is needed and the ACPI event log as been created. Log a + // NO_ACTION_EVENT with the truncation string to the end of it to mark that + // it is now truncated. + if (DynamicScalingNeeded && mReadyToBoot && !mAcpiEventLog.EventLogTruncated) { + InitNoActionEvent (&NoActionEvent, sizeof (TCG_LOG_TRUNCATION_EVENT_STRING)); + EventHdrSize = (UINT32)(sizeof (NoActionEvent.PCRIndex) + + sizeof (NoActionEvent.EventType) + + GetDigestListBinSize ((UINT8 *)&NoActionEvent.Digests) + + sizeof (NoActionEvent.EventSize)); + + OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); + Status = TcgCommLogEvent ( + &mAcpiEventLog, + &NoActionEvent, + EventHdrSize, + (UINT8 *)TCG_LOG_TRUNCATION_EVENT_STRING, + sizeof (TCG_LOG_TRUNCATION_EVENT_STRING) + ); + gBS->RestoreTPL (OldTpl); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to log truncation NO_ACTION_EVENT!\n")); + return Status; + } + + mAcpiEventLog.EventLogTruncated = TRUE; + } + + // Only scale when needed. + if (DynamicScalingNeeded) { + 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 +1955,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; @@ -2575,6 +2825,161 @@ MeasureSecureBootPolicy ( return; } +// MU_CHANGE - [BEGIN] + +/** + Find the installed TPM2 ACPI table, uninstall it, update LAML/LASA, + and reinstall the table. + + @retval EFI_SUCCESS Table updated successfully. + @retval EFI_NOT_FOUND TPM2 table not found or protocols unavailable. + @retval Other Uninstall or reinstall failed. +**/ +STATIC +EFI_STATUS +UpdateTpm2AcpiTable ( + VOID + ) +{ + EFI_STATUS Status; + EFI_ACPI_SDT_PROTOCOL *AcpiSdt; + EFI_ACPI_TABLE_PROTOCOL *AcpiTable; + UINTN Index; + EFI_ACPI_SDT_HEADER *SdtHeader; + EFI_ACPI_TABLE_VERSION Version; + UINTN TableKey; + EFI_TPM2_ACPI_TABLE_V4 *Tpm2Table; + EFI_TPM2_ACPI_TABLE_V4 *TableCopy; + + Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (VOID **)&AcpiSdt); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "%a: AcpiSdt protocol not found - %r\n", __func__, Status)); + return EFI_NOT_FOUND; + } + + Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **)&AcpiTable); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "%a: AcpiTable protocol not found - %r\n", __func__, Status)); + return EFI_NOT_FOUND; + } + + // Walk installed ACPI tables looking for the TPM2 signature. + Index = 0; + while (TRUE) { + Status = AcpiSdt->GetAcpiTable (Index, &SdtHeader, &Version, &TableKey); + if (EFI_ERROR (Status)) { + // Reached the end of the table list without finding TPM2. + DEBUG ((DEBUG_WARN, "%a: TPM2 table not found\n", __func__)); + return EFI_NOT_FOUND; + } + + if (SdtHeader->Signature == EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE) { + break; + } + + Index++; + } + + // Verify the table is large enough to contain LAML/LASA. + if (SdtHeader->Length < sizeof (EFI_TPM2_ACPI_TABLE_V4)) { + DEBUG ((DEBUG_WARN, "%a: TPM2 table too small for LAML/LASA\n", __func__)); + return EFI_NOT_FOUND; + } + + Tpm2Table = (EFI_TPM2_ACPI_TABLE_V4 *)SdtHeader; + + // Make a copy of the table. + TableCopy = AllocateCopyPool (Tpm2Table->Header.Length, Tpm2Table); + if (TableCopy == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // Patch LAML/LASA in the copy. + TableCopy->Laml = PcdGet32 (PcdTpm2AcpiTableLaml); + TableCopy->Lasa = PcdGet64 (PcdTpm2AcpiTableLasa); + + // Uninstall the old table. + Status = AcpiTable->UninstallAcpiTable (AcpiTable, TableKey); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: UninstallAcpiTable failed - %r\n", __func__, Status)); + FreePool (TableCopy); + return Status; + } + + // Reinstall with updated values. + Status = AcpiTable->InstallAcpiTable ( + AcpiTable, + TableCopy, + TableCopy->Header.Length, + &TableKey + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: InstallAcpiTable failed - %r\n", __func__, Status)); + } else { + DEBUG ((DEBUG_INFO, "%a: TPM2 table updated (LAML=0x%x, LASA=0x%lx)\n", __func__, TableCopy->Laml, TableCopy->Lasa)); + } + + FreePool (TableCopy); + return Status; +} + +/** + Generate the ACPI TCG event log. + + @param[in, out] EventLogAreaStruct The event log area data structure. + + @retval EFI_SUCCESS Log was successfully allocated. + @retval EFI_OUT_OF_RESOURCES Allocation failed. + +**/ +STATIC +EFI_STATUS +GenerateAcpiLog ( + IN OUT TCG_EVENT_LOG_AREA_STRUCT *EventLogAreaStruct + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS AcpiLasa; + + // Allocate the NVS region for the ACPI log. + Status = gBS->AllocatePages ( + AllocateAnyPages, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES (EventLogAreaStruct->Laml), + &AcpiLasa + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to allocate NVS ACPI log region\n")); + return Status; + } + + // Copy the event log information. + mAcpiEventLog.EventLogFormat = EventLogAreaStruct->EventLogFormat; + mAcpiEventLog.Lasa = AcpiLasa; + mAcpiEventLog.Laml = EventLogAreaStruct->Laml; + mAcpiEventLog.EventLogSize = EventLogAreaStruct->EventLogSize; + mAcpiEventLog.LastEvent = (UINT8 *)(UINTN)AcpiLasa + EventLogAreaStruct->EventLogSize; + mAcpiEventLog.EventLogStarted = EventLogAreaStruct->EventLogStarted; + mAcpiEventLog.EventLogTruncated = FALSE; + mAcpiEventLog.Next800155EventOffset = EventLogAreaStruct->Next800155EventOffset; + + // Copy the data to the ACPI log. + CopyMem ((VOID*)(UINTN)AcpiLasa, (VOID*)(UINTN)EventLogAreaStruct->Lasa, mAcpiEventLog.Laml); + + // Update the PCDs. + PcdSet32S (PcdTpm2AcpiTableLaml, (UINT32)mAcpiEventLog.Laml); + PcdSet64S (PcdTpm2AcpiTableLasa, AcpiLasa); + + // Uninstall and reinstall the ACPI table with the updated LAML/LASA. + UpdateTpm2AcpiTable (); + + return Status; +} + +// MU_CHANGE - [END] + /** Ready to Boot Event notification handler. @@ -2593,9 +2998,32 @@ OnReadyToBoot ( { EFI_STATUS Status; TPM_PCRINDEX PcrIndex; + UINTN Index; // MU_CHANGE PERF_FUNCTION_BEGIN (); + // MU_CHANGE - [BEGIN] + + for (Index = 0; Index < ARRAY_SIZE (mTcg2EventInfo); Index++) { + if ((mTcgDxeData.BsCap.SupportedEventLogs & mTcg2EventInfo[Index].LogFormat) != 0) { + switch (mTcg2EventInfo[Index].LogFormat) { + case EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2: + // Do nothing for TCG1.2. + break; + case EFI_TCG2_EVENT_LOG_FORMAT_TCG_2: + // Only generate the ACPI log once. + if ((PcdGet8 (PcdTpm2AcpiTableRev) >= 4) && !mReadyToBoot) { + GenerateAcpiLog (&mTcgDxeData.EventLogAreaStruct[Index]); + } + break; + } + } + } + + mReadyToBoot = TRUE; + + // MU_CHANGE - [END] + // 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..d98d896b4ac 100644 --- a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf +++ b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf @@ -107,6 +107,8 @@ gEfiMpServiceProtocolGuid ## SOMETIMES_CONSUMES gEfiVariableWriteArchProtocolGuid ## NOTIFY gEfiResetNotificationProtocolGuid ## CONSUMES + gEfiAcpiTableProtocolGuid ## SOMETIMES_CONSUMES # MU_CHANGE + gEfiAcpiSdtProtocolGuid ## SOMETIMES_CONSUMES # MU_CHANGE [Pcd] gEfiSecurityPkgTokenSpaceGuid.PcdTpmPlatformClass ## SOMETIMES_CONSUMES diff --git a/SecurityPkg/Tcg/TcgLogTest/README.md b/SecurityPkg/Tcg/TcgLogTest/README.md new file mode 100644 index 00000000000..9e1a91cce07 --- /dev/null +++ b/SecurityPkg/Tcg/TcgLogTest/README.md @@ -0,0 +1,207 @@ +# 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 until the event log base address changes (indicating + scaling occurred). +2. Calls `TcgLogTestDumpEventLog` to dump every event in the log and verify + the normal log is **not** truncated. +3. 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 and collects pre-ReadyToBoot results from the DXE driver. + +#### Test: TestPostReadyToBootScaling + +Executed after `ReadyToBoot` in the UEFI shell. Exercises dynamic scaling +after `ReadyToBoot` has fired. + +1. Retrieves the TPM2 ACPI table's `LAML`/`LASA` values via the ACPI SDT + protocol. +2. Calls `TcgLogTestLogEventsUntilScaled` to repeatedly log `EV_NO_ACTION` + events to PCR 8 until the event log base address changes (indicating + scaling occurred). +3. Calls `TcgLogTestDumpEventLog` to dump every event in the log and verify + the normal log is **not** truncated. +4. Calls `CheckTruncationEvent` to verify the `"TCG Event Log Truncated"` + `NO_ACTION` marker **is** present in the ACPI log (since the ACPI log + cannot scale and should have been marked truncated). + +#### Test: TestPreReadyToBootResults + +Verifies the DXE driver's pre-ReadyToBoot results. + +1. Locates `TCG_LOG_TEST_PROTOCOL` and calls `GetLog`. +2. Dumps the DXE 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 (TestApp Test) +├── 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. +│ ├── Calls TestPostReadyToBootScaling(): +│ │ ├── Calls TcgLogTestLogEventsUntilScaled() to scale the event log. +│ │ ├── Verifies the log was not truncated. +│ │ ├── Checks ACPI truncation event. +│ │ └── PASS. +│ └── Test Cleanup: +│ └── Calls EnableDxeTestAndReboot(). +│ ├── Calls Enable (TRUE) to create the NV variable. +│ └── Calls SaveAndReboot() to SaveFrameworkState + EfiResetCold. +│ +Boot 2 (DXE Driver Test) +├── 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. +│ │ ├── Verifies the log was not truncated. +│ │ ├── PASS. +│ │ └── Logs results into internal buffer for later access via GetLog(). +├── TcgLogTestApp: +│ ├── Resumes execution from UEFI shell. (UnitTest Framework) +│ ├── Test Prerequisite: +│ │ └── SKIPPED. +│ ├── Calls TestPostReadyToBootScaling(): +│ │ └── Already PASSED in saved state → SKIPPED. +│ ├── Calls TestPreReadyToBootResults(): +│ │ ├── Locates TcgLogTest protocol. +│ │ ├── Calls GetLog() to acquire the TcgLogTestDxe log. +│ │ ├── Verifies PASS in TcgLogTestDxe log. +│ │ └── PASS. +│ └── Test Cleanup: +│ └── 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) +│ ├── Both 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 `GetEventLog` reports a different base address. | +| `TcgLogTestDumpEventLog` | Calls `GetEventLog`, walks the entire log (skipping the TCG 1.2 SpecID header), and prints each event's index, PCR index, event type, and event size via `DEBUG`. Returns the truncation status. | + +## 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..32f8c490736 --- /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..f843974ea32 --- /dev/null +++ b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.c @@ -0,0 +1,383 @@ +/** @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 + and verifies the truncation marker is present in the ACPI event log. + + Copyright (c), Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TcgLogTest.h" +#include "TcgLogTestCommon.h" + +#pragma pack(1) + +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Flags; + UINT64 AddressOfControlArea; + UINT32 StartMethod; + UINT8 PlatformSpecificParameters[12]; + UINT32 Laml; + UINT64 Lasa; +} TCG_LOG_TEST_TPM2_ACPI_TABLE_V4; + +#pragma pack() + +#define TCG_LOG_TRUNCATION_EVENT_STRING "TCG Event Log Truncated" +#define UNIT_TEST_NAME "TCG Log Scaling Test" +#define UNIT_TEST_VERSION "1.0" + +STATIC EFI_TCG2_PROTOCOL *mTcg2Protocol = NULL; +STATIC TCG_LOG_TEST_PROTOCOL *mTcgLogTestProtocol = NULL; + +/** + Look up the installed TPM2 ACPI table and return its LAML/LASA values. + + @param[out] Laml Log Area Minimum Length from the ACPI table. + @param[out] Lasa Log Area Start Address from the ACPI table. + + @retval EFI_SUCCESS Table found and values returned. + @retval EFI_NOT_FOUND TPM2 table not installed or too small. + @retval EFI_INVALID_PARAMETER Protocol not installed. +**/ +STATIC +EFI_STATUS +GetTpm2AcpiTableLogData ( + OUT UINT32 *Laml, + OUT EFI_PHYSICAL_ADDRESS *Lasa + ) +{ + EFI_STATUS Status; + EFI_ACPI_SDT_PROTOCOL *AcpiSdt; + EFI_ACPI_SDT_HEADER *SdtHeader; + EFI_ACPI_TABLE_VERSION Version; + UINTN TableKey; + UINTN Index; + TCG_LOG_TEST_TPM2_ACPI_TABLE_V4 *Tpm2Table; + + Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (VOID **)&AcpiSdt); + if (EFI_ERROR (Status)) { + return Status; + } + + // Walk the installed ACPI tables looking for the TPM2 signature. + Index = 0; + while (TRUE) { + Status = AcpiSdt->GetAcpiTable (Index, &SdtHeader, &Version, &TableKey); + if (EFI_ERROR (Status)) { + // Reached the end of the table list without finding TPM2. + DEBUG ((DEBUG_ERROR, "%a: TPM2 table not found\n", __func__)); + return EFI_NOT_FOUND; + } + + if (SdtHeader->Signature == EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE) { + break; + } + + Index++; + } + + if (SdtHeader->Length < sizeof (TCG_LOG_TEST_TPM2_ACPI_TABLE_V4)) { + return EFI_NOT_FOUND; + } + + Tpm2Table = (TCG_LOG_TEST_TPM2_ACPI_TABLE_V4 *)SdtHeader; + *Laml = Tpm2Table->Laml; + *Lasa = (EFI_PHYSICAL_ADDRESS)Tpm2Table->Lasa; + + return EFI_SUCCESS; +} + +/** + Walk the ACPI event log and check whether it contains a NO_ACTION event + whose payload matches the given truncation string. + + The ACPI log starts with a TCG 1.2 format SpecID event (TCG_PCR_EVENT_HDR + with a fixed 20-byte SHA1 digest), followed by TCG 2.0 format events. + This function skips the SpecID header, then walks all TCG 2.0 events + looking for the truncation marker. + + @param[in] Lasa Log Area Start Address (ACPI log base). + @param[in] Laml Log Area Min Length (ACPI log size). + + @retval TRUE A matching NO_ACTION truncation event was found. + @retval FALSE No match or log could not be parsed. +**/ +BOOLEAN +CheckTruncationEvent ( + IN EFI_PHYSICAL_ADDRESS Lasa, + IN UINTN Laml + ) +{ + UINT8 *CurrentEvent; + UINT8 *EndOfLog; + UINT32 PcrIndex; + UINT32 EventType; + UINT32 EventSize; + UINT8 *EventData; + UINT32 EventDataLen; + UINT32 SpecIdEventSize; + CONST CHAR8 *TruncEventStr = TCG_LOG_TRUNCATION_EVENT_STRING; + + // Verify the input parameters. + if ((Lasa == 0) || (Laml == 0) || (TruncEventStr == NULL)) { + return FALSE; + } + + CurrentEvent = (UINT8 *)(UINTN)Lasa; + EndOfLog = CurrentEvent + Laml; + EventDataLen = (UINT32)AsciiStrSize (TruncEventStr); + + // Skip the first event which is the TCG 1.2 format SpecID event: + // PCRIndex (4) + EventType (4) + Digest (20 = SHA1) + EventSize (4) + Event[EventSize] + if ((UINTN)(EndOfLog - CurrentEvent) < sizeof (TCG_PCR_EVENT_HDR)) { + return FALSE; + } + + SpecIdEventSize = ((TCG_PCR_EVENT_HDR *)CurrentEvent)->EventSize; + if ((UINTN)(EndOfLog - CurrentEvent) < sizeof (TCG_PCR_EVENT_HDR) + SpecIdEventSize) { + return FALSE; + } + + CurrentEvent += sizeof (TCG_PCR_EVENT_HDR) + SpecIdEventSize; + + // Walk all TCG 2.0 events looking for the truncation marker. + while (TcgLogTestAdvanceEvent (&CurrentEvent, EndOfLog, &PcrIndex, &EventType, &EventSize, &EventData)) { + if ((EventType == EV_NO_ACTION) && (PcrIndex == 0) && (EventSize == EventDataLen)) { + if (CompareMem (TruncEventStr, EventData, EventDataLen) == 0) { + return TRUE; + } + } + } + + return FALSE; +} + +/** + 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 +TestPreReadyToBootResults ( + 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); + } + + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_NOT_NULL (LogBuffer); + UT_ASSERT_TRUE (LogSize > 1); + + // 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, then verify + the truncation marker is present in the ACPI log region. + + @param[in] Context Unit test context (unused). + + @retval UNIT_TEST_PASSED Scaling and truncation marker verified. + @retval UNIT_TEST_ERROR_TEST_FAILED Assertion failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestPostReadyToBootScaling ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + BOOLEAN Scaled; + BOOLEAN Truncated; + EFI_PHYSICAL_ADDRESS AcpiLasa; + UINT32 AcpiLaml; + + Status = GetTpm2AcpiTableLogData (&AcpiLaml, &AcpiLasa); + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_TRUE (AcpiLasa != 0); + UT_ASSERT_TRUE (AcpiLaml != 0); + + Status = TcgLogTestLogEventsUntilScaled (mTcg2Protocol, &Scaled); + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_TRUE (Scaled); + + Status = TcgLogTestDumpEventLog (mTcg2Protocol, &Truncated); + UT_ASSERT_NOT_EFI_ERROR (Status); + + // The normal event log must not be truncated after scaling. + UT_ASSERT_FALSE (Truncated); + + UT_LOG_INFO ("Post-ReadyToBoot scaling succeeded\n"); + + // Verify truncation marker in ACPI log. + UT_ASSERT_TRUE (CheckTruncationEvent (AcpiLasa, (UINTN)AcpiLaml)); + + 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 produces truncation event", "PostRtbScaling", TestPostReadyToBootScaling, LocateProtocols, EnableDxeTestAndReboot, NULL); + AddTestCase (Suite, "Pre-ReadyToBoot DXE results contain PASS", "PreRtbResults", TestPreReadyToBootResults, 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..46cd39cdc4a --- /dev/null +++ b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.inf @@ -0,0 +1,43 @@ +## @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 + gEfiAcpiSdtProtocolGuid ## SOMETIMES_CONSUMES + gTcgLogTestProtocolGuid ## CONSUMES diff --git a/SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.c b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.c new file mode 100644 index 00000000000..d03d937e2c7 --- /dev/null +++ b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.c @@ -0,0 +1,414 @@ +/** @file + TCG Log Test common implementation shared by TcgLogTestDxe and TcgLogTestApp. + + Contains event log walking, truncation event checking, log-until-scaled + logic, and TPM2 ACPI table lookup. + + Copyright (c), Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#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" + +STATIC CHAR8 mCommonEventPayload[] = TCG_LOG_TEST_EVENT_PAYLOAD; + +/** + 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)AsciiStrSize (mCommonEventPayload); + 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, mCommonEventPayload, 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)mCommonEventPayload, + AsciiStrSize (mCommonEventPayload), + 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 = *(UINT32 *)EventPtr; + } + + // Store the EventType, if provided. + if (EventType != NULL) { + *EventType = *(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 = *(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 = *(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 = *(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; +} + +/** + Log events until the event log base address changes (i.e. dynamic scaling + occurs) or 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_PHYSICAL_ADDRESS LocationBefore; + EFI_PHYSICAL_ADDRESS LocationAfter; + EFI_PHYSICAL_ADDRESS LastEntry; + BOOLEAN Truncated; + EFI_TCG2_EVENT *Event; + + // Validate the input parameters. + if ((Tcg2Protocol == NULL) || (Scaled == NULL)) { + return EFI_INVALID_PARAMETER; + } + + *Scaled = FALSE; + + // Build a test event. + Status = TcgLogTestBuildEvent (&Event); + if (EFI_ERROR (Status)) { + return Status; + } + + // Get the event log before scaling. + Status = Tcg2Protocol->GetEventLog ( + Tcg2Protocol, + EFI_TCG2_EVENT_LOG_FORMAT_TCG_2, + &LocationBefore, + &LastEntry, + &Truncated + ); + + if (EFI_ERROR (Status)) { + FreePool (Event); + return Status; + } + + // Log multiple events until scaling occurs. + do { + Status = TcgLogTestLogEvent (Tcg2Protocol, Event); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: LogEvent failed - %r\n", __func__, Status)); + FreePool (Event); + return Status; + } + + Status = Tcg2Protocol->GetEventLog ( + Tcg2Protocol, + EFI_TCG2_EVENT_LOG_FORMAT_TCG_2, + &LocationAfter, + &LastEntry, + &Truncated + ); + + if (EFI_ERROR (Status)) { + FreePool (Event); + return Status; + } + } while (LocationBefore == LocationAfter); + + *Scaled = TRUE; + + DEBUG ((DEBUG_INFO, "%a: Log scaled (0x%lx -> 0x%lx)\n", __func__, LocationBefore, LocationAfter)); + + FreePool (Event); + return EFI_SUCCESS; +} + +/** + Dump the contents of a TCG 2.0 event log via DEBUG prints. + + Walks the event log skipping the TCG 1.2 SpecID header event. + Prints each event's index, PCRIndex, EventType, and EventSize. + + @param[in] Tcg2Protocol TCG2 protocol instance used to retrieve the event log. + @param[out] Truncated If the log is truncated. + + @retval EFI_SUCCESS Log dumped successfully. + @retval EFI_INVALID_PARAMETER One or more invalid parameters. +**/ +EFI_STATUS +TcgLogTestDumpEventLog ( + IN EFI_TCG2_PROTOCOL *Tcg2Protocol, + OUT BOOLEAN *Truncated + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS LogBase; + EFI_PHYSICAL_ADDRESS LastEntry; + BOOLEAN LogTruncated; + UINT8 *CurrentEvent; + UINT8 *EndOfLog; + UINT32 PcrIndex; + UINT32 EventType; + UINT32 EventSize; + UINTN Index; + + // Validate the input parameters. + if ((Tcg2Protocol == NULL) || (Truncated == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Status = Tcg2Protocol->GetEventLog ( + Tcg2Protocol, + EFI_TCG2_EVENT_LOG_FORMAT_TCG_2, + &LogBase, + &LastEntry, + &LogTruncated + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: GetEventLog failed - %r\n", __func__, Status)); + return Status; + } + + // Check if the log is truncated. This should never happen. + if (Truncated != NULL) { + *Truncated = LogTruncated; + } + + // Check if the log is empty. + if (LastEntry < LogBase) { + DEBUG ((DEBUG_WARN, "%a: EventLog is empty\n", __func__)); + return EFI_SUCCESS; + } + + // Skip the TCG 1.2 SpecID header event. + CurrentEvent = (UINT8 *)(UINTN)LogBase; + CurrentEvent += sizeof (TCG_PCR_EVENT_HDR) + ((TCG_PCR_EVENT_HDR *)CurrentEvent)->EventSize; + + // Determine what the EndOfLog should be. + EndOfLog = (UINT8 *)(UINTN)LastEntry; + if (!TcgLogTestAdvanceEvent (&EndOfLog, EndOfLog + MAX_UINT16, NULL, NULL, NULL, NULL)) { + DEBUG ((DEBUG_WARN, "%a: Could not determine EndOfLog\n", __func__)); + return EFI_SUCCESS; + } + + // Dump the contents of the EventLog. + DEBUG ((DEBUG_INFO, "%a: Event log dump (base=0x%lx, truncated=%d):\n", __func__, LogBase, LogTruncated)); + DEBUG ((DEBUG_INFO, " %-6a %-10a %-12a %a\n", "Index", "PCRIndex", "EventType", "EventSize")); + DEBUG ((DEBUG_INFO, " %-6a %-10a %-12a %a\n", "-----", "--------", "---------", "---------")); + + Index = 0; + while (TcgLogTestAdvanceEvent (&CurrentEvent, EndOfLog, &PcrIndex, &EventType, &EventSize, NULL)) { + DEBUG ((DEBUG_INFO, " %-6u %-10u 0x%08x %u\n", Index, PcrIndex, EventType, EventSize)); + Index++; + } + + DEBUG ((DEBUG_INFO, "%a: Total events: %u\n", __func__, Index)); + return EFI_SUCCESS; +} diff --git a/SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.h b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.h new file mode 100644 index 00000000000..2d602114d2d --- /dev/null +++ b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.h @@ -0,0 +1,74 @@ +/** @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 + ); + +/** + Dump the contents of a TCG 2.0 event log via DEBUG prints. + + Walks the event log skipping the TCG 1.2 SpecID header event. + Prints each event's index, PCRIndex, EventType, and EventSize. + + @param[in] Tcg2 TCG2 protocol instance used to retrieve the event log. + @param[out] Truncated If the log is truncated. + + @retval EFI_SUCCESS Log dumped successfully. + @retval EFI_INVALID_PARAMETER One or more invalid parameters. +**/ +EFI_STATUS +TcgLogTestDumpEventLog ( + IN EFI_TCG2_PROTOCOL *Tcg2, + OUT BOOLEAN *Truncated + ); + +#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..9b627b30cfa --- /dev/null +++ b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestDxe.c @@ -0,0 +1,268 @@ +/** @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; + } + + *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 + (log base address changes) and the log is not truncated. +**/ +STATIC +VOID +TestPreReadyToBootScaling ( + VOID + ) +{ + EFI_STATUS Status; + BOOLEAN Scaled; + BOOLEAN Truncated; + + 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; + } + + // Dump the event log and check for truncation. + Status = TcgLogTestDumpEventLog (mTcg2Protocol, &Truncated); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: DumpEventLog failed - %r\n", __func__, Status)); + LogAppend ("FAIL: Pre-ReadyToBoot: DumpEventLog - %r\n", Status); + return; + } + + if (Truncated) { + DEBUG ((DEBUG_ERROR, "%a: Log truncated after scaling\n", __func__)); + LogAppend ("FAIL: Pre-ReadyToBoot: Log truncated\n"); + 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. + TcgLogTestEnable (&mTcgLogTestProtocol, FALSE); + + 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..ab4a5054de9 --- /dev/null +++ b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestDxe.inf @@ -0,0 +1,47 @@ +## @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 + +[Depex] + gEfiVariableArchProtocolGuid AND gEfiTcg2ProtocolGuid From c996b96e91529be8a6daf9cc802291c2804919bf Mon Sep 17 00:00:00 2001 From: rdiaz Date: Fri, 8 May 2026 19:07:07 +0000 Subject: [PATCH 2/8] Ran Uncrustify. --- SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c | 85 ++++++++++--------- SecurityPkg/Tcg/TcgLogTest/TcgLogTest.h | 4 +- SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.c | 18 ++-- SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.c | 48 +++++------ 4 files changed, 78 insertions(+), 77 deletions(-) diff --git a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c index 24f498dc7f0..80c6248209b 100644 --- a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c +++ b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c @@ -1038,12 +1038,12 @@ TcgDxeLogEvent ( if (mReadyToBoot && !EventLogAreaStruct->EventLogTruncated) { Status = TcgCommLogEvent ( - EventLogAreaStruct, - NewEventHdr, - NewEventHdrSize, - NewEventData, - NewEventSize - ); + EventLogAreaStruct, + NewEventHdr, + NewEventHdrSize, + NewEventData, + NewEventSize + ); if (Status == EFI_OUT_OF_RESOURCES) { EventLogAreaStruct->EventLogTruncated = TRUE; @@ -1217,12 +1217,12 @@ TcgScaleEventLog ( // Double the length of the TCG log. NewLaml = EventLogAreaStruct->Laml * 2; - Status = gBS->AllocatePages ( - AllocateAnyPages, - EfiBootServicesData, - EFI_SIZE_TO_PAGES (NewLaml), - &NewLasa - ); + Status = gBS->AllocatePages ( + AllocateAnyPages, + EfiBootServicesData, + EFI_SIZE_TO_PAGES (NewLaml), + &NewLasa + ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Failed to allocate new TCG event log\n")); @@ -1230,7 +1230,7 @@ TcgScaleEventLog ( } // Copy the data from the old event log to the new event log. - CopyMem ((VOID*)(UINTN)NewLasa, (VOID*)(UINTN)EventLogAreaStruct->Lasa, EventLogAreaStruct->EventLogSize); + CopyMem ((VOID *)(UINTN)NewLasa, (VOID *)(UINTN)EventLogAreaStruct->Lasa, EventLogAreaStruct->EventLogSize); // Store the old Lasa and Laml before updating. OldLasa = EventLogAreaStruct->Lasa; @@ -1293,10 +1293,10 @@ TcgLogDynamicScalingNeeded ( if (!mAcpiEventLog.EventLogTruncated) { InitNoActionEvent (&NoActionEvent, sizeof (TCG_LOG_TRUNCATION_EVENT_STRING)); EventHdrSize = (UINT32)(sizeof (NoActionEvent.PCRIndex) + - sizeof (NoActionEvent.EventType) + - GetDigestListBinSize ((UINT8 *)&NoActionEvent.Digests) + - sizeof (NoActionEvent.EventSize)); - EventSize = EventHdrSize + sizeof (TCG_LOG_TRUNCATION_EVENT_STRING); + sizeof (NoActionEvent.EventType) + + GetDigestListBinSize ((UINT8 *)&NoActionEvent.Digests) + + sizeof (NoActionEvent.EventSize)); + EventSize = EventHdrSize + sizeof (TCG_LOG_TRUNCATION_EVENT_STRING); // Validate the NO_ACTION_EVENT doesn't cause an overflow. if (EventSize > MAX_ADDRESS - NewLogSize) { @@ -1350,16 +1350,16 @@ TcgDxeLogHashEvent ( { // MU_CHANGE - [BEGIN] - EFI_STATUS Status; - EFI_TPL OldTpl; - UINTN Index; - EFI_STATUS RetStatus; - TCG_PCR_EVENT2 TcgPcrEvent2; - UINT8 *DigestBuffer; - UINT32 *EventSizePtr; - BOOLEAN DynamicScalingNeeded; - TCG_PCR_EVENT2_HDR NoActionEvent; - UINT32 EventHdrSize; + EFI_STATUS Status; + EFI_TPL OldTpl; + UINTN Index; + EFI_STATUS RetStatus; + TCG_PCR_EVENT2 TcgPcrEvent2; + UINT8 *DigestBuffer; + UINT32 *EventSizePtr; + BOOLEAN DynamicScalingNeeded; + TCG_PCR_EVENT2_HDR NoActionEvent; + UINT32 EventHdrSize; // MU_CHANGE - [END] @@ -1404,10 +1404,10 @@ TcgDxeLogHashEvent ( // Need to dynamically scale the TCG log before we enter a critical region. DynamicScalingNeeded = TcgLogDynamicScalingNeeded ( - &mTcgDxeData.EventLogAreaStruct[Index], - sizeof (TcgPcrEvent2.PCRIndex) + sizeof (TcgPcrEvent2.EventType) + GetDigestListBinSize (DigestBuffer) + sizeof (TcgPcrEvent2.EventSize), - NewEventHdr->EventSize - ); + &mTcgDxeData.EventLogAreaStruct[Index], + sizeof (TcgPcrEvent2.PCRIndex) + sizeof (TcgPcrEvent2.EventType) + GetDigestListBinSize (DigestBuffer) + sizeof (TcgPcrEvent2.EventSize), + NewEventHdr->EventSize + ); // If scaling is needed and the ACPI event log as been created. Log a // NO_ACTION_EVENT with the truncation string to the end of it to mark that @@ -1415,18 +1415,18 @@ TcgDxeLogHashEvent ( if (DynamicScalingNeeded && mReadyToBoot && !mAcpiEventLog.EventLogTruncated) { InitNoActionEvent (&NoActionEvent, sizeof (TCG_LOG_TRUNCATION_EVENT_STRING)); EventHdrSize = (UINT32)(sizeof (NoActionEvent.PCRIndex) + - sizeof (NoActionEvent.EventType) + - GetDigestListBinSize ((UINT8 *)&NoActionEvent.Digests) + - sizeof (NoActionEvent.EventSize)); + sizeof (NoActionEvent.EventType) + + GetDigestListBinSize ((UINT8 *)&NoActionEvent.Digests) + + sizeof (NoActionEvent.EventSize)); OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); Status = TcgCommLogEvent ( - &mAcpiEventLog, - &NoActionEvent, - EventHdrSize, - (UINT8 *)TCG_LOG_TRUNCATION_EVENT_STRING, - sizeof (TCG_LOG_TRUNCATION_EVENT_STRING) - ); + &mAcpiEventLog, + &NoActionEvent, + EventHdrSize, + (UINT8 *)TCG_LOG_TRUNCATION_EVENT_STRING, + sizeof (TCG_LOG_TRUNCATION_EVENT_STRING) + ); gBS->RestoreTPL (OldTpl); if (EFI_ERROR (Status)) { @@ -1439,7 +1439,7 @@ TcgDxeLogHashEvent ( // Only scale when needed. if (DynamicScalingNeeded) { - Status = TcgScaleEventLog(&mTcgDxeData.EventLogAreaStruct[Index]); + Status = TcgScaleEventLog (&mTcgDxeData.EventLogAreaStruct[Index]); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Unable to scale the TCG event log!\n")); return Status; @@ -2966,7 +2966,7 @@ GenerateAcpiLog ( mAcpiEventLog.Next800155EventOffset = EventLogAreaStruct->Next800155EventOffset; // Copy the data to the ACPI log. - CopyMem ((VOID*)(UINTN)AcpiLasa, (VOID*)(UINTN)EventLogAreaStruct->Lasa, mAcpiEventLog.Laml); + CopyMem ((VOID *)(UINTN)AcpiLasa, (VOID *)(UINTN)EventLogAreaStruct->Lasa, mAcpiEventLog.Laml); // Update the PCDs. PcdSet32S (PcdTpm2AcpiTableLaml, (UINT32)mAcpiEventLog.Laml); @@ -3015,6 +3015,7 @@ OnReadyToBoot ( if ((PcdGet8 (PcdTpm2AcpiTableRev) >= 4) && !mReadyToBoot) { GenerateAcpiLog (&mTcgDxeData.EventLogAreaStruct[Index]); } + break; } } diff --git a/SecurityPkg/Tcg/TcgLogTest/TcgLogTest.h b/SecurityPkg/Tcg/TcgLogTest/TcgLogTest.h index 32f8c490736..ee5795cc41c 100644 --- a/SecurityPkg/Tcg/TcgLogTest/TcgLogTest.h +++ b/SecurityPkg/Tcg/TcgLogTest/TcgLogTest.h @@ -58,8 +58,8 @@ EFI_STATUS ); struct _TCG_LOG_TEST_PROTOCOL { - TCG_LOG_TEST_GET_LOG GetLog; - TCG_LOG_TEST_ENABLE Enable; + TCG_LOG_TEST_GET_LOG GetLog; + TCG_LOG_TEST_ENABLE Enable; }; extern EFI_GUID gTcgLogTestProtocolGuid; diff --git a/SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.c b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.c index f843974ea32..45bb3c8df97 100644 --- a/SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.c +++ b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.c @@ -127,15 +127,15 @@ CheckTruncationEvent ( IN UINTN Laml ) { - UINT8 *CurrentEvent; - UINT8 *EndOfLog; - UINT32 PcrIndex; - UINT32 EventType; - UINT32 EventSize; - UINT8 *EventData; - UINT32 EventDataLen; - UINT32 SpecIdEventSize; - CONST CHAR8 *TruncEventStr = TCG_LOG_TRUNCATION_EVENT_STRING; + UINT8 *CurrentEvent; + UINT8 *EndOfLog; + UINT32 PcrIndex; + UINT32 EventType; + UINT32 EventSize; + UINT8 *EventData; + UINT32 EventDataLen; + UINT32 SpecIdEventSize; + CONST CHAR8 *TruncEventStr = TCG_LOG_TRUNCATION_EVENT_STRING; // Verify the input parameters. if ((Lasa == 0) || (Laml == 0) || (TruncEventStr == NULL)) { diff --git a/SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.c b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.c index d03d937e2c7..0668f6ab887 100644 --- a/SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.c +++ b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.c @@ -81,12 +81,12 @@ TcgLogTestLogEvent ( ) { return Tcg2Protocol->HashLogExtendEvent ( - Tcg2Protocol, - 0, - (EFI_PHYSICAL_ADDRESS)(UINTN)mCommonEventPayload, - AsciiStrSize (mCommonEventPayload), - Event - ); + Tcg2Protocol, + 0, + (EFI_PHYSICAL_ADDRESS)(UINTN)mCommonEventPayload, + AsciiStrSize (mCommonEventPayload), + Event + ); } /** @@ -286,12 +286,12 @@ TcgLogTestLogEventsUntilScaled ( // Get the event log before scaling. Status = Tcg2Protocol->GetEventLog ( - Tcg2Protocol, - EFI_TCG2_EVENT_LOG_FORMAT_TCG_2, - &LocationBefore, - &LastEntry, - &Truncated - ); + Tcg2Protocol, + EFI_TCG2_EVENT_LOG_FORMAT_TCG_2, + &LocationBefore, + &LastEntry, + &Truncated + ); if (EFI_ERROR (Status)) { FreePool (Event); @@ -308,12 +308,12 @@ TcgLogTestLogEventsUntilScaled ( } Status = Tcg2Protocol->GetEventLog ( - Tcg2Protocol, - EFI_TCG2_EVENT_LOG_FORMAT_TCG_2, - &LocationAfter, - &LastEntry, - &Truncated - ); + Tcg2Protocol, + EFI_TCG2_EVENT_LOG_FORMAT_TCG_2, + &LocationAfter, + &LastEntry, + &Truncated + ); if (EFI_ERROR (Status)) { FreePool (Event); @@ -364,12 +364,12 @@ TcgLogTestDumpEventLog ( } Status = Tcg2Protocol->GetEventLog ( - Tcg2Protocol, - EFI_TCG2_EVENT_LOG_FORMAT_TCG_2, - &LogBase, - &LastEntry, - &LogTruncated - ); + Tcg2Protocol, + EFI_TCG2_EVENT_LOG_FORMAT_TCG_2, + &LogBase, + &LastEntry, + &LogTruncated + ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: GetEventLog failed - %r\n", __func__, Status)); From 7abb18618781e31bfd79de9a8d37f453f1078566 Mon Sep 17 00:00:00 2001 From: rdiaz Date: Fri, 8 May 2026 19:21:51 +0000 Subject: [PATCH 3/8] Fixed a warning as error where conversion from UINT64 to UINTN would cause possible loss of data. --- SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c index 80c6248209b..0bb910cf523 100644 --- a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c +++ b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c @@ -1220,7 +1220,7 @@ TcgScaleEventLog ( Status = gBS->AllocatePages ( AllocateAnyPages, EfiBootServicesData, - EFI_SIZE_TO_PAGES (NewLaml), + EFI_SIZE_TO_PAGES ((UINTN)NewLaml), &NewLasa ); @@ -1246,7 +1246,7 @@ TcgScaleEventLog ( // Once we reach ReadyToBoot, we do not want to free the old log regions, this is // due to the ACPI table containing the old log pointer, we do not want to // invalidate this memory. - gBS->FreePages (OldLasa, EFI_SIZE_TO_PAGES (OldLaml)); + gBS->FreePages (OldLasa, EFI_SIZE_TO_PAGES ((UINTN)OldLaml)); return Status; } @@ -2946,7 +2946,7 @@ GenerateAcpiLog ( Status = gBS->AllocatePages ( AllocateAnyPages, EfiACPIMemoryNVS, - EFI_SIZE_TO_PAGES (EventLogAreaStruct->Laml), + EFI_SIZE_TO_PAGES ((UINTN)EventLogAreaStruct->Laml), &AcpiLasa ); @@ -2966,7 +2966,7 @@ GenerateAcpiLog ( mAcpiEventLog.Next800155EventOffset = EventLogAreaStruct->Next800155EventOffset; // Copy the data to the ACPI log. - CopyMem ((VOID *)(UINTN)AcpiLasa, (VOID *)(UINTN)EventLogAreaStruct->Lasa, mAcpiEventLog.Laml); + CopyMem ((VOID *)(UINTN)AcpiLasa, (VOID *)(UINTN)EventLogAreaStruct->Lasa, (UINTN)mAcpiEventLog.Laml); // Update the PCDs. PcdSet32S (PcdTpm2AcpiTableLaml, (UINT32)mAcpiEventLog.Laml); From 99fda2e18a8aa12c4855e6a6cae6a2d3ecf70b1f Mon Sep 17 00:00:00 2001 From: rdiaz Date: Fri, 8 May 2026 19:40:19 +0000 Subject: [PATCH 4/8] Added TcgLogTestApp and TcgLogTestDxe to SecurityPkg.dsc. --- SecurityPkg/SecurityPkg.dsc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SecurityPkg/SecurityPkg.dsc b/SecurityPkg/SecurityPkg.dsc index 82dd0be714c..dbba3d8693d 100644 --- a/SecurityPkg/SecurityPkg.dsc +++ b/SecurityPkg/SecurityPkg.dsc @@ -248,6 +248,8 @@ SecurityPkg/Library/PeiDxeTpmPlatformHierarchyLibNull/PeiDxeTpmPlatformHierarchyLib.inf SecurityPkg/Applications/TpmShellApp/TpmShellApp.inf ## MU_CHANGE + SecurityPkg/Tcg/TcgLogTest/TcgLogTestDxe.inf ## MU_CHANGE + SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.inf ## MU_CHANGE # # TCG Storage. From 703f774002ff60a55fc4b87fdeaf86839edd7d22 Mon Sep 17 00:00:00 2001 From: rdiaz Date: Fri, 8 May 2026 19:49:38 +0000 Subject: [PATCH 5/8] Added UnitTestLib module overrides for TcgLogTestApp. --- SecurityPkg/SecurityPkg.dsc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/SecurityPkg/SecurityPkg.dsc b/SecurityPkg/SecurityPkg.dsc index dbba3d8693d..247a1000254 100644 --- a/SecurityPkg/SecurityPkg.dsc +++ b/SecurityPkg/SecurityPkg.dsc @@ -248,8 +248,16 @@ SecurityPkg/Library/PeiDxeTpmPlatformHierarchyLibNull/PeiDxeTpmPlatformHierarchyLib.inf SecurityPkg/Applications/TpmShellApp/TpmShellApp.inf ## MU_CHANGE - SecurityPkg/Tcg/TcgLogTest/TcgLogTestDxe.inf ## MU_CHANGE - SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.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/UnitTestResultReportLibDebugLib.inf + } + ## MU_CHANGE - [END] # # TCG Storage. From 12c63d7421152d5b3c0f4653af5fa5bfc6677602 Mon Sep 17 00:00:00 2001 From: rdiaz Date: Mon, 11 May 2026 21:15:23 +0000 Subject: [PATCH 6/8] Addressed review feedback/comments. --- MdePkg/Include/IndustryStandard/Tpm2Acpi.h | 30 ++++++ .../IndustryStandard/UefiTcgPlatform.h | 5 + SecurityPkg/SecurityPkg.dec | 2 +- SecurityPkg/Tcg/Tcg2Acpi/Tcg2Acpi.c | 12 ++- SecurityPkg/Tcg/Tcg2AcpiFfa/Tcg2AcpiFfa.c | 12 ++- SecurityPkg/Tcg/Tcg2Dxe/README.md | 7 +- SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c | 93 ++++++++----------- SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.c | 38 +++----- SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.c | 91 +++++++++++++++++- 9 files changed, 201 insertions(+), 89 deletions(-) diff --git a/MdePkg/Include/IndustryStandard/Tpm2Acpi.h b/MdePkg/Include/IndustryStandard/Tpm2Acpi.h index 879a6058d73..90573e7f88f 100644 --- a/MdePkg/Include/IndustryStandard/Tpm2Acpi.h +++ b/MdePkg/Include/IndustryStandard/Tpm2Acpi.h @@ -80,6 +80,36 @@ typedef struct { UINT8 Reserved[8]; } EFI_TPM2_ACPI_START_METHOD_SPECIFIC_PARAMETERS_ARM_FFA; +// MU_CHANGE - [BEGIN] + +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; + UINT32 StartMethod; + UINT8 PlatformSpecificParameters[12]; // size up to 12 + UINT32 Laml; // Optional + UINT64 Lasa; // Optional +} EFI_TPM2_ACPI_TABLE_V4; + +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; + UINT32 StartMethod; + EFI_TPM2_ACPI_START_METHOD_SPECIFIC_PARAMETERS_ARM_FFA FfaParameters; + UINT32 Laml; // Optional + UINT64 Lasa; // Optional +} EFI_TPM2_ACPI_TABLE_V5; + +// 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/MdePkg/Include/IndustryStandard/UefiTcgPlatform.h b/MdePkg/Include/IndustryStandard/UefiTcgPlatform.h index 1b7b2406e9d..b7abedd82c5 100644 --- a/MdePkg/Include/IndustryStandard/UefiTcgPlatform.h +++ b/MdePkg/Include/IndustryStandard/UefiTcgPlatform.h @@ -101,6 +101,11 @@ #define FIRMWARE_DEBUGGER_EVENT_STRING "UEFI Debug Mode" #define FIRMWARE_DEBUGGER_EVENT_STRING_LEN (sizeof(FIRMWARE_DEBUGGER_EVENT_STRING) - 1) +// MU_CHANGE +// String logged as a NO_ACTION event to mark the ACPI-visible TCG +// log as truncated when dynamic scaling occurs post ReadyToBoot. +#define TCG_LOG_TRUNCATION_EVENT_STRING "TCG Event Log Truncated" + // // Set structure alignment to 1-byte // diff --git a/SecurityPkg/SecurityPkg.dec b/SecurityPkg/SecurityPkg.dec index 3280ad887a5..eb5d260218b 100644 --- a/SecurityPkg/SecurityPkg.dec +++ b/SecurityPkg/SecurityPkg.dec @@ -303,7 +303,7 @@ ## MU_CHANGE - END - Add a new protocol to support Log-only events. ## MU_CHANGE - [BEGIN] - ## TCG Log Test protocol produced by TcgLogTestDxe. + ## Protocol used to test dynamic TCG log scaling functionality. # Tcg/TcgLogTest/TcgLogTest.h gTcgLogTestProtocolGuid = {0xa3c12f80, 0x7d9e, 0x4b5a, { 0x91, 0xe4, 0x6c, 0xf8, 0x2d, 0xa1, 0xb7, 0x03 }} ## MU_CHANGE - [END] diff --git a/SecurityPkg/Tcg/Tcg2Acpi/Tcg2Acpi.c b/SecurityPkg/Tcg/Tcg2Acpi/Tcg2Acpi.c index 87bd22cc93a..f523728442d 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,7 +93,11 @@ typedef struct { UINT64 Lasa; // Optional } EFI_TPM2_ACPI_TABLE_V4; -#pragma pack() + #pragma pack() + +#endif + +// MU_CHANGE - [END] EFI_TPM2_ACPI_TABLE_V4 mTpm2AcpiTemplate = { { diff --git a/SecurityPkg/Tcg/Tcg2AcpiFfa/Tcg2AcpiFfa.c b/SecurityPkg/Tcg/Tcg2AcpiFfa/Tcg2AcpiFfa.c index c3ae72e6225..696128abf31 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,7 +85,11 @@ typedef struct { UINT64 Lasa; // Optional } EFI_TPM2_ACPI_TABLE_V5; -#pragma pack() + #pragma pack() + +#endif + +// MU_CHANGE - [END] EFI_TPM2_ACPI_TABLE_V5 mTpm2AcpiTemplate = { { diff --git a/SecurityPkg/Tcg/Tcg2Dxe/README.md b/SecurityPkg/Tcg/Tcg2Dxe/README.md index f6c80b79db4..6c1b3cab0ae 100644 --- a/SecurityPkg/Tcg/Tcg2Dxe/README.md +++ b/SecurityPkg/Tcg/Tcg2Dxe/README.md @@ -1,9 +1,10 @@ # Tcg2Dxe Tcg2Dxe is a DXE-phase UEFI driver that publishes the TCG2 protocol defined -by the TCG EFI Protocol Specification. It's 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. +by the [TCG EFI Protocol Specification](https://trustedcomputinggroup.org/resource/tcg-efi-protocol-specification/). +It's 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 diff --git a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c index 0bb910cf523..2d0e8bdd7c9 100644 --- a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c +++ b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c @@ -11,6 +11,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include +#include // MU_CHANGE #include #include @@ -134,31 +135,12 @@ VARIABLE_TYPE mVariableType[] = { { EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid }, }; -EFI_HANDLE mImageHandle; - // MU_CHANGE - [BEGIN] +EFI_HANDLE mImageHandle; BOOLEAN mReadyToBoot = FALSE; TCG_EVENT_LOG_AREA_STRUCT mAcpiEventLog; -// String logged as a NO_ACTION event to mark the ACPI-visible TCG -// log as truncated when dynamic scaling occurs post ReadyToBoot. -#define TCG_LOG_TRUNCATION_EVENT_STRING "TCG Event Log Truncated" - -#pragma pack(1) - -typedef struct { - EFI_ACPI_DESCRIPTION_HEADER Header; - UINT32 Flags; - UINT64 AddressOfControlArea; - UINT32 StartMethod; - UINT8 PlatformSpecificParameters[12]; - UINT32 Laml; - UINT64 Lasa; -} EFI_TPM2_ACPI_TABLE_V4; - -#pragma pack() - // MU_CHANGE - [END] /** @@ -1047,7 +1029,6 @@ TcgDxeLogEvent ( if (Status == EFI_OUT_OF_RESOURCES) { EventLogAreaStruct->EventLogTruncated = TRUE; - return EFI_VOLUME_FULL; } else if (Status == EFI_SUCCESS) { EventLogAreaStruct->EventLogStarted = TRUE; } @@ -1243,9 +1224,7 @@ TcgScaleEventLog ( EventLogAreaStruct->Lasa = NewLasa; EventLogAreaStruct->Laml = NewLaml; - // Once we reach ReadyToBoot, we do not want to free the old log regions, this is - // due to the ACPI table containing the old log pointer, we do not want to - // invalidate this memory. + // Free the old log region. gBS->FreePages (OldLasa, EFI_SIZE_TO_PAGES ((UINTN)OldLaml)); return Status; @@ -1270,10 +1249,7 @@ TcgLogDynamicScalingNeeded ( IN UINT32 NewEventSize ) { - UINTN NewLogSize; - TCG_PCR_EVENT2_HDR NoActionEvent; - UINT32 EventHdrSize; - UINTN EventSize; + UINTN NewLogSize; // Make sure EventLogAreaStruct is valid. if (EventLogAreaStruct == NULL) { @@ -1282,32 +1258,15 @@ TcgLogDynamicScalingNeeded ( // Validate NewEventSize + NewEventHdrSize doesn't cause an overflow. if (NewEventSize > MAX_ADDRESS - NewEventHdrSize) { + ASSERT (FALSE); return FALSE; } NewLogSize = NewEventHdrSize + NewEventSize; - // Reserve space for the truncation NO_ACTION_EVENT so that the log can never - // fill past the point where the truncation marker would not fit. We only need - // to continue to reserve space as long as the ACPI event log is not truncated. - if (!mAcpiEventLog.EventLogTruncated) { - InitNoActionEvent (&NoActionEvent, sizeof (TCG_LOG_TRUNCATION_EVENT_STRING)); - EventHdrSize = (UINT32)(sizeof (NoActionEvent.PCRIndex) + - sizeof (NoActionEvent.EventType) + - GetDigestListBinSize ((UINT8 *)&NoActionEvent.Digests) + - sizeof (NoActionEvent.EventSize)); - EventSize = EventHdrSize + sizeof (TCG_LOG_TRUNCATION_EVENT_STRING); - - // Validate the NO_ACTION_EVENT doesn't cause an overflow. - if (EventSize > MAX_ADDRESS - NewLogSize) { - return FALSE; - } - - NewLogSize += EventSize; - } - // Validate EventLogSize + NewLogSize doesn't cause an overflow. if (NewLogSize > MAX_ADDRESS - EventLogAreaStruct->EventLogSize) { + ASSERT (FALSE); return FALSE; } @@ -2924,6 +2883,29 @@ UpdateTpm2AcpiTable ( return Status; } +/** + Compute the full size of the truncation NO_ACTION event (header + payload). + + @retval Size in bytes of the truncation event. +**/ +STATIC +UINTN +GetTruncationEventSize ( + VOID + ) +{ + TCG_PCR_EVENT2_HDR NoActionEvent; + UINT32 EventHdrSize; + + InitNoActionEvent (&NoActionEvent, sizeof (TCG_LOG_TRUNCATION_EVENT_STRING)); + EventHdrSize = (UINT32)(sizeof (NoActionEvent.PCRIndex) + + sizeof (NoActionEvent.EventType) + + GetDigestListBinSize ((UINT8 *)&NoActionEvent.Digests) + + sizeof (NoActionEvent.EventSize)); + + return (UINTN)EventHdrSize + sizeof (TCG_LOG_TRUNCATION_EVENT_STRING); +} + /** Generate the ACPI TCG event log. @@ -2941,12 +2923,19 @@ GenerateAcpiLog ( { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS AcpiLasa; + UINTN TruncationEventSize; + UINT64 AcpiLaml; + + // Compute the truncation event size so we can reserve space for it in the + // ACPI log. + TruncationEventSize = GetTruncationEventSize (); + AcpiLaml = EventLogAreaStruct->Laml + TruncationEventSize; - // Allocate the NVS region for the ACPI log. + // Allocate the NVS region for the ACPI log (with truncation event headroom). Status = gBS->AllocatePages ( AllocateAnyPages, EfiACPIMemoryNVS, - EFI_SIZE_TO_PAGES ((UINTN)EventLogAreaStruct->Laml), + EFI_SIZE_TO_PAGES ((UINTN)AcpiLaml), &AcpiLasa ); @@ -2958,7 +2947,7 @@ GenerateAcpiLog ( // Copy the event log information. mAcpiEventLog.EventLogFormat = EventLogAreaStruct->EventLogFormat; mAcpiEventLog.Lasa = AcpiLasa; - mAcpiEventLog.Laml = EventLogAreaStruct->Laml; + mAcpiEventLog.Laml = AcpiLaml; mAcpiEventLog.EventLogSize = EventLogAreaStruct->EventLogSize; mAcpiEventLog.LastEvent = (UINT8 *)(UINTN)AcpiLasa + EventLogAreaStruct->EventLogSize; mAcpiEventLog.EventLogStarted = EventLogAreaStruct->EventLogStarted; @@ -2966,10 +2955,10 @@ GenerateAcpiLog ( mAcpiEventLog.Next800155EventOffset = EventLogAreaStruct->Next800155EventOffset; // Copy the data to the ACPI log. - CopyMem ((VOID *)(UINTN)AcpiLasa, (VOID *)(UINTN)EventLogAreaStruct->Lasa, (UINTN)mAcpiEventLog.Laml); + CopyMem ((VOID *)(UINTN)AcpiLasa, (VOID *)(UINTN)EventLogAreaStruct->Lasa, (UINTN)mAcpiEventLog.EventLogSize); // Update the PCDs. - PcdSet32S (PcdTpm2AcpiTableLaml, (UINT32)mAcpiEventLog.Laml); + PcdSet32S (PcdTpm2AcpiTableLaml, (UINT32)AcpiLaml); PcdSet64S (PcdTpm2AcpiTableLasa, AcpiLasa); // Uninstall and reinstall the ACPI table with the updated LAML/LASA. diff --git a/SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.c b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.c index 45bb3c8df97..ec6b1ab6348 100644 --- a/SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.c +++ b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestApp.c @@ -23,27 +23,13 @@ #include #include #include +#include #include "TcgLogTest.h" #include "TcgLogTestCommon.h" -#pragma pack(1) - -typedef struct { - EFI_ACPI_DESCRIPTION_HEADER Header; - UINT32 Flags; - UINT64 AddressOfControlArea; - UINT32 StartMethod; - UINT8 PlatformSpecificParameters[12]; - UINT32 Laml; - UINT64 Lasa; -} TCG_LOG_TEST_TPM2_ACPI_TABLE_V4; - -#pragma pack() - -#define TCG_LOG_TRUNCATION_EVENT_STRING "TCG Event Log Truncated" -#define UNIT_TEST_NAME "TCG Log Scaling Test" -#define UNIT_TEST_VERSION "1.0" +#define UNIT_TEST_NAME "TCG Log Scaling Test" +#define UNIT_TEST_VERSION "1.0" STATIC EFI_TCG2_PROTOCOL *mTcg2Protocol = NULL; STATIC TCG_LOG_TEST_PROTOCOL *mTcgLogTestProtocol = NULL; @@ -65,13 +51,13 @@ GetTpm2AcpiTableLogData ( OUT EFI_PHYSICAL_ADDRESS *Lasa ) { - EFI_STATUS Status; - EFI_ACPI_SDT_PROTOCOL *AcpiSdt; - EFI_ACPI_SDT_HEADER *SdtHeader; - EFI_ACPI_TABLE_VERSION Version; - UINTN TableKey; - UINTN Index; - TCG_LOG_TEST_TPM2_ACPI_TABLE_V4 *Tpm2Table; + EFI_STATUS Status; + EFI_ACPI_SDT_PROTOCOL *AcpiSdt; + EFI_ACPI_SDT_HEADER *SdtHeader; + EFI_ACPI_TABLE_VERSION Version; + UINTN TableKey; + UINTN Index; + EFI_TPM2_ACPI_TABLE_V4 *Tpm2Table; Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (VOID **)&AcpiSdt); if (EFI_ERROR (Status)) { @@ -95,11 +81,11 @@ GetTpm2AcpiTableLogData ( Index++; } - if (SdtHeader->Length < sizeof (TCG_LOG_TEST_TPM2_ACPI_TABLE_V4)) { + if (SdtHeader->Length < sizeof (EFI_TPM2_ACPI_TABLE_V4)) { return EFI_NOT_FOUND; } - Tpm2Table = (TCG_LOG_TEST_TPM2_ACPI_TABLE_V4 *)SdtHeader; + Tpm2Table = (EFI_TPM2_ACPI_TABLE_V4 *)SdtHeader; *Laml = Tpm2Table->Laml; *Lasa = (EFI_PHYSICAL_ADDRESS)Tpm2Table->Lasa; diff --git a/SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.c b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.c index 0668f6ab887..e7166fdf877 100644 --- a/SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.c +++ b/SecurityPkg/Tcg/TcgLogTest/TcgLogTestCommon.c @@ -24,6 +24,91 @@ STATIC CHAR8 mCommonEventPayload[] = TCG_LOG_TEST_EVENT_PAYLOAD; +/** + Converts EventType to ASCII string. + + @param[in] EventType TCG_EVENTTYPE value. + + @retval ASCII string describing the event type. +**/ +STATIC +CHAR8 * +TcgEventTypeToString ( + IN UINT32 EventType + ) +{ + switch (EventType) { + case EV_PREBOOT_CERT: + return "EV_PREBOOT_CERT"; + case EV_POST_CODE: + return "EV_POST_CODE"; + case EV_NO_ACTION: + return "EV_NO_ACTION"; + case EV_SEPARATOR: + return "EV_SEPARATOR"; + case EV_ACTION: + return "EV_ACTION"; + case EV_EVENT_TAG: + return "EV_EVENT_TAG"; + case EV_S_CRTM_CONTENTS: + return "EV_S_CRTM_CONTENTS"; + case EV_S_CRTM_VERSION: + return "EV_S_CRTM_VERSION"; + case EV_CPU_MICROCODE: + return "EV_CPU_MICROCODE"; + case EV_PLATFORM_CONFIG_FLAGS: + return "EV_PLATFORM_CONFIG_FLAGS"; + case EV_TABLE_OF_DEVICES: + return "EV_TABLE_OF_DEVICES"; + case EV_COMPACT_HASH: + return "EV_COMPACT_HASH"; + case EV_NONHOST_CODE: + return "EV_NONHOST_CODE"; + case EV_NONHOST_CONFIG: + return "EV_NONHOST_CONFIG"; + case EV_NONHOST_INFO: + return "EV_NONHOST_INFO"; + case EV_OMIT_BOOT_DEVICE_EVENTS: + return "EV_OMIT_BOOT_DEVICE_EVENTS"; + case EV_EFI_VARIABLE_DRIVER_CONFIG: + return "EV_EFI_VARIABLE_DRIVER_CONFIG"; + case EV_EFI_VARIABLE_BOOT: + return "EV_EFI_VARIABLE_BOOT"; + case EV_EFI_BOOT_SERVICES_APPLICATION: + return "EV_EFI_BOOT_SERVICES_APPLICATION"; + case EV_EFI_BOOT_SERVICES_DRIVER: + return "EV_EFI_BOOT_SERVICES_DRIVER"; + case EV_EFI_RUNTIME_SERVICES_DRIVER: + return "EV_EFI_RUNTIME_SERVICES_DRIVER"; + case EV_EFI_GPT_EVENT: + return "EV_EFI_GPT_EVENT"; + case EV_EFI_ACTION: + return "EV_EFI_ACTION"; + case EV_EFI_PLATFORM_FIRMWARE_BLOB: + return "EV_EFI_PLATFORM_FIRMWARE_BLOB"; + case EV_EFI_HANDOFF_TABLES: + return "EV_EFI_HANDOFF_TABLES"; + case EV_EFI_PLATFORM_FIRMWARE_BLOB2: + return "EV_EFI_PLATFORM_FIRMWARE_BLOB2"; + case EV_EFI_HANDOFF_TABLES2: + return "EV_EFI_HANDOFF_TABLES2"; + case EV_EFI_HCRTM_EVENT: + return "EV_EFI_HCRTM_EVENT"; + case EV_EFI_VARIABLE_AUTHORITY: + return "EV_EFI_VARIABLE_AUTHORITY"; + case EV_EFI_SPDM_FIRMWARE_BLOB: + return "EV_EFI_SPDM_FIRMWARE_BLOB"; + case EV_EFI_SPDM_FIRMWARE_CONFIG: + return "EV_EFI_SPDM_FIRMWARE_CONFIG"; + case EV_EFI_SPDM_DEVICE_POLICY: + return "EV_EFI_SPDM_DEVICE_POLICY"; + case EV_EFI_SPDM_DEVICE_AUTHORITY: + return "EV_EFI_SPDM_DEVICE_AUTHORITY"; + default: + return "UNKNOWN"; + } +} + /** Allocate and initialize an EFI_TCG2_EVENT structure with a fixed payload. @@ -400,12 +485,12 @@ TcgLogTestDumpEventLog ( // Dump the contents of the EventLog. DEBUG ((DEBUG_INFO, "%a: Event log dump (base=0x%lx, truncated=%d):\n", __func__, LogBase, LogTruncated)); - DEBUG ((DEBUG_INFO, " %-6a %-10a %-12a %a\n", "Index", "PCRIndex", "EventType", "EventSize")); - DEBUG ((DEBUG_INFO, " %-6a %-10a %-12a %a\n", "-----", "--------", "---------", "---------")); + DEBUG ((DEBUG_INFO, " %-6a %-10a %-34a %a\n", "Index", "PCRIndex", "EventType", "EventSize")); + DEBUG ((DEBUG_INFO, " %-6a %-10a %-34a %a\n", "-----", "--------", "---------", "---------")); Index = 0; while (TcgLogTestAdvanceEvent (&CurrentEvent, EndOfLog, &PcrIndex, &EventType, &EventSize, NULL)) { - DEBUG ((DEBUG_INFO, " %-6u %-10u 0x%08x %u\n", Index, PcrIndex, EventType, EventSize)); + DEBUG ((DEBUG_INFO, " %-6u %-10u %-34a %u\n", Index, PcrIndex, TcgEventTypeToString (EventType), EventSize)); Index++; } From 79d99e743956c3eeb38b1e5f5fd84e0fbb1d9f59 Mon Sep 17 00:00:00 2001 From: rdiaz Date: Tue, 12 May 2026 01:07:08 +0000 Subject: [PATCH 7/8] Fixed an issue where LastEvent could be stale when an 800155 event caused dynamic scaling to occur. Scaling the log now makes sure the LastEvent pointer is always valid. --- SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c index 2d0e8bdd7c9..78a9cbcffdd 100644 --- a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c +++ b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c @@ -1224,6 +1224,10 @@ TcgScaleEventLog ( 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); + // Free the old log region. gBS->FreePages (OldLasa, EFI_SIZE_TO_PAGES ((UINTN)OldLaml)); From 4d886b731e4f176d855af275432cd32bbe876807 Mon Sep 17 00:00:00 2001 From: rdiaz Date: Wed, 13 May 2026 00:08:50 +0000 Subject: [PATCH 8/8] Reworded the post-ReadyToBoot error log message to be less confusing. --- SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c index 78a9cbcffdd..de2784aaa64 100644 --- a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c +++ b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c @@ -1283,7 +1283,7 @@ TcgLogDynamicScalingNeeded ( // Log an error if we attempt to scale post ReadyToBoot. if (mReadyToBoot) { - DEBUG ((DEBUG_ERROR, "Scaling post ReadyToBoot is invalid!\n")); + DEBUG ((DEBUG_ERROR, "Unexpected dynamic scaling occurring post ReadyToBoot!\n")); } return TRUE;