diff mbox series

[v1] efi/libstub: Add Confidential Computing (CC) measurement support

Message ID 20240203075736.3982371-1-sathyanarayanan.kuppuswamy@linux.intel.com
State Superseded
Headers show
Series [v1] efi/libstub: Add Confidential Computing (CC) measurement support | expand

Commit Message

Kuppuswamy Sathyanarayanan Feb. 3, 2024, 7:57 a.m. UTC
If the virtual firmware implements TPM support, TCG2 protocol will be
used for kernel measurements and event logging support. But in CC
environment, not all platforms support or enable the TPM feature. UEFI
specification [1] exposes protocol and interfaces used for kernel
measurements in CC platforms without TPM support.

Currently, the efi-stub only supports the kernel related measurements
for the platform that supports TCG2 protocol. So, extend it add
CC measurement protocol (EFI_CC_MEASUREMENT_PROTOCOL) and event logging
support. Event logging format in the CC environment is the same as
TCG2.

More details about the EFI CC measurements and logging can be found
in [1].

Link: https://uefi.org/specs/UEFI/2.10/38_Confidential_Computing.html#efi-cc-measurement-protocol [1]
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
---
 .../firmware/efi/libstub/efi-stub-helper.c    | 113 +++++++++++++-----
 drivers/firmware/efi/libstub/efistub.h        |  73 +++++++++++
 include/linux/efi.h                           |   1 +
 3 files changed, 159 insertions(+), 28 deletions(-)

Comments

Ard Biesheuvel Feb. 3, 2024, 4:59 p.m. UTC | #1
(cc Ilias)

On Sat, 3 Feb 2024 at 08:58, Kuppuswamy Sathyanarayanan
<sathyanarayanan.kuppuswamy@linux.intel.com> wrote:
>
> If the virtual firmware implements TPM support, TCG2 protocol will be
> used for kernel measurements and event logging support. But in CC
> environment, not all platforms support or enable the TPM feature. UEFI
> specification [1] exposes protocol and interfaces used for kernel
> measurements in CC platforms without TPM support.
>
> Currently, the efi-stub only supports the kernel related measurements
> for the platform that supports TCG2 protocol. So, extend it add
> CC measurement protocol (EFI_CC_MEASUREMENT_PROTOCOL) and event logging
> support. Event logging format in the CC environment is the same as
> TCG2.
>
> More details about the EFI CC measurements and logging can be found
> in [1].
>
> Link: https://uefi.org/specs/UEFI/2.10/38_Confidential_Computing.html#efi-cc-measurement-protocol [1]
> Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
> ---
>  .../firmware/efi/libstub/efi-stub-helper.c    | 113 +++++++++++++-----
>  drivers/firmware/efi/libstub/efistub.h        |  73 +++++++++++
>  include/linux/efi.h                           |   1 +
>  3 files changed, 159 insertions(+), 28 deletions(-)
>
> diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
> index bfa30625f5d0..e323b768048f 100644
> --- a/drivers/firmware/efi/libstub/efi-stub-helper.c
> +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
> @@ -219,50 +219,107 @@ static const struct {
>         },
>  };
>
> +static efi_status_t tcg2_efi_measure(efi_tcg2_protocol_t *tcg2,
> +                                    unsigned long load_addr,
> +                                    unsigned long load_size,
> +                                    enum efistub_event event)
> +{
> +       struct efi_measured_event {
> +               efi_tcg2_event_t        event_data;
> +               efi_tcg2_tagged_event_t tagged_event;
> +               u8                      tagged_event_data[];
> +       } *evt;
> +       int size = sizeof(*evt) + events[event].event_data_len;
> +       efi_status_t status;
> +
> +       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size,
> +                            (void **)&evt);
> +       if (status != EFI_SUCCESS)
> +               return status;
> +
> +       evt->event_data = (struct efi_tcg2_event){
> +               .event_size                     = size,
> +               .event_header.header_size       = sizeof(evt->event_data.event_header),
> +               .event_header.header_version    = EFI_TCG2_EVENT_HEADER_VERSION,
> +               .event_header.pcr_index         = events[event].pcr_index,
> +               .event_header.event_type        = EV_EVENT_TAG,
> +       };
> +
> +       evt->tagged_event = (struct efi_tcg2_tagged_event){
> +               .tagged_event_id                = events[event].event_id,
> +               .tagged_event_data_size         = events[event].event_data_len,
> +       };
> +
> +       memcpy(evt->tagged_event_data, events[event].event_data,
> +              events[event].event_data_len);
> +
> +       status = efi_call_proto(tcg2, hash_log_extend_event, 0,
> +                               load_addr, load_size, &evt->event_data);
> +       efi_bs_call(free_pool, evt);
> +
> +       return status;
> +}
> +
> +static efi_status_t cc_efi_measure(efi_cc_protocol_t *cc,
> +                                  unsigned long load_addr,
> +                                  unsigned long load_size,
> +                                  enum efistub_event event)
> +{
> +       efi_cc_mr_index_t mr;
> +       efi_cc_event_t *evt;
> +       efi_status_t status;
> +       size_t size;
> +
> +       status = efi_call_proto(cc, map_pcr_to_mr_index, events[event].pcr_index, &mr);
> +       if (status != EFI_SUCCESS) {
> +               efi_err("CC_MEASURE: PCR to MR mapping failed\n");
> +               return status;
> +       }
> +
> +       size = sizeof(*evt) + events[event].event_data_len;
> +       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size, (void **)&evt);
> +       if (status != EFI_SUCCESS) {
> +               efi_err("CC_MEASURE: Allocating event struct failed\n");
> +               return status;
> +       }
> +
> +       evt->event_size = size;
> +       evt->event_header.header_size = sizeof(evt->event_header);
> +       evt->event_header.header_version = EFI_CC_EVENT_HEADER_VERSION;
> +       evt->event_header.mr_index = mr;
> +       evt->event_header.event_type = EV_EVENT_TAG;
> +       memcpy(evt->event_data, events[event].event_data, events[event].event_data_len);
> +

Why does this look entirely different from the TCG2 version? What
happened to the tagged event?

> +       status = efi_call_proto(cc, hash_log_extend_event, 0, load_addr, load_size, evt);
> +       efi_bs_call(free_pool, evt);
> +
> +       return status;
> +}
>  static efi_status_t efi_measure_tagged_event(unsigned long load_addr,
>                                              unsigned long load_size,
>                                              enum efistub_event event)
>  {
>         efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID;
> +       efi_guid_t cc_guid = EFI_CC_MEASUREMENT_PROTOCOL_GUID;
> +       efi_cc_protocol_t *cc = NULL;
>         efi_tcg2_protocol_t *tcg2 = NULL;
>         efi_status_t status;
>
>         efi_bs_call(locate_protocol, &tcg2_guid, NULL, (void **)&tcg2);
>         if (tcg2) {
> -               struct efi_measured_event {
> -                       efi_tcg2_event_t        event_data;
> -                       efi_tcg2_tagged_event_t tagged_event;
> -                       u8                      tagged_event_data[];
> -               } *evt;
> -               int size = sizeof(*evt) + events[event].event_data_len;
> -
> -               status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size,
> -                                    (void **)&evt);
> +               status = tcg2_efi_measure(tcg2, load_addr, load_size, event);
>                 if (status != EFI_SUCCESS)
>                         goto fail;
>
> -               evt->event_data = (struct efi_tcg2_event){
> -                       .event_size                     = size,
> -                       .event_header.header_size       = sizeof(evt->event_data.event_header),
> -                       .event_header.header_version    = EFI_TCG2_EVENT_HEADER_VERSION,
> -                       .event_header.pcr_index         = events[event].pcr_index,
> -                       .event_header.event_type        = EV_EVENT_TAG,
> -               };
> -
> -               evt->tagged_event = (struct efi_tcg2_tagged_event){
> -                       .tagged_event_id                = events[event].event_id,
> -                       .tagged_event_data_size         = events[event].event_data_len,
> -               };
> -
> -               memcpy(evt->tagged_event_data, events[event].event_data,
> -                      events[event].event_data_len);
> -
> -               status = efi_call_proto(tcg2, hash_log_extend_event, 0,
> -                                       load_addr, load_size, &evt->event_data);
> -               efi_bs_call(free_pool, evt);
> +               return EFI_SUCCESS;
> +       }
>
> +       efi_bs_call(locate_protocol, &cc_guid, NULL, (void **)&cc);
> +       if (cc) {
> +               status = cc_efi_measure(cc, load_addr, load_size, event);
>                 if (status != EFI_SUCCESS)
>                         goto fail;
> +
>                 return EFI_SUCCESS;
>         }
>
> diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
> index 212687c30d79..dbdeb2ad7a93 100644
> --- a/drivers/firmware/efi/libstub/efistub.h
> +++ b/drivers/firmware/efi/libstub/efistub.h
> @@ -882,6 +882,79 @@ union efi_tcg2_protocol {
>         } mixed_mode;
>  };
>
> +typedef struct {
> +       u8 major;
> +       u8 minor;
> +} efi_cc_version_t;
> +
> +typedef struct {
> +       u8 type;
> +       u8 sub_type;
> +} efi_cc_type_t;
> +
> +/* EFI CC type/subtype defines */
> +#define EFI_CC_TYPE_NONE               0
> +#define EFI_CC_TYPE_AMD_SEV            1
> +#define EFI_CC_TYPE_INTEL_TDX          2
> +
> +typedef u32 efi_cc_mr_index_t;
> +
> +typedef struct {
> +       u32 event_size;
> +       struct {
> +               u32 header_size;
> +               u16 header_version;
> +               u32 mr_index;
> +               u32 event_type;
> +       } __packed event_header;
> +       u8 event_data[0];
> +} __packed efi_cc_event_t;
> +
> +typedef u32 efi_cc_event_log_bitmap_t;
> +typedef u32 efi_cc_event_log_format_t;
> +typedef u32 efi_cc_event_algorithm_bitmap_t;
> +
> +typedef struct {
> +       u8 size;
> +       efi_cc_version_t structure_version;
> +       efi_cc_version_t protocol_version;
> +       efi_cc_event_algorithm_bitmap_t hash_algorithm_bitmap;
> +       efi_cc_event_log_bitmap_t supported_event_logs;
> +       efi_cc_type_t cc_type;
> +} efi_cc_boot_service_cap_t;
> +
> +#define EFI_CC_EVENT_HEADER_VERSION  1
> +
> +#define EFI_CC_BOOT_HASH_ALG_SHA384     0x00000004
> +
> +typedef union efi_cc_protocol efi_cc_protocol_t;
> +
> +union efi_cc_protocol {
> +       struct {
> +               efi_status_t (__efiapi *get_capability)(efi_cc_protocol_t *,
> +                                                       efi_cc_boot_service_cap_t *);
> +               efi_status_t (__efiapi *get_event_log)(efi_cc_protocol_t *,
> +                                                      efi_cc_event_log_format_t,
> +                                                      efi_physical_addr_t *,
> +                                                      efi_physical_addr_t *,
> +                                                      efi_bool_t *);
> +               efi_status_t (__efiapi *hash_log_extend_event)(efi_cc_protocol_t *,
> +                                                              u64,
> +                                                              efi_physical_addr_t,
> +                                                              u64,
> +                                                              const efi_cc_event_t *);
> +               efi_status_t (__efiapi *map_pcr_to_mr_index)(efi_cc_protocol_t *,
> +                                                            u32,
> +                                                            efi_cc_mr_index_t *);
> +       };
> +       struct {
> +               u32 get_capability;
> +               u32 get_event_log;
> +               u32 hash_log_extend_event;
> +               u32 map_pcr_to_mr_index;
> +       } mixed_mode;
> +};
> +
>  struct riscv_efi_boot_protocol {
>         u64 revision;
>
> diff --git a/include/linux/efi.h b/include/linux/efi.h
> index c74f47711f0b..2f57fec2e629 100644
> --- a/include/linux/efi.h
> +++ b/include/linux/efi.h
> @@ -400,6 +400,7 @@ void efi_native_runtime_setup(void);
>  #define EFI_CERT_X509_GUID                     EFI_GUID(0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72)
>  #define EFI_CERT_X509_SHA256_GUID              EFI_GUID(0x3bd2a492, 0x96c0, 0x4079, 0xb4, 0x20, 0xfc, 0xf9, 0x8e, 0xf1, 0x03, 0xed)
>  #define EFI_CC_BLOB_GUID                       EFI_GUID(0x067b1f5f, 0xcf26, 0x44c5, 0x85, 0x54, 0x93, 0xd7, 0x77, 0x91, 0x2d, 0x42)
> +#define EFI_CC_MEASUREMENT_PROTOCOL_GUID       EFI_GUID(0x96751a3d, 0x72f4, 0x41a6, 0xa7, 0x94, 0xed, 0x5d, 0x0e, 0x67, 0xae, 0x6b)
>
>  /*
>   * This GUID is used to pass to the kernel proper the struct screen_info
> --
> 2.25.1
>
Kuppuswamy Sathyanarayanan Feb. 3, 2024, 10:44 p.m. UTC | #2
On 2/3/24 8:59 AM, Ard Biesheuvel wrote:
> (cc Ilias)
>
> On Sat, 3 Feb 2024 at 08:58, Kuppuswamy Sathyanarayanan
> <sathyanarayanan.kuppuswamy@linux.intel.com> wrote:
>> If the virtual firmware implements TPM support, TCG2 protocol will be
>> used for kernel measurements and event logging support. But in CC
>> environment, not all platforms support or enable the TPM feature. UEFI
>> specification [1] exposes protocol and interfaces used for kernel
>> measurements in CC platforms without TPM support.
>>
>> Currently, the efi-stub only supports the kernel related measurements
>> for the platform that supports TCG2 protocol. So, extend it add
>> CC measurement protocol (EFI_CC_MEASUREMENT_PROTOCOL) and event logging
>> support. Event logging format in the CC environment is the same as
>> TCG2.
>>
>> More details about the EFI CC measurements and logging can be found
>> in [1].
>>
>> Link: https://uefi.org/specs/UEFI/2.10/38_Confidential_Computing.html#efi-cc-measurement-protocol [1]
>> Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>> ---
>>  .../firmware/efi/libstub/efi-stub-helper.c    | 113 +++++++++++++-----
>>  drivers/firmware/efi/libstub/efistub.h        |  73 +++++++++++
>>  include/linux/efi.h                           |   1 +
>>  3 files changed, 159 insertions(+), 28 deletions(-)
>>
>> diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
>> index bfa30625f5d0..e323b768048f 100644
>> --- a/drivers/firmware/efi/libstub/efi-stub-helper.c
>> +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
>> @@ -219,50 +219,107 @@ static const struct {
>>         },
>>  };
>>
>> +static efi_status_t tcg2_efi_measure(efi_tcg2_protocol_t *tcg2,
>> +                                    unsigned long load_addr,
>> +                                    unsigned long load_size,
>> +                                    enum efistub_event event)
>> +{
>> +       struct efi_measured_event {
>> +               efi_tcg2_event_t        event_data;
>> +               efi_tcg2_tagged_event_t tagged_event;
>> +               u8                      tagged_event_data[];
>> +       } *evt;
>> +       int size = sizeof(*evt) + events[event].event_data_len;
>> +       efi_status_t status;
>> +
>> +       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size,
>> +                            (void **)&evt);
>> +       if (status != EFI_SUCCESS)
>> +               return status;
>> +
>> +       evt->event_data = (struct efi_tcg2_event){
>> +               .event_size                     = size,
>> +               .event_header.header_size       = sizeof(evt->event_data.event_header),
>> +               .event_header.header_version    = EFI_TCG2_EVENT_HEADER_VERSION,
>> +               .event_header.pcr_index         = events[event].pcr_index,
>> +               .event_header.event_type        = EV_EVENT_TAG,
>> +       };
>> +
>> +       evt->tagged_event = (struct efi_tcg2_tagged_event){
>> +               .tagged_event_id                = events[event].event_id,
>> +               .tagged_event_data_size         = events[event].event_data_len,
>> +       };
>> +
>> +       memcpy(evt->tagged_event_data, events[event].event_data,
>> +              events[event].event_data_len);
>> +
>> +       status = efi_call_proto(tcg2, hash_log_extend_event, 0,
>> +                               load_addr, load_size, &evt->event_data);
>> +       efi_bs_call(free_pool, evt);
>> +
>> +       return status;
>> +}
>> +
>> +static efi_status_t cc_efi_measure(efi_cc_protocol_t *cc,
>> +                                  unsigned long load_addr,
>> +                                  unsigned long load_size,
>> +                                  enum efistub_event event)
>> +{
>> +       efi_cc_mr_index_t mr;
>> +       efi_cc_event_t *evt;
>> +       efi_status_t status;
>> +       size_t size;
>> +
>> +       status = efi_call_proto(cc, map_pcr_to_mr_index, events[event].pcr_index, &mr);
>> +       if (status != EFI_SUCCESS) {
>> +               efi_err("CC_MEASURE: PCR to MR mapping failed\n");
>> +               return status;
>> +       }
>> +
>> +       size = sizeof(*evt) + events[event].event_data_len;
>> +       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size, (void **)&evt);
>> +       if (status != EFI_SUCCESS) {
>> +               efi_err("CC_MEASURE: Allocating event struct failed\n");
>> +               return status;
>> +       }
>> +
>> +       evt->event_size = size;
>> +       evt->event_header.header_size = sizeof(evt->event_header);
>> +       evt->event_header.header_version = EFI_CC_EVENT_HEADER_VERSION;
>> +       evt->event_header.mr_index = mr;
>> +       evt->event_header.event_type = EV_EVENT_TAG;
>> +       memcpy(evt->event_data, events[event].event_data, events[event].event_data_len);
>> +
> Why does this look entirely different from the TCG2 version? What
> happened to the tagged event?

Sorry, I misunderstood the event data related comment in the EFI_CC_EVENT
definition in UEFI spec. I thought we have copy the event data directly. But
after checking the EV_EVENT_TAG format in the TCG specification, I know
that my understanding is incorrect. I will add tagged event info and send
v2 version.

Copied from UEFI 2.10, section "38.2.4. EFI_CC_MEASUREMENT_PROTOCOL.HashLogExtendEvent"

typedef struct {
  //
  // Total size of the event including the Size component,
  // the header and the Event data.
  //
  UINT32                Size;
  EFI_CC_EVENT_HEADER   Header;
  UINT8                 Event[1];
} EFI_CC_EVENT;

>> +       status = efi_call_proto(cc, hash_log_extend_event, 0, load_addr, load_size, evt);
>> +       efi_bs_call(free_pool, evt);
>> +
>> +       return status;
>> +}
>>  static efi_status_t efi_measure_tagged_event(unsigned long load_addr,
>>                                              unsigned long load_size,
>>                                              enum efistub_event event)
>>  {
>>         efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID;
>> +       efi_guid_t cc_guid = EFI_CC_MEASUREMENT_PROTOCOL_GUID;
>> +       efi_cc_protocol_t *cc = NULL;
>>         efi_tcg2_protocol_t *tcg2 = NULL;
>>         efi_status_t status;
>>
>>         efi_bs_call(locate_protocol, &tcg2_guid, NULL, (void **)&tcg2);
>>         if (tcg2) {
>> -               struct efi_measured_event {
>> -                       efi_tcg2_event_t        event_data;
>> -                       efi_tcg2_tagged_event_t tagged_event;
>> -                       u8                      tagged_event_data[];
>> -               } *evt;
>> -               int size = sizeof(*evt) + events[event].event_data_len;
>> -
>> -               status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size,
>> -                                    (void **)&evt);
>> +               status = tcg2_efi_measure(tcg2, load_addr, load_size, event);
>>                 if (status != EFI_SUCCESS)
>>                         goto fail;
>>
>> -               evt->event_data = (struct efi_tcg2_event){
>> -                       .event_size                     = size,
>> -                       .event_header.header_size       = sizeof(evt->event_data.event_header),
>> -                       .event_header.header_version    = EFI_TCG2_EVENT_HEADER_VERSION,
>> -                       .event_header.pcr_index         = events[event].pcr_index,
>> -                       .event_header.event_type        = EV_EVENT_TAG,
>> -               };
>> -
>> -               evt->tagged_event = (struct efi_tcg2_tagged_event){
>> -                       .tagged_event_id                = events[event].event_id,
>> -                       .tagged_event_data_size         = events[event].event_data_len,
>> -               };
>> -
>> -               memcpy(evt->tagged_event_data, events[event].event_data,
>> -                      events[event].event_data_len);
>> -
>> -               status = efi_call_proto(tcg2, hash_log_extend_event, 0,
>> -                                       load_addr, load_size, &evt->event_data);
>> -               efi_bs_call(free_pool, evt);
>> +               return EFI_SUCCESS;
>> +       }
>>
>> +       efi_bs_call(locate_protocol, &cc_guid, NULL, (void **)&cc);
>> +       if (cc) {
>> +               status = cc_efi_measure(cc, load_addr, load_size, event);
>>                 if (status != EFI_SUCCESS)
>>                         goto fail;
>> +
>>                 return EFI_SUCCESS;
>>         }
>>
>> diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
>> index 212687c30d79..dbdeb2ad7a93 100644
>> --- a/drivers/firmware/efi/libstub/efistub.h
>> +++ b/drivers/firmware/efi/libstub/efistub.h
>> @@ -882,6 +882,79 @@ union efi_tcg2_protocol {
>>         } mixed_mode;
>>  };
>>
>> +typedef struct {
>> +       u8 major;
>> +       u8 minor;
>> +} efi_cc_version_t;
>> +
>> +typedef struct {
>> +       u8 type;
>> +       u8 sub_type;
>> +} efi_cc_type_t;
>> +
>> +/* EFI CC type/subtype defines */
>> +#define EFI_CC_TYPE_NONE               0
>> +#define EFI_CC_TYPE_AMD_SEV            1
>> +#define EFI_CC_TYPE_INTEL_TDX          2
>> +
>> +typedef u32 efi_cc_mr_index_t;
>> +
>> +typedef struct {
>> +       u32 event_size;
>> +       struct {
>> +               u32 header_size;
>> +               u16 header_version;
>> +               u32 mr_index;
>> +               u32 event_type;
>> +       } __packed event_header;
>> +       u8 event_data[0];
>> +} __packed efi_cc_event_t;
>> +
>> +typedef u32 efi_cc_event_log_bitmap_t;
>> +typedef u32 efi_cc_event_log_format_t;
>> +typedef u32 efi_cc_event_algorithm_bitmap_t;
>> +
>> +typedef struct {
>> +       u8 size;
>> +       efi_cc_version_t structure_version;
>> +       efi_cc_version_t protocol_version;
>> +       efi_cc_event_algorithm_bitmap_t hash_algorithm_bitmap;
>> +       efi_cc_event_log_bitmap_t supported_event_logs;
>> +       efi_cc_type_t cc_type;
>> +} efi_cc_boot_service_cap_t;
>> +
>> +#define EFI_CC_EVENT_HEADER_VERSION  1
>> +
>> +#define EFI_CC_BOOT_HASH_ALG_SHA384     0x00000004
>> +
>> +typedef union efi_cc_protocol efi_cc_protocol_t;
>> +
>> +union efi_cc_protocol {
>> +       struct {
>> +               efi_status_t (__efiapi *get_capability)(efi_cc_protocol_t *,
>> +                                                       efi_cc_boot_service_cap_t *);
>> +               efi_status_t (__efiapi *get_event_log)(efi_cc_protocol_t *,
>> +                                                      efi_cc_event_log_format_t,
>> +                                                      efi_physical_addr_t *,
>> +                                                      efi_physical_addr_t *,
>> +                                                      efi_bool_t *);
>> +               efi_status_t (__efiapi *hash_log_extend_event)(efi_cc_protocol_t *,
>> +                                                              u64,
>> +                                                              efi_physical_addr_t,
>> +                                                              u64,
>> +                                                              const efi_cc_event_t *);
>> +               efi_status_t (__efiapi *map_pcr_to_mr_index)(efi_cc_protocol_t *,
>> +                                                            u32,
>> +                                                            efi_cc_mr_index_t *);
>> +       };
>> +       struct {
>> +               u32 get_capability;
>> +               u32 get_event_log;
>> +               u32 hash_log_extend_event;
>> +               u32 map_pcr_to_mr_index;
>> +       } mixed_mode;
>> +};
>> +
>>  struct riscv_efi_boot_protocol {
>>         u64 revision;
>>
>> diff --git a/include/linux/efi.h b/include/linux/efi.h
>> index c74f47711f0b..2f57fec2e629 100644
>> --- a/include/linux/efi.h
>> +++ b/include/linux/efi.h
>> @@ -400,6 +400,7 @@ void efi_native_runtime_setup(void);
>>  #define EFI_CERT_X509_GUID                     EFI_GUID(0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72)
>>  #define EFI_CERT_X509_SHA256_GUID              EFI_GUID(0x3bd2a492, 0x96c0, 0x4079, 0xb4, 0x20, 0xfc, 0xf9, 0x8e, 0xf1, 0x03, 0xed)
>>  #define EFI_CC_BLOB_GUID                       EFI_GUID(0x067b1f5f, 0xcf26, 0x44c5, 0x85, 0x54, 0x93, 0xd7, 0x77, 0x91, 0x2d, 0x42)
>> +#define EFI_CC_MEASUREMENT_PROTOCOL_GUID       EFI_GUID(0x96751a3d, 0x72f4, 0x41a6, 0xa7, 0x94, 0xed, 0x5d, 0x0e, 0x67, 0xae, 0x6b)
>>
>>  /*
>>   * This GUID is used to pass to the kernel proper the struct screen_info
>> --
>> 2.25.1
>>
Ard Biesheuvel Feb. 4, 2024, 10:03 p.m. UTC | #3
On Sun, 4 Feb 2024 at 21:28, Kuppuswamy Sathyanarayanan
<sathyanarayanan.kuppuswamy@linux.intel.com> wrote:
>
> +Jiewen & Ken (RTMR firmware owner)
>
> On 2/3/24 10:46 PM, James Bottomley wrote:
> > On Sat, 2024-02-03 at 07:57 +0000, Kuppuswamy Sathyanarayanan wrote:
> >> If the virtual firmware implements TPM support, TCG2 protocol will be
> >> used for kernel measurements and event logging support. But in CC
> >> environment, not all platforms support or enable the TPM feature.
> >> UEFI specification [1] exposes protocol and interfaces used for
> >> kernel measurements in CC platforms without TPM support.
> >>
> >> Currently, the efi-stub only supports the kernel related measurements
> >> for the platform that supports TCG2 protocol. So, extend it add
> >> CC measurement protocol (EFI_CC_MEASUREMENT_PROTOCOL) and event
> >> logging support. Event logging format in the CC environment is the
> >> same as TCG2.
> > Why do we have to do this anymore?  Given that you're already pushing
> > patches that map RTMRs to TPM PCRs:
> >
> > https://lore.kernel.org/lkml/20240128212532.2754325-4-sameo@rivosinc.com/
>
> IMHO, I am not sure whether we need this mapping support . I have already
> mentioned the same comment in [1]. If we support extension and logging
> via configFS ABI, why again support PCR mapping?
>
> https://lore.kernel.org/lkml/2bd7c80b-9cd8-4450-a410-c3739d224167@linux.intel.com/ [1]
>
> >
> > Can't you just add a stub TCG2 driver to EFI that exposes only the
> > ability to log and measure using this mapping?  That way all our
> > existing code will "just work" without the need to understand anything
> > about confidential computing or add new code to do the measurement?
>
> I am not familiar with the EFI implementation, but I think a new protocol
> is added to handle future CC extensions (which could deviate from
> TCG2) and to support platforms that does not support or enable TPM
> feature. So modifying the TCG2 driver in EFI may not work for the
> above-mentioned cases. I think the EFI driver part of this support
> is already merged.
>
> Jiewen/Ken may have more comments about this proposal.
>

I don't think it is sufficient to wire up the CC protocol here. There
is more code in drivers/firmware/efi/libstub/tpm.c that deals with the
event log.

Given that the EFI CC protocol was specifically designed to act as a
substitute for the TCG2 protocol, I would expect all occurrences of
TCG2 protocol invocations to be handled accordingly.

So I think the approach here should be to provide a local wrapper
around get_event_log() and hash_log_extend_event() that is backed by
either the TCG2 protocol of the EFI cc protocol, and all current
callers invoke this wrapper rather than the TCG2 protocol directly.
Kuppuswamy Sathyanarayanan Feb. 5, 2024, 8:13 p.m. UTC | #4
On 2/4/24 2:03 PM, Ard Biesheuvel wrote:
> On Sun, 4 Feb 2024 at 21:28, Kuppuswamy Sathyanarayanan
> <sathyanarayanan.kuppuswamy@linux.intel.com> wrote:
>> +Jiewen & Ken (RTMR firmware owner)
>>
>> On 2/3/24 10:46 PM, James Bottomley wrote:
>>> On Sat, 2024-02-03 at 07:57 +0000, Kuppuswamy Sathyanarayanan wrote:
>>>> If the virtual firmware implements TPM support, TCG2 protocol will be
>>>> used for kernel measurements and event logging support. But in CC
>>>> environment, not all platforms support or enable the TPM feature.
>>>> UEFI specification [1] exposes protocol and interfaces used for
>>>> kernel measurements in CC platforms without TPM support.
>>>>
>>>> Currently, the efi-stub only supports the kernel related measurements
>>>> for the platform that supports TCG2 protocol. So, extend it add
>>>> CC measurement protocol (EFI_CC_MEASUREMENT_PROTOCOL) and event
>>>> logging support. Event logging format in the CC environment is the
>>>> same as TCG2.
>>> Why do we have to do this anymore?  Given that you're already pushing
>>> patches that map RTMRs to TPM PCRs:
>>>
>>> https://lore.kernel.org/lkml/20240128212532.2754325-4-sameo@rivosinc.com/
>> IMHO, I am not sure whether we need this mapping support . I have already
>> mentioned the same comment in [1]. If we support extension and logging
>> via configFS ABI, why again support PCR mapping?
>>
>> https://lore.kernel.org/lkml/2bd7c80b-9cd8-4450-a410-c3739d224167@linux.intel.com/ [1]
>>
>>> Can't you just add a stub TCG2 driver to EFI that exposes only the
>>> ability to log and measure using this mapping?  That way all our
>>> existing code will "just work" without the need to understand anything
>>> about confidential computing or add new code to do the measurement?
>> I am not familiar with the EFI implementation, but I think a new protocol
>> is added to handle future CC extensions (which could deviate from
>> TCG2) and to support platforms that does not support or enable TPM
>> feature. So modifying the TCG2 driver in EFI may not work for the
>> above-mentioned cases. I think the EFI driver part of this support
>> is already merged.
>>
>> Jiewen/Ken may have more comments about this proposal.
>>
> I don't think it is sufficient to wire up the CC protocol here. There
> is more code in drivers/firmware/efi/libstub/tpm.c that deals with the
> event log.
>
> Given that the EFI CC protocol was specifically designed to act as a
> substitute for the TCG2 protocol, I would expect all occurrences of
> TCG2 protocol invocations to be handled accordingly.
>
> So I think the approach here should be to provide a local wrapper
> around get_event_log() and hash_log_extend_event() that is backed by
> either the TCG2 protocol of the EFI cc protocol, and all current
> callers invoke this wrapper rather than the TCG2 protocol directly.
Ah, I missed that part. Thanks for pointing out. I will fix this in
next version.
diff mbox series

Patch

diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index bfa30625f5d0..e323b768048f 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -219,50 +219,107 @@  static const struct {
 	},
 };
 
+static efi_status_t tcg2_efi_measure(efi_tcg2_protocol_t *tcg2,
+				     unsigned long load_addr,
+				     unsigned long load_size,
+				     enum efistub_event event)
+{
+	struct efi_measured_event {
+		efi_tcg2_event_t	event_data;
+		efi_tcg2_tagged_event_t tagged_event;
+		u8			tagged_event_data[];
+	} *evt;
+	int size = sizeof(*evt) + events[event].event_data_len;
+	efi_status_t status;
+
+	status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size,
+			     (void **)&evt);
+	if (status != EFI_SUCCESS)
+		return status;
+
+	evt->event_data = (struct efi_tcg2_event){
+		.event_size			= size,
+		.event_header.header_size	= sizeof(evt->event_data.event_header),
+		.event_header.header_version	= EFI_TCG2_EVENT_HEADER_VERSION,
+		.event_header.pcr_index		= events[event].pcr_index,
+		.event_header.event_type	= EV_EVENT_TAG,
+	};
+
+	evt->tagged_event = (struct efi_tcg2_tagged_event){
+		.tagged_event_id		= events[event].event_id,
+		.tagged_event_data_size		= events[event].event_data_len,
+	};
+
+	memcpy(evt->tagged_event_data, events[event].event_data,
+	       events[event].event_data_len);
+
+	status = efi_call_proto(tcg2, hash_log_extend_event, 0,
+				load_addr, load_size, &evt->event_data);
+	efi_bs_call(free_pool, evt);
+
+	return status;
+}
+
+static efi_status_t cc_efi_measure(efi_cc_protocol_t *cc,
+				   unsigned long load_addr,
+				   unsigned long load_size,
+				   enum efistub_event event)
+{
+	efi_cc_mr_index_t mr;
+	efi_cc_event_t *evt;
+	efi_status_t status;
+	size_t size;
+
+	status = efi_call_proto(cc, map_pcr_to_mr_index, events[event].pcr_index, &mr);
+	if (status != EFI_SUCCESS) {
+		efi_err("CC_MEASURE: PCR to MR mapping failed\n");
+		return status;
+	}
+
+	size = sizeof(*evt) + events[event].event_data_len;
+	status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size, (void **)&evt);
+	if (status != EFI_SUCCESS) {
+		efi_err("CC_MEASURE: Allocating event struct failed\n");
+		return status;
+	}
+
+	evt->event_size = size;
+	evt->event_header.header_size = sizeof(evt->event_header);
+	evt->event_header.header_version = EFI_CC_EVENT_HEADER_VERSION;
+	evt->event_header.mr_index = mr;
+	evt->event_header.event_type = EV_EVENT_TAG;
+	memcpy(evt->event_data, events[event].event_data, events[event].event_data_len);
+
+	status = efi_call_proto(cc, hash_log_extend_event, 0, load_addr, load_size, evt);
+	efi_bs_call(free_pool, evt);
+
+	return status;
+}
 static efi_status_t efi_measure_tagged_event(unsigned long load_addr,
 					     unsigned long load_size,
 					     enum efistub_event event)
 {
 	efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID;
+	efi_guid_t cc_guid = EFI_CC_MEASUREMENT_PROTOCOL_GUID;
+	efi_cc_protocol_t *cc = NULL;
 	efi_tcg2_protocol_t *tcg2 = NULL;
 	efi_status_t status;
 
 	efi_bs_call(locate_protocol, &tcg2_guid, NULL, (void **)&tcg2);
 	if (tcg2) {
-		struct efi_measured_event {
-			efi_tcg2_event_t	event_data;
-			efi_tcg2_tagged_event_t tagged_event;
-			u8			tagged_event_data[];
-		} *evt;
-		int size = sizeof(*evt) + events[event].event_data_len;
-
-		status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size,
-				     (void **)&evt);
+		status = tcg2_efi_measure(tcg2, load_addr, load_size, event);
 		if (status != EFI_SUCCESS)
 			goto fail;
 
-		evt->event_data = (struct efi_tcg2_event){
-			.event_size			= size,
-			.event_header.header_size	= sizeof(evt->event_data.event_header),
-			.event_header.header_version	= EFI_TCG2_EVENT_HEADER_VERSION,
-			.event_header.pcr_index		= events[event].pcr_index,
-			.event_header.event_type	= EV_EVENT_TAG,
-		};
-
-		evt->tagged_event = (struct efi_tcg2_tagged_event){
-			.tagged_event_id		= events[event].event_id,
-			.tagged_event_data_size		= events[event].event_data_len,
-		};
-
-		memcpy(evt->tagged_event_data, events[event].event_data,
-		       events[event].event_data_len);
-
-		status = efi_call_proto(tcg2, hash_log_extend_event, 0,
-					load_addr, load_size, &evt->event_data);
-		efi_bs_call(free_pool, evt);
+		return EFI_SUCCESS;
+	}
 
+	efi_bs_call(locate_protocol, &cc_guid, NULL, (void **)&cc);
+	if (cc) {
+		status = cc_efi_measure(cc, load_addr, load_size, event);
 		if (status != EFI_SUCCESS)
 			goto fail;
+
 		return EFI_SUCCESS;
 	}
 
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index 212687c30d79..dbdeb2ad7a93 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -882,6 +882,79 @@  union efi_tcg2_protocol {
 	} mixed_mode;
 };
 
+typedef struct {
+	u8 major;
+	u8 minor;
+} efi_cc_version_t;
+
+typedef struct {
+	u8 type;
+	u8 sub_type;
+} efi_cc_type_t;
+
+/* EFI CC type/subtype defines */
+#define EFI_CC_TYPE_NONE		0
+#define EFI_CC_TYPE_AMD_SEV		1
+#define EFI_CC_TYPE_INTEL_TDX		2
+
+typedef u32 efi_cc_mr_index_t;
+
+typedef struct {
+	u32 event_size;
+	struct {
+		u32 header_size;
+		u16 header_version;
+		u32 mr_index;
+		u32 event_type;
+	} __packed event_header;
+	u8 event_data[0];
+} __packed efi_cc_event_t;
+
+typedef u32 efi_cc_event_log_bitmap_t;
+typedef u32 efi_cc_event_log_format_t;
+typedef u32 efi_cc_event_algorithm_bitmap_t;
+
+typedef struct {
+	u8 size;
+	efi_cc_version_t structure_version;
+	efi_cc_version_t protocol_version;
+	efi_cc_event_algorithm_bitmap_t hash_algorithm_bitmap;
+	efi_cc_event_log_bitmap_t supported_event_logs;
+	efi_cc_type_t cc_type;
+} efi_cc_boot_service_cap_t;
+
+#define EFI_CC_EVENT_HEADER_VERSION  1
+
+#define EFI_CC_BOOT_HASH_ALG_SHA384     0x00000004
+
+typedef union efi_cc_protocol efi_cc_protocol_t;
+
+union efi_cc_protocol {
+	struct {
+		efi_status_t (__efiapi *get_capability)(efi_cc_protocol_t *,
+							efi_cc_boot_service_cap_t *);
+		efi_status_t (__efiapi *get_event_log)(efi_cc_protocol_t *,
+						       efi_cc_event_log_format_t,
+						       efi_physical_addr_t *,
+						       efi_physical_addr_t *,
+						       efi_bool_t *);
+		efi_status_t (__efiapi *hash_log_extend_event)(efi_cc_protocol_t *,
+							       u64,
+							       efi_physical_addr_t,
+							       u64,
+							       const efi_cc_event_t *);
+		efi_status_t (__efiapi *map_pcr_to_mr_index)(efi_cc_protocol_t *,
+							     u32,
+							     efi_cc_mr_index_t *);
+	};
+	struct {
+		u32 get_capability;
+		u32 get_event_log;
+		u32 hash_log_extend_event;
+		u32 map_pcr_to_mr_index;
+	} mixed_mode;
+};
+
 struct riscv_efi_boot_protocol {
 	u64 revision;
 
diff --git a/include/linux/efi.h b/include/linux/efi.h
index c74f47711f0b..2f57fec2e629 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -400,6 +400,7 @@  void efi_native_runtime_setup(void);
 #define EFI_CERT_X509_GUID			EFI_GUID(0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72)
 #define EFI_CERT_X509_SHA256_GUID		EFI_GUID(0x3bd2a492, 0x96c0, 0x4079, 0xb4, 0x20, 0xfc, 0xf9, 0x8e, 0xf1, 0x03, 0xed)
 #define EFI_CC_BLOB_GUID			EFI_GUID(0x067b1f5f, 0xcf26, 0x44c5, 0x85, 0x54, 0x93, 0xd7, 0x77, 0x91, 0x2d, 0x42)
+#define EFI_CC_MEASUREMENT_PROTOCOL_GUID	EFI_GUID(0x96751a3d, 0x72f4, 0x41a6, 0xa7, 0x94, 0xed, 0x5d, 0x0e, 0x67, 0xae, 0x6b)
 
 /*
  * This GUID is used to pass to the kernel proper the struct screen_info