| /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
| |
| #if ENABLE_TPM |
| |
| #include <efi.h> |
| #include <efilib.h> |
| |
| #include "macro-fundamental.h" |
| #include "measure.h" |
| #include "missing_efi.h" |
| #include "util.h" |
| |
| static EFI_STATUS tpm1_measure_to_pcr_and_event_log( |
| const EFI_TCG *tcg, |
| UINT32 pcrindex, |
| EFI_PHYSICAL_ADDRESS buffer, |
| UINTN buffer_size, |
| const CHAR16 *description) { |
| |
| _cleanup_freepool_ TCG_PCR_EVENT *tcg_event = NULL; |
| EFI_PHYSICAL_ADDRESS event_log_last; |
| UINT32 event_number = 1; |
| UINTN desc_len; |
| |
| assert(tcg); |
| assert(description); |
| |
| desc_len = StrSize(description); |
| tcg_event = xallocate_zero_pool(offsetof(TCG_PCR_EVENT, Event) + desc_len); |
| *tcg_event = (TCG_PCR_EVENT) { |
| .EventSize = desc_len, |
| .PCRIndex = pcrindex, |
| .EventType = EV_IPL, |
| }; |
| CopyMem(tcg_event->Event, description, desc_len); |
| |
| return tcg->HashLogExtendEvent( |
| (EFI_TCG *) tcg, |
| buffer, buffer_size, |
| TCG_ALG_SHA, |
| tcg_event, |
| &event_number, |
| &event_log_last); |
| } |
| |
| static EFI_STATUS tpm2_measure_to_pcr_and_event_log( |
| EFI_TCG2 *tcg, |
| UINT32 pcrindex, |
| EFI_PHYSICAL_ADDRESS buffer, |
| UINT64 buffer_size, |
| const CHAR16 *description) { |
| |
| _cleanup_freepool_ EFI_TCG2_EVENT *tcg_event = NULL; |
| UINTN desc_len; |
| |
| assert(tcg); |
| assert(description); |
| |
| desc_len = StrSize(description); |
| tcg_event = xallocate_zero_pool(offsetof(EFI_TCG2_EVENT, Event) + desc_len); |
| *tcg_event = (EFI_TCG2_EVENT) { |
| .Size = offsetof(EFI_TCG2_EVENT, Event) + desc_len, |
| .Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER), |
| .Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION, |
| .Header.PCRIndex = pcrindex, |
| .Header.EventType = EV_IPL, |
| }; |
| |
| CopyMem(tcg_event->Event, description, desc_len); |
| |
| return tcg->HashLogExtendEvent( |
| tcg, |
| 0, |
| buffer, buffer_size, |
| tcg_event); |
| } |
| |
| static EFI_TCG *tcg1_interface_check(void) { |
| EFI_PHYSICAL_ADDRESS event_log_location, event_log_last_entry; |
| TCG_BOOT_SERVICE_CAPABILITY capability = { |
| .Size = sizeof(capability), |
| }; |
| EFI_STATUS status; |
| UINT32 features; |
| EFI_TCG *tcg; |
| |
| status = LibLocateProtocol((EFI_GUID*) EFI_TCG_GUID, (void **) &tcg); |
| if (EFI_ERROR(status)) |
| return NULL; |
| |
| status = tcg->StatusCheck( |
| tcg, |
| &capability, |
| &features, |
| &event_log_location, |
| &event_log_last_entry); |
| if (EFI_ERROR(status)) |
| return NULL; |
| |
| if (capability.TPMDeactivatedFlag) |
| return NULL; |
| |
| if (!capability.TPMPresentFlag) |
| return NULL; |
| |
| return tcg; |
| } |
| |
| static EFI_TCG2 * tcg2_interface_check(void) { |
| EFI_TCG2_BOOT_SERVICE_CAPABILITY capability = { |
| .Size = sizeof(capability), |
| }; |
| EFI_STATUS status; |
| EFI_TCG2 *tcg; |
| |
| status = LibLocateProtocol((EFI_GUID*) EFI_TCG2_GUID, (void **) &tcg); |
| if (EFI_ERROR(status)) |
| return NULL; |
| |
| status = tcg->GetCapability(tcg, &capability); |
| if (EFI_ERROR(status)) |
| return NULL; |
| |
| if (capability.StructureVersion.Major == 1 && |
| capability.StructureVersion.Minor == 0) { |
| TCG_BOOT_SERVICE_CAPABILITY *caps_1_0 = |
| (TCG_BOOT_SERVICE_CAPABILITY*) &capability; |
| if (caps_1_0->TPMPresentFlag) |
| return tcg; |
| } |
| |
| if (!capability.TPMPresentFlag) |
| return NULL; |
| |
| return tcg; |
| } |
| |
| BOOLEAN tpm_present(void) { |
| return tcg2_interface_check() || tcg1_interface_check(); |
| } |
| |
| EFI_STATUS tpm_log_event(UINT32 pcrindex, EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description) { |
| EFI_TCG *tpm1; |
| EFI_TCG2 *tpm2; |
| |
| assert(description); |
| |
| /* PCR disabled */ |
| if (pcrindex == UINT32_MAX) |
| return EFI_SUCCESS; |
| |
| tpm2 = tcg2_interface_check(); |
| if (tpm2) |
| return tpm2_measure_to_pcr_and_event_log(tpm2, pcrindex, buffer, buffer_size, description); |
| |
| tpm1 = tcg1_interface_check(); |
| if (tpm1) |
| return tpm1_measure_to_pcr_and_event_log(tpm1, pcrindex, buffer, buffer_size, description); |
| |
| /* No active TPM found, so don't return an error */ |
| return EFI_SUCCESS; |
| } |
| |
| EFI_STATUS tpm_log_load_options(const CHAR16 *load_options) { |
| EFI_STATUS err; |
| |
| /* Measures a load options string into the TPM2, i.e. the kernel command line */ |
| |
| for (UINTN i = 0; i < 2; i++) { |
| UINT32 pcr = i == 0 ? TPM_PCR_INDEX_KERNEL_PARAMETERS : TPM_PCR_INDEX_KERNEL_PARAMETERS_COMPAT; |
| |
| err = tpm_log_event(pcr, |
| POINTER_TO_PHYSICAL_ADDRESS(load_options), |
| StrSize(load_options), load_options); |
| if (EFI_ERROR(err)) |
| return log_error_status_stall(err, L"Unable to add load options (i.e. kernel command) line measurement to PCR %u: %r", pcr, err); |
| } |
| |
| return EFI_SUCCESS; |
| } |
| |
| #endif |