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. Tests were added via TcgLogTest which includes a DXE driver and a UEFI shell 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. Added the Truncation event marker to the end of the FinalEventLog when it becomes truncated. Added a event signal for when scaling occurs on the normal event log. Consumers can trigger callbacks on this event; the test app uses this to know when scaling occurs. Added an ACPI log region for the ACPI table LAML/LASA. This region does not scale and can become truncated indicated by the Truncation event marker. Signed-off-by: Raymond Diaz <raymonddiaz@microsoft.com> |
||
|---|---|---|
| .. | ||
| MeasureBootPeCoff.c | ||
| README.md | ||
| Tcg2Dxe.c | ||
| Tcg2Dxe.inf | ||
| Tcg2Dxe.uni | ||
| Tcg2DxeExtra.uni | ||
Tcg2Dxe
Tcg2Dxe is a DXE-phase UEFI driver that publishes the TCG2 protocol defined by the TCG EFI Protocol Specification. Its main responsibilites are to expose a standard interface to a TPM device, measure components and events into PCRs, support measured boot, and enable secure boot attestation.
Dynamic Event Log Scaling
The TCG event log is initially allocated with a fixed size defined by a PCD: PcdTcgLogAreaMinLen. As firmware components log measured boot events the log fills up. Traditionally, when the log is full, subsequent events are dropped and the log is marked as truncated.
Tcg2Dxe extends this behavior with dynamic scaling: when the log is about to overflow, the driver doubles its allocation, copies the existing log into the new buffer, and frees the old one. This allows the log to grow as needed and avoids losing events.
How It Works
-
Scaling check — Before logging a TCG 2.0 event,
TcgLogDynamicScalingNeededcalculates whether the new event would exceed the current allocation (EventLogAreaStruct->Laml). -
Reallocation — When scaling is needed,
TcgScaleEventLogallocates a newEfiBootServicesDataregion at twice the current size, copies the existing log, updates theLasa/Lamlfields in the event log area struct, and frees the old region. -
Logging — After scaling, the new event is logged into the resized buffer via
TcgDxeLogEventinside a TPL-raised critical section.
NormalEventLog vs. FinalEventLog
Tcg2Dxe maintains two distinct event log regions:
| Log | Memory Type | Lifetime | Can Scale |
|---|---|---|---|
| Normal log | EfiBootServicesData |
Available until ExitBootServices |
Yes |
| Final Events log | EfiACPIMemoryNVS |
Persistent | No |
| ACPI event 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 toGetEventLogcould contain stale data if the log was scaled after. It is recommended to callGetEventLogeach time access is required. - The Final Events log (
EFI_TCG2_FINAL_EVENTS_TABLE) records events logged afterGetEventLoghas been called. It is installed as a UEFI configuration table so the OS can discover events that occurred between its call toGetEventLogandExitBootServices. Because the Final Events log does not scale, it can become truncated. - The ACPI event log is a fixed-size mirror of the normal log, allocated
in
EfiACPIMemoryNVSand sized fromPcdTcgLogAreaMinLen. Because this region does not scale, it can become truncated. Its address and length are published toPcdTpm2AcpiTableLasaandPcdTpm2AcpiTableLamlsoTcg2Acpipicks them up when populating the TPM2 ACPI table.
Scale Limit
The number of times the normal event log region may be dynamically scaled is
capped by TCG_EVENT_LOG_MAX_SCALE_COUNT. Each successful scale doubles the
allocation, so this caps total growth at PcdTcgLogAreaMinLen << TCG_EVENT_LOG_MAX_SCALE_COUNT.
Once the limit is reached:
TcgScaleEventLogrefuses to scale further and returnsEFI_OUT_OF_RESOURCES.EventLogAreaStruct->EventLogTruncatedis set toTRUE, so subsequentGetEventLogcallers seeEventLogTruncated == TRUE.HashLogExtendEventreturnsEFI_VOLUME_FULLfor events that would have triggered the refused scale.
Scaling Notification (gTcg2EventLogScaledGuid)
Each time the normal log is successfully resized, TcgScaleEventLog calls
EfiEventGroupSignal (&gTcg2EventLogScaledGuid) to notify interested parties
that the log moved in memory.
Consumers that cache the log base address returned by GetEventLog (for
example, parsers walking the log incrementally) must invalidate their cache
on this signal and call GetEventLog again to get the current Lasa/last
entry. A typical consumer:
gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
OnTcgEventLogScaled,
Context,
&gTcg2EventLogScaledGuid,
&Event
);
The event is declared in gTcg2EventLogScaledGuid (see
SecurityPkg/Include/Guid/Tcg2EventLogScaled.h) and listed in Tcg2Dxe.inf.
FinalEventLog Truncation Marker
Because the FinalEventLog is fixed-size and cannot scale, it can fill
up before ExitBootServices. When the next event would overflow the log,
TcgDxeLogEvent calls AppendTruncationMarker which writes a final
EV_NO_ACTION event whose payload is the ASCII string
TCG_LOG_TRUNCATION_EVENT_STRING. The NumberOfEvents counter in
EFI_TCG2_FINAL_EVENTS_TABLE is incremented to include the marker, and
EventLogTruncated is set so subsequent attempts return EFI_VOLUME_FULL
without re-appending the marker.
To guarantee the marker always fits, FinalEventLog initialization in
SetupEventLog subtracts GetTruncationEventSize() from the usable Laml:
mTcgDxeData.FinalEventLogAreaStruct[Index].Laml =
PcdGet32 (PcdTcg2FinalLogAreaLen)
- sizeof (EFI_TCG2_FINAL_EVENTS_TABLE)
- GetTruncationEventSize ();
AppendTruncationMarker temporarily restores this reserved space so
TcgCommLogEvent will accept the marker write.
OS-side and pre-OS consumers can detect FinalEventLog truncation by:
- walking
EFI_TCG2_FINAL_EVENTS_TABLEand inspecting the last entry for anEV_NO_ACTIONevent whose payload begins with"TCG Event Log Truncated".
ACPI Event Log Truncation Marker
The ACPI event log uses the same truncation-marker mechanism as
FinalEventLog. Because it is fixed-size and does not scale, TcgDxeLogEvent
appends an EV_NO_ACTION truncation event whose payload is
TCG_LOG_TRUNCATION_EVENT_STRING when the next event would overflow the
region. EventLogTruncated is then set so subsequent writes silently skip the
ACPI region without re-appending the marker. Unlike FinalEventLog, the
truncated ACPI region does not cause HashLogExtendEvent to return
EFI_VOLUME_FULL.
To guarantee the marker always fits, the ACPI event log initialization in
SetupEventLog subtracts GetTruncationEventSize() from the usable Laml:
mTcgDxeData.AcpiEventLogAreaStruct[Index].Laml =
PcdGet32 (PcdTcgLogAreaMinLen) - GetTruncationEventSize ();
Truncation can be detected by walking the region and inspecting the last
entry for the "TCG Event Log Truncated" payload.