[PATCH] efi_loader: explicitly return EFI_UNSUPPORTED for TCG 1.0 compatibility

Stuart Yoder stuart.yoder at arm.com
Wed May 31 21:37:28 CEST 2023


Unfortunately, the TCG spec is very confusing in section 6.4.4 #2 and
#3.  They attempted to clarify in an errata:
https://trustedcomputinggroup.org/wp-content/uploads/EFI-Protocol-Specification-Errata-v.5.pdf

...but it is still confusing.

Ilias and I had discussed the ambiguities, and back in March 2022 I
requested clarification from the TCG workgroup.  In cases of
ambiguity TCG frequently will defer to how EDK2 has implemented
a point in the spec.

Here are my notes following the call with TCG about the intent
of #2 and #3, which was based on their review of the EDK2
implementation:

a. If a client passes in a Size that is the full size including all
    fields including ActivePcrBanks, the return code is SUCCESS and
    all fields are populated. [This is a 1.1 client scenario]

b. If a client passes in a Size that includes all fields up to
    and including the vendor ID, the return code is SUCCESS and all
    fields up to including the vendor ID are populated. [This is a
    1.0 client scenario, so a populated 1.0 struct is returned]

c. If a client passes in a Size that is less than the size up to
    and including the vendor ID, the return code is BUFFER_TOO_SMALL
    and the Size field is populated with the full size of the struct
    supported by the firmware. [This allows a client to determine
    whether it is talking to 1.0 or 1.1 firmware]

What Ilias wants to avoid is supporting #b above in u-boot, and
I agree that having u-boot support clients based on struct 1.0
seems unnecessary.

>> I took a look at the u-boot code.  What I think we want is this:
>>
>> diff --git a/include/efi_tcg2.h b/include/efi_tcg2.h
>> index b1c3abd097..6a46d9e51c 100644
>> --- a/include/efi_tcg2.h
>> +++ b/include/efi_tcg2.h
>> @@ -126,7 +126,7 @@ struct efi_tcg2_boot_service_capability {
>>   };
>>
>>   /* up to and including the vendor ID (manufacturer_id) field */
>> -#define BOOT_SERVICE_CAPABILITY_MIN \
>> +#define BOOT_SERVICE_CAPABILITY_1_0 \
>>          offsetof(struct efi_tcg2_boot_service_capability,
>> number_of_pcr_banks)
>>
>>   #define TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03 "Spec ID Event03"
>> diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c
>> index a83ae7a46c..d37b896b7e 100644
>> --- a/lib/efi_loader/efi_tcg2.c
>> +++ b/lib/efi_loader/efi_tcg2.c
>> @@ -742,15 +742,15 @@ efi_tcg2_get_capability(struct efi_tcg2_protocol
>> *this,
>>                  goto out;
>>          }
>>
>> -       if (capability->size < BOOT_SERVICE_CAPABILITY_MIN) {
>> -               capability->size = BOOT_SERVICE_CAPABILITY_MIN;
>> +       if (capability->size < BOOT_SERVICE_CAPABILITY_1_0) {
>> +               capability->size = sizeof(*capability);
>>                  efi_ret = EFI_BUFFER_TOO_SMALL;
>>                  goto out;
>>          }
>>
>>          if (capability->size < sizeof(*capability)) {
>>                  capability->size = sizeof(*capability);
>> -               efi_ret = EFI_BUFFER_TOO_SMALL;
>> +               efi_ret = EFI_UNSUPPORTED;
>>                  goto out;
>>          }
>>
>> That is:
>>
>> -if the passed in size is less than the 1.0 struct size
>>   then return sizeof() the full struct.  This allows
>>   client to query and determine the supported struct
>>   size
>>
>> -to detect and reject 1.0 clients, if the passed in
>>   size is >= 1.0 struct size AND less than sizeof(*capability)
>>   then return EFI_UNSUPPORTED
>>
>> Does that make sense?
> 
> No, this will not work. A 1.0 client may call with size = 0 and next
> will call with whatever size was returned accompanied by
> EFI_BUFFER_TOO_SMALL.

The spec defines the Size field as "Allocated size of the
structure.", so I don't see how a value of 0 makes sense.

If a client wants to just get the Size field populated, pass in
a buffer of Size=1 and firmware will return just the Size field
populated with the correct struct size.

> It is the client's obligation to check the values of fields
> StructureVersion and ProtocolVersion.

Yes, but what if the client fails to do that? What if a client
passes in a struct with a size corresponding to a 1.0 struct?
What should firmware do?

According to point #b above, firmware should support the 1.0
client and populate only the 1.0 fields.  But, what we are
proposing is not supporting that in u-boot.  Instead return
EFI_UNSUPPORTED.  I can discuss this with the TCG WG.

Thanks,
Stuart


More information about the U-Boot mailing list