diff options
| -rw-r--r-- | Makefile.am | 4 | ||||
| -rw-r--r-- | configure.ac | 23 | ||||
| -rw-r--r-- | src/boot/efi/boot.c | 13 | ||||
| -rw-r--r-- | src/boot/efi/measure.c | 312 | ||||
| -rw-r--r-- | src/boot/efi/measure.h | 21 | ||||
| -rw-r--r-- | src/boot/efi/stub.c | 13 | 
6 files changed, 386 insertions, 0 deletions
| diff --git a/Makefile.am b/Makefile.am index 3b7cc1e33e..9f051e2954 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2701,6 +2701,7 @@ systemd_boot_headers = \  	src/boot/efi/console.h \  	src/boot/efi/graphics.h \  	src/boot/efi/pefile.h \ +	src/boot/efi/measure.h \  	src/boot/efi/disk.h  systemd_boot_sources = \ @@ -2709,6 +2710,7 @@ systemd_boot_sources = \  	src/boot/efi/graphics.c \  	src/boot/efi/pefile.c \  	src/boot/efi/disk.c \ +	src/boot/efi/measure.c \  	src/boot/efi/boot.c  EXTRA_DIST += $(systemd_boot_sources) $(systemd_boot_headers) @@ -2745,6 +2747,7 @@ stub_headers = \  	src/boot/efi/disk.h \  	src/boot/efi/graphics.h \  	src/boot/efi/splash.h \ +	src/boot/efi/measure.h \  	src/boot/efi/linux.h  stub_sources = \ @@ -2754,6 +2757,7 @@ stub_sources = \  	src/boot/efi/graphics.c \  	src/boot/efi/splash.c \  	src/boot/efi/linux.c \ +	src/boot/efi/measure.c \  	src/boot/efi/stub.c  EXTRA_DIST += \ diff --git a/configure.ac b/configure.ac index 5fd73c59f1..59cc9fd99e 100644 --- a/configure.ac +++ b/configure.ac @@ -1218,6 +1218,28 @@ AS_IF([test "x$enable_gnuefi" != "xno"], [  AM_CONDITIONAL(HAVE_GNUEFI, [test "x$have_gnuefi" = xyes])  # ------------------------------------------------------------------------------ +have_tpm=no +AC_ARG_ENABLE([tpm], AS_HELP_STRING([--enable-tpm],[Enable optional TPM support]), +                [case "${enableval}" in +                        yes) have_tpm=yes ;; +                        no) have_tpm=no ;; +                        *) AC_MSG_ERROR(bad value ${enableval} for --enable-tpm) ;; +                esac], +                [have_tpm=no]) + +if test "x${have_tpm}" != xno ; then +        AC_DEFINE(SD_BOOT_LOG_TPM, 1, [Define if TPM should be used to log events and extend the registers]) +fi + +AC_ARG_WITH(tpm-pcrindex, +        AS_HELP_STRING([--with-tpm-pcrindex=<NUM>], +                [TPM PCR register number to use]), +        [SD_TPM_PCR="$withval"], +        [SD_TPM_PCR="8"]) + +AC_DEFINE_UNQUOTED(SD_TPM_PCR, [$SD_TPM_PCR], [TPM PCR register number to use]) + +# ------------------------------------------------------------------------------  have_kdbus=no  AC_ARG_ENABLE(kdbus, AS_HELP_STRING([--disable-kdbus], [do not connect to kdbus by default]))  if test "x$enable_kdbus" != "xno"; then @@ -1571,6 +1593,7 @@ AC_MSG_RESULT([          dbus:                    ${have_dbus}          nss-myhostname:          ${have_myhostname}          hwdb:                    ${enable_hwdb} +        tpm:                     ${have_tpm}          kdbus:                   ${have_kdbus}          Python:                  ${have_python}          man pages:               ${have_manpages} diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index 893980071f..30c1ead1aa 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -22,6 +22,7 @@  #include "linux.h"  #include "pefile.h"  #include "util.h" +#include "measure.h"  #ifndef EFI_OS_INDICATIONS_BOOT_TO_FW_UI  #define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001ULL @@ -1644,6 +1645,18 @@ static EFI_STATUS image_start(EFI_HANDLE parent_image, const Config *config, con                  }                  loaded_image->LoadOptions = options;                  loaded_image->LoadOptionsSize = (StrLen(loaded_image->LoadOptions)+1) * sizeof(CHAR16); + +#ifdef SD_BOOT_LOG_TPM +                /* Try to log any options to the TPM, escpecially to catch manually edited options */ +                err = tpm_log_event(SD_TPM_PCR, +                                    (EFI_PHYSICAL_ADDRESS) loaded_image->LoadOptions, +                                    loaded_image->LoadOptionsSize, loaded_image->LoadOptions); +                if (EFI_ERROR(err)) { +                        Print(L"Unable to add image options measurement: %r", err); +                        uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000); +                        return err; +                } +#endif          }          efivar_set_time_usec(L"LoaderTimeExecUSec", 0); diff --git a/src/boot/efi/measure.c b/src/boot/efi/measure.c new file mode 100644 index 0000000000..7c016387c1 --- /dev/null +++ b/src/boot/efi/measure.c @@ -0,0 +1,312 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + */ + +#ifdef SD_BOOT_LOG_TPM + +#include <efi.h> +#include <efilib.h> +#include "measure.h" + +#define EFI_TCG_PROTOCOL_GUID { 0xf541796d, 0xa62e, 0x4954, {0xa7, 0x75, 0x95, 0x84, 0xf6, 0x1b, 0x9c, 0xdd} } + +typedef struct _TCG_VERSION { +        UINT8 Major; +        UINT8 Minor; +        UINT8 RevMajor; +        UINT8 RevMinor; +} TCG_VERSION; + +typedef struct _TCG_BOOT_SERVICE_CAPABILITY { +        UINT8 Size; +        struct _TCG_VERSION StructureVersion; +        struct _TCG_VERSION ProtocolSpecVersion; +        UINT8 HashAlgorithmBitmap; +        BOOLEAN TPMPresentFlag; +        BOOLEAN TPMDeactivatedFlag; +} TCG_BOOT_SERVICE_CAPABILITY; + +typedef UINT32 TCG_ALGORITHM_ID; +#define TCG_ALG_SHA 0x00000004  // The SHA1 algorithm + +#define SHA1_DIGEST_SIZE 20 + +typedef struct _TCG_DIGEST { +        UINT8 Digest[SHA1_DIGEST_SIZE]; +} TCG_DIGEST; + +#define EV_IPL 13 + +typedef struct _TCG_PCR_EVENT { +        UINT32 PCRIndex; +        UINT32 EventType; +        struct _TCG_DIGEST digest; +        UINT32 EventSize; +        UINT8 Event[1]; +} TCG_PCR_EVENT; + +INTERFACE_DECL(_EFI_TCG); + +typedef EFI_STATUS(EFIAPI * EFI_TCG_STATUS_CHECK) (IN struct _EFI_TCG * This, +                                                   OUT struct _TCG_BOOT_SERVICE_CAPABILITY * ProtocolCapability, +                                                   OUT UINT32 * TCGFeatureFlags, +                                                   OUT EFI_PHYSICAL_ADDRESS * EventLogLocation, +                                                   OUT EFI_PHYSICAL_ADDRESS * EventLogLastEntry); + +typedef EFI_STATUS(EFIAPI * EFI_TCG_HASH_ALL) (IN struct _EFI_TCG * This, +                                               IN UINT8 * HashData, +                                               IN UINT64 HashDataLen, +                                               IN TCG_ALGORITHM_ID AlgorithmId, +                                               IN OUT UINT64 * HashedDataLen, IN OUT UINT8 ** HashedDataResult); + +typedef EFI_STATUS(EFIAPI * EFI_TCG_LOG_EVENT) (IN struct _EFI_TCG * This, +                                                IN struct _TCG_PCR_EVENT * TCGLogData, +                                                IN OUT UINT32 * EventNumber, IN UINT32 Flags); + +typedef EFI_STATUS(EFIAPI * EFI_TCG_PASS_THROUGH_TO_TPM) (IN struct _EFI_TCG * This, +                                                          IN UINT32 TpmInputParameterBlockSize, +                                                          IN UINT8 * TpmInputParameterBlock, +                                                          IN UINT32 TpmOutputParameterBlockSize, +                                                          IN UINT8 * TpmOutputParameterBlock); + +typedef EFI_STATUS(EFIAPI * EFI_TCG_HASH_LOG_EXTEND_EVENT) (IN struct _EFI_TCG * This, +                                                            IN EFI_PHYSICAL_ADDRESS HashData, +                                                            IN UINT64 HashDataLen, +                                                            IN TCG_ALGORITHM_ID AlgorithmId, +                                                            IN struct _TCG_PCR_EVENT * TCGLogData, +                                                            IN OUT UINT32 * EventNumber, +                                                            OUT EFI_PHYSICAL_ADDRESS * EventLogLastEntry); + +typedef struct _EFI_TCG { +        EFI_TCG_STATUS_CHECK StatusCheck; +        EFI_TCG_HASH_ALL HashAll; +        EFI_TCG_LOG_EVENT LogEvent; +        EFI_TCG_PASS_THROUGH_TO_TPM PassThroughToTPM; +        EFI_TCG_HASH_LOG_EXTEND_EVENT HashLogExtendEvent; +} EFI_TCG; + +#define EFI_TCG2_PROTOCOL_GUID {0x607f766c, 0x7455, 0x42be, { 0x93, 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f }} + +typedef struct tdEFI_TCG2_PROTOCOL EFI_TCG2_PROTOCOL; + +typedef struct tdEFI_TCG2_VERSION { +        UINT8 Major; +        UINT8 Minor; +} EFI_TCG2_VERSION; + +typedef UINT32 EFI_TCG2_EVENT_LOG_BITMAP; +typedef UINT32 EFI_TCG2_EVENT_LOG_FORMAT; +typedef UINT32 EFI_TCG2_EVENT_ALGORITHM_BITMAP; + +#define EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2       0x00000001 +#define EFI_TCG2_EVENT_LOG_FORMAT_TCG_2         0x00000002 + +typedef struct tdEFI_TCG2_BOOT_SERVICE_CAPABILITY { +        UINT8 Size; +        EFI_TCG2_VERSION StructureVersion; +        EFI_TCG2_VERSION ProtocolVersion; +        EFI_TCG2_EVENT_ALGORITHM_BITMAP HashAlgorithmBitmap; +        EFI_TCG2_EVENT_LOG_BITMAP SupportedEventLogs; +        BOOLEAN TPMPresentFlag; +        UINT16 MaxCommandSize; +        UINT16 MaxResponseSize; +        UINT32 ManufacturerID; +        UINT32 NumberOfPCRBanks; +        EFI_TCG2_EVENT_ALGORITHM_BITMAP ActivePcrBanks; +} EFI_TCG2_BOOT_SERVICE_CAPABILITY; + +#define EFI_TCG2_EVENT_HEADER_VERSION  1 + +typedef struct { +        UINT32 HeaderSize; +        UINT16 HeaderVersion; +        UINT32 PCRIndex; +        UINT32 EventType; +} EFI_TCG2_EVENT_HEADER; + +typedef struct tdEFI_TCG2_EVENT { +        UINT32 Size; +        EFI_TCG2_EVENT_HEADER Header; +        UINT8 Event[1]; +} EFI_TCG2_EVENT; + +typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_CAPABILITY) (IN EFI_TCG2_PROTOCOL * This, +                                                      IN OUT EFI_TCG2_BOOT_SERVICE_CAPABILITY * ProtocolCapability); + +typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_EVENT_LOG) (IN EFI_TCG2_PROTOCOL * This, +                                                     IN EFI_TCG2_EVENT_LOG_FORMAT EventLogFormat, +                                                     OUT EFI_PHYSICAL_ADDRESS * EventLogLocation, +                                                     OUT EFI_PHYSICAL_ADDRESS * EventLogLastEntry, +                                                     OUT BOOLEAN * EventLogTruncated); + +typedef EFI_STATUS(EFIAPI * EFI_TCG2_HASH_LOG_EXTEND_EVENT) (IN EFI_TCG2_PROTOCOL * This, +                                                             IN UINT64 Flags, +                                                             IN EFI_PHYSICAL_ADDRESS DataToHash, +                                                             IN UINT64 DataToHashLen, IN EFI_TCG2_EVENT * EfiTcgEvent); + +typedef EFI_STATUS(EFIAPI * EFI_TCG2_SUBMIT_COMMAND) (IN EFI_TCG2_PROTOCOL * This, +                                                      IN UINT32 InputParameterBlockSize, +                                                      IN UINT8 * InputParameterBlock, +                                                      IN UINT32 OutputParameterBlockSize, IN UINT8 * OutputParameterBlock); + +typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_ACTIVE_PCR_BANKS) (IN EFI_TCG2_PROTOCOL * This, OUT UINT32 * ActivePcrBanks); + +typedef EFI_STATUS(EFIAPI * EFI_TCG2_SET_ACTIVE_PCR_BANKS) (IN EFI_TCG2_PROTOCOL * This, IN UINT32 ActivePcrBanks); + +typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_RESULT_OF_SET_ACTIVE_PCR_BANKS) (IN EFI_TCG2_PROTOCOL * This, +                                                                          OUT UINT32 * OperationPresent, OUT UINT32 * Response); + +typedef struct tdEFI_TCG2_PROTOCOL { +        EFI_TCG2_GET_CAPABILITY GetCapability; +        EFI_TCG2_GET_EVENT_LOG GetEventLog; +        EFI_TCG2_HASH_LOG_EXTEND_EVENT HashLogExtendEvent; +        EFI_TCG2_SUBMIT_COMMAND SubmitCommand; +        EFI_TCG2_GET_ACTIVE_PCR_BANKS GetActivePcrBanks; +        EFI_TCG2_SET_ACTIVE_PCR_BANKS SetActivePcrBanks; +        EFI_TCG2_GET_RESULT_OF_SET_ACTIVE_PCR_BANKS GetResultOfSetActivePcrBanks; +} EFI_TCG2; + + +static EFI_STATUS tpm1_measure_to_pcr_and_event_log(const EFI_TCG *tcg, UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, +                                                    UINTN buffer_size, const CHAR16 *description) { +        EFI_STATUS status; +        TCG_PCR_EVENT *tcg_event; +        UINT32 event_number; +        EFI_PHYSICAL_ADDRESS event_log_last; +        UINTN desc_len; + +        desc_len = (StrLen(description) + 1) * sizeof(CHAR16); + +        tcg_event = AllocateZeroPool(desc_len + sizeof(TCG_PCR_EVENT)); + +        if (tcg_event == NULL) +                return EFI_OUT_OF_RESOURCES; + +        tcg_event->EventSize = desc_len; +        CopyMem((VOID *) & tcg_event->Event[0], (VOID *) description, desc_len); + +        tcg_event->PCRIndex = pcrindex; +        tcg_event->EventType = EV_IPL; + +        event_number = 1; +        status = uefi_call_wrapper(tcg->HashLogExtendEvent, 7, +                                   tcg, buffer, buffer_size, TCG_ALG_SHA, tcg_event, &event_number, &event_log_last); + +        if (EFI_ERROR(status)) +                return status; + +        uefi_call_wrapper(BS->FreePool, 1, tcg_event); + +        return EFI_SUCCESS; +} + + +static EFI_STATUS tpm2_measure_to_pcr_and_event_log(const EFI_TCG2 *tcg, UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, +                                                    UINT64 buffer_size, const CHAR16 *description) { +        EFI_STATUS status; +        EFI_TCG2_EVENT *tcg_event; +        UINTN desc_len; + +        desc_len = StrLen(description) * sizeof(CHAR16); + +        tcg_event = AllocateZeroPool(sizeof(*tcg_event) - sizeof(tcg_event->Event) + desc_len + 1); + +        if (tcg_event == NULL) +                return EFI_OUT_OF_RESOURCES; + +        tcg_event->Size = sizeof(EFI_TCG2_EVENT) - sizeof(tcg_event->Event) + desc_len + 1; +        tcg_event->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER); +        tcg_event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION; +        tcg_event->Header.PCRIndex = pcrindex; +        tcg_event->Header.EventType = EV_IPL; + +        CopyMem((VOID *) tcg_event->Event, (VOID *) description, desc_len); + +        status = uefi_call_wrapper(tcg->HashLogExtendEvent, 5, tcg, 0, buffer, buffer_size, tcg_event); + +        uefi_call_wrapper(BS->FreePool, 1, tcg_event); + +        if (EFI_ERROR(status)) +                return status; + +        return EFI_SUCCESS; +} + +static EFI_TCG * tcg1_interface_check(void) { +        EFI_GUID tpm_guid = EFI_TCG_PROTOCOL_GUID; +        EFI_STATUS status; +        EFI_TCG *tcg; +        TCG_BOOT_SERVICE_CAPABILITY capability; +        UINT32 features; +        EFI_PHYSICAL_ADDRESS event_log_location; +        EFI_PHYSICAL_ADDRESS event_log_last_entry; + +        status = LibLocateProtocol(&tpm_guid, (void **) &tcg); + +        if (EFI_ERROR(status)) +                return NULL; + +        capability.Size = (UINT8) sizeof(capability); +        status = uefi_call_wrapper(tcg->StatusCheck, 5, 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_GUID tpm2_guid = EFI_TCG2_PROTOCOL_GUID; +        EFI_STATUS status; +        EFI_TCG2 *tcg; +        EFI_TCG2_BOOT_SERVICE_CAPABILITY capability; + +        status = LibLocateProtocol(&tpm2_guid, (void **) &tcg); + +        if (EFI_ERROR(status)) +                return NULL; + +        capability.Size = (UINT8) sizeof(capability); +        status = uefi_call_wrapper(tcg->GetCapability, 2, tcg, &capability); + +        if (EFI_ERROR(status)) +                return NULL; + +        if (!capability.TPMPresentFlag) +                return NULL; + +        return tcg; +} + +EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description) { +        EFI_TCG *tpm1; +        EFI_TCG2 *tpm2; + +        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; +} + +#endif diff --git a/src/boot/efi/measure.h b/src/boot/efi/measure.h new file mode 100644 index 0000000000..a2cfe817d0 --- /dev/null +++ b/src/boot/efi/measure.h @@ -0,0 +1,21 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + */ +#ifndef __SDBOOT_MEASURE_H +#define __SDBOOT_MEASURE_H + +#ifndef SD_TPM_PCR +#define SD_TPM_PCR 8 +#endif + +EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description); +#endif diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c index 9633bc1792..1e250f34f4 100644 --- a/src/boot/efi/stub.c +++ b/src/boot/efi/stub.c @@ -20,6 +20,7 @@  #include "pefile.h"  #include "splash.h"  #include "util.h" +#include "measure.h"  /* magic string to find in the binary image */  static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-stub " VERSION " ####"; @@ -97,6 +98,18 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {                  for (i = 0; i < cmdline_len; i++)                          line[i] = options[i];                  cmdline = line; + +#ifdef SD_BOOT_LOG_TPM +                /* Try to log any options to the TPM, escpecially manually edited options */ +                err = tpm_log_event(SD_TPM_PCR, +                                    (EFI_PHYSICAL_ADDRESS) loaded_image->LoadOptions, +                                    loaded_image->LoadOptionsSize, loaded_image->LoadOptions); +                if (EFI_ERROR(err)) { +                        Print(L"Unable to add image options measurement: %r", err); +                        uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000); +                        return err; +                } +#endif          }          /* export the device path this image is started from */ | 
