[PATCH v2 3/6] efi_loader: add boot variable measurement

Masahisa Kojima masahisa.kojima at linaro.org
Thu Jul 15 10:12:55 CEST 2021


On Thu, 15 Jul 2021 at 15:59, Heinrich Schuchardt <xypron.glpk at gmx.de> wrote:
>
>
>
> On 7/14/21 3:00 PM, Masahisa Kojima wrote:
> > TCG PC Client PFP spec requires to measure "Boot####"
> > and "BootOrder" variables, EV_SEPARATOR event prior
> > to the Ready to Boot invocation.
> > Since u-boot does not implement Ready to Boot event,
> > these measurements are performed when efi_start_image() is called.
> >
> > TCG spec also requires to measure "Calling EFI Application from
> > Boot Option" for each boot attempt, and "Returning from EFI
> > Application from Boot Option" if a boot device returns control
> > back to the Boot Manager.
> >
> > Signed-off-by: Masahisa Kojima <masahisa.kojima at linaro.org>
> > ---
> >
> > Changes in v2:
> > - use efi_create_indexed_name() for "Boot####" variable
> >
> >   include/efi_loader.h          |   4 ++
> >   include/tpm-v2.h              |  18 ++++-
> >   lib/efi_loader/efi_boottime.c |  20 ++++++
> >   lib/efi_loader/efi_tcg2.c     | 121 ++++++++++++++++++++++++++++++++++
> >   4 files changed, 162 insertions(+), 1 deletion(-)
> >
> > diff --git a/include/efi_loader.h b/include/efi_loader.h
> > index b81180cfda..703b675950 100644
> > --- a/include/efi_loader.h
> > +++ b/include/efi_loader.h
> > @@ -407,6 +407,10 @@ efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size);
> >   efi_status_t efi_init_variables(void);
> >   /* Notify ExitBootServices() is called */
> >   void efi_variables_boot_exit_notify(void);
> > +/* Measure efi application invocation */
> > +efi_status_t EFIAPI efi_tcg2_measure_efi_app_invocation(void);
> > +/* Measure efi application exit */
> > +efi_status_t EFIAPI efi_tcg2_measure_efi_app_exit(void);
> >   /* Called by bootefi to initialize root node */
> >   efi_status_t efi_root_node_register(void);
> >   /* Called by bootefi to initialize runtime */
> > diff --git a/include/tpm-v2.h b/include/tpm-v2.h
> > index 247b386967..325c73006e 100644
> > --- a/include/tpm-v2.h
> > +++ b/include/tpm-v2.h
> > @@ -73,7 +73,7 @@ struct udevice;
> >   /*
> >    * event types, cf.
> >    * "TCG PC Client Platform Firmware Profile Specification", Family "2.0"
> > - * rev 1.04, June 3, 2019
> > + * Level 00 Version 1.05 Revision 23, May 7, 2021
> >    */
> >   #define EV_EFI_EVENT_BASE                   ((u32)0x80000000)
> >   #define EV_EFI_VARIABLE_DRIVER_CONFIG               ((u32)0x80000001)
> > @@ -85,8 +85,24 @@ struct udevice;
> >   #define EV_EFI_ACTION                               ((u32)0x80000007)
> >   #define EV_EFI_PLATFORM_FIRMWARE_BLOB               ((u32)0x80000008)
> >   #define EV_EFI_HANDOFF_TABLES                       ((u32)0x80000009)
> > +#define EV_EFI_PLATFORM_FIRMWARE_BLOB2               ((u32)0x8000000A)
> > +#define EV_EFI_HANDOFF_TABLES2                       ((u32)0x8000000B)
> > +#define EV_EFI_VARIABLE_BOOT2                        ((u32)0x8000000C)
> >   #define EV_EFI_HCRTM_EVENT                  ((u32)0x80000010)
> >   #define EV_EFI_VARIABLE_AUTHORITY           ((u32)0x800000E0)
> > +#define EV_EFI_SPDM_FIRMWARE_BLOB            ((u32)0x800000E1)
> > +#define EV_EFI_SPDM_FIRMWARE_CONFIG          ((u32)0x800000E2)
> > +
> > +#define EFI_CALLING_EFI_APPLICATION         \
> > +     "Calling EFI Application from Boot Option"
> > +#define EFI_RETURNING_FROM_EFI_APPLICATION  \
> > +     "Returning from EFI Application from Boot Option"
> > +#define EFI_EXIT_BOOT_SERVICES_INVOCATION   \
> > +     "Exit Boot Services Invocation"
> > +#define EFI_EXIT_BOOT_SERVICES_FAILED       \
> > +     "Exit Boot Services Returned with Failure"
> > +#define EFI_EXIT_BOOT_SERVICES_SUCCEEDED    \
> > +     "Exit Boot Services Returned with Success"
> >
> >   /* TPMS_TAGGED_PROPERTY Structure */
> >   struct tpms_tagged_property {
> > diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
> > index f6d5ba05e3..2914800c56 100644
> > --- a/lib/efi_loader/efi_boottime.c
> > +++ b/lib/efi_loader/efi_boottime.c
> > @@ -2993,6 +2993,16 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
> >       image_obj->exit_status = &exit_status;
> >       image_obj->exit_jmp = &exit_jmp;
> >
> > +     if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {
> > +             if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION) {
> > +                     ret = efi_tcg2_measure_efi_app_invocation();
> > +                     if (ret != EFI_SUCCESS) {
> > +                             EFI_PRINT("tcg2 measurement fails(0x%lx)\n",
> > +                                       ret);
>
> This will only show when enabling debug messages.
> Should this be log_warning()?
>
> > +                     }
> > +             }
> > +     }
> > +
> >       /* call the image! */
> >       if (setjmp(&exit_jmp)) {
> >               /*
> > @@ -3251,6 +3261,16 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,
> >           exit_status != EFI_SUCCESS)
> >               efi_delete_image(image_obj, loaded_image_protocol);
> >
> > +     if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {
> > +             if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION) {
> > +                     ret = efi_tcg2_measure_efi_app_exit();
> > +                     if (ret != EFI_SUCCESS) {
> > +                             EFI_PRINT("tcg2 measurement fails(0x%lx)\n",
> > +                                       ret);
>
> ditto
>
> > +                     }
> > +             }
> > +     }
> > +
> >       /* Make sure entry/exit counts for EFI world cross-overs match */
> >       EFI_EXIT(exit_status);
> >
> > diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c
> > index 12db6f6b7c..d59fc5a890 100644
> > --- a/lib/efi_loader/efi_tcg2.c
> > +++ b/lib/efi_loader/efi_tcg2.c
> > @@ -35,6 +35,7 @@ struct event_log_buffer {
> >   };
> >
> >   static struct event_log_buffer event_log;
> > +static bool tcg2_efi_app_invoked;
> >   /*
> >    * When requesting TPM2_CAP_TPM_PROPERTIES the value is on a standard offset.
> >    * Since the current tpm2_get_capability() response buffers starts at
> > @@ -1383,6 +1384,126 @@ static efi_status_t tcg2_measure_variable(struct udevice *dev, u32 pcr_index,
> >       return ret;
> >   }
> >
> > +/**
> > + * tcg2_measure_boot_variable() - measure boot variables
> > + *
> > + * @dev:     TPM device
> > + *
> > + * Return:   status code
> > + */
> > +static efi_status_t tcg2_measure_boot_variable(struct udevice *dev)
> > +{
> > +     u16 *boot_order;
> > +     u16 *boot_index;
> > +     u16 var_name[] = L"BootOrder";
> > +     u16 boot_name[] = L"Boot####";
> > +     u8 *bootvar;
> > +     efi_uintn_t var_data_size;
> > +     u32 count, i;
> > +     efi_status_t ret;
> > +
> > +     boot_order = efi_get_var(var_name, &efi_global_variable_guid,
> > +                              &var_data_size);
> > +     if (!boot_order) {
> > +             log_info("BootOrder not defined\n");
>
> The user should know it anyway. Nothing noteworthy in the context of
> measurement.
>
> > +             ret = EFI_NOT_FOUND;
> > +             goto error;
> > +     }
> > +
> > +     ret = tcg2_measure_variable(dev, 1, EV_EFI_VARIABLE_BOOT2, var_name,
> > +                                 &efi_global_variable_guid, var_data_size,
> > +                                 (u8 *)boot_order);
> > +     if (ret != EFI_SUCCESS)
> > +             goto error;
> > +
> > +     count = var_data_size / sizeof(*boot_order);
> > +     boot_index = boot_order;
> > +     for (i = 0; i < count; i++) {
> > +             efi_create_indexed_name(boot_name, sizeof(boot_name), "Boot", *boot_index++);
> > +
> > +             bootvar = efi_get_var(boot_name, &efi_global_variable_guid,
> > +                                   &var_data_size);
>
> Does measurement of Boot#### and BootOrder imply for measured boot that
> a board will not boot into Windows if I change the boot option for Debian?

Basically, measured boot does not affect system will boot or not.
Measured boot records the boot configuration and boot sequence by extending
eventlog and PCRs.
After boot , Attestation process will decide system behavior depending
on the PCRs.

Thanks,
Masahisa Kojima

>
> Best regards
>
> Heinrich
>
> > +
> > +             if (!bootvar) {
> > +                     log_info("%ls not found\n", boot_name);
> > +                     continue;
> > +             }
> > +
> > +             ret = tcg2_measure_variable(dev, 1, EV_EFI_VARIABLE_BOOT2,
> > +                                         boot_name,
> > +                                         &efi_global_variable_guid,
> > +                                         var_data_size, bootvar);
> > +             free(bootvar);
> > +             if (ret != EFI_SUCCESS)
> > +                     goto error;
> > +     }
> > +
> > +error:
> > +     free(boot_order);
> > +     return ret;
> > +}
> > +
> > +/**
> > + * efi_tcg2_measure_efi_app_invocation() - measure efi app invocation
> > + *
> > + * Return:   status code
> > + */
> > +efi_status_t EFIAPI efi_tcg2_measure_efi_app_invocation(void)
> > +{
> > +     efi_status_t ret;
> > +     u32 pcr_index;
> > +     struct udevice *dev;
> > +     u32 event = 0;
> > +
> > +     if (tcg2_efi_app_invoked)
> > +             return EFI_SUCCESS;
> > +
> > +     ret = platform_get_tpm2_device(&dev);
> > +     if (ret != EFI_SUCCESS)
> > +             return ret;
> > +
> > +     ret = tcg2_measure_boot_variable(dev);
> > +     if (ret != EFI_SUCCESS)
> > +             goto out;
> > +
> > +     ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION,
> > +                              strlen(EFI_CALLING_EFI_APPLICATION),
> > +                              (u8 *)EFI_CALLING_EFI_APPLICATION);
> > +     if (ret != EFI_SUCCESS)
> > +             goto out;
> > +
> > +     for (pcr_index = 0; pcr_index <= 7; pcr_index++) {
> > +             ret = tcg2_measure_event(dev, pcr_index, EV_SEPARATOR,
> > +                                      sizeof(event), (u8 *)&event);
> > +             if (ret != EFI_SUCCESS)
> > +                     goto out;
> > +     }
> > +
> > +     tcg2_efi_app_invoked = true;
> > +out:
> > +     return ret;
> > +}
> > +
> > +/**
> > + * efi_tcg2_measure_efi_app_exit() - measure efi app exit
> > + *
> > + * Return:   status code
> > + */
> > +efi_status_t EFIAPI efi_tcg2_measure_efi_app_exit(void)
> > +{
> > +     efi_status_t ret;
> > +     struct udevice *dev;
> > +
> > +     ret = platform_get_tpm2_device(&dev);
> > +     if (ret != EFI_SUCCESS)
> > +             return ret;
> > +
> > +     ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION,
> > +                              strlen(EFI_RETURNING_FROM_EFI_APPLICATION),
> > +                              (u8 *)EFI_RETURNING_FROM_EFI_APPLICATION);
> > +     return ret;
> > +}
> > +
> >   /**
> >    * tcg2_measure_secure_boot_variable() - measure secure boot variables
> >    *
> >


More information about the U-Boot mailing list