Currently, efi_get_variable_mem() returns the raw stored format for
authenticated variables, which includes the EFI_VARIABLE_AUTHENTICATION_2
descriptor . This causes image authentication failures when reading
secure boot variables as callers receive wrong data containing
authentication headers instead of the actual variable payload.

The UEFI Specification Section 8.2.6(EFI_VARIABLE_AUTHENTICATION_2 descriptor)
explicitly states:
"The authentication descriptor is not part of the variable data and is
not returned by subsequent calls to GetVariable()."

This patch implements spec-compliant behavior by detecting variables with
the EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute and
stripping the authentication descriptor before returning data to callers.

Signed-off-by: Aswin Murugan <[email protected]>
---
Changes in v2:
- Enhanced commit message with explicit UEFI spec reference
Link to v1: 
https://lore.kernel.org/u-boot/[email protected]/
---
 lib/efi_loader/efi_var_mem.c | 44 +++++++++++++++++++++++++++++-------
 1 file changed, 36 insertions(+), 8 deletions(-)

diff --git a/lib/efi_loader/efi_var_mem.c b/lib/efi_loader/efi_var_mem.c
index 8d5f99f4870..edf4522e51f 100644
--- a/lib/efi_loader/efi_var_mem.c
+++ b/lib/efi_loader/efi_var_mem.c
@@ -336,9 +336,10 @@ efi_get_variable_mem(const u16 *variable_name, const 
efi_guid_t *vendor,
                     u32 *attributes, efi_uintn_t *data_size, void *data,
                     u64 *timep, u32 mask)
 {
-       efi_uintn_t old_size;
+       efi_uintn_t old_size, var_data_size;
        struct efi_var_entry *var;
        u16 *pdata;
+       void *var_data;
 
        if (!variable_name || !vendor || !data_size)
                return EFI_INVALID_PARAMETER;
@@ -362,19 +363,46 @@ efi_get_variable_mem(const u16 *variable_name, const 
efi_guid_t *vendor,
        if (!u16_strcmp(variable_name, vtf))
                return efi_var_collect_mem(data, data_size, 
EFI_VARIABLE_NON_VOLATILE);
 
+       for (pdata = var->name; *pdata; ++pdata)
+               ;
+       ++pdata;
+
+       var_data = (void *)pdata;
+       var_data_size = var->length;
+
+       /* Handle EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS */
+       if (var->attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
+               if (var_data_size > sizeof(struct efi_time)) {
+                       struct efi_time *timestamp;
+                       struct win_certificate_uefi_guid *cert;
+                       efi_uintn_t auth_size;
+
+                       timestamp = (struct efi_time *)var_data;
+                       cert = (struct win_certificate_uefi_guid *)(timestamp + 
1);
+                       auth_size = sizeof(struct efi_time) + 
cert->hdr.dwLength;
+                       if (var_data_size > auth_size) {
+                               var_data = (u8 *)var_data + auth_size;
+                               var_data_size -= auth_size;
+                       }
+               }
+       }
+       /*
+        * EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS type is old & not
+        * expected for auth variables
+        */
+       else if (var->attr & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
+               return EFI_INVALID_PARAMETER;
+
        old_size = *data_size;
-       *data_size = var->length;
-       if (old_size < var->length)
+       *data_size = var_data_size;
+
+       if (old_size < var_data_size)
                return EFI_BUFFER_TOO_SMALL;
 
        if (!data)
                return EFI_INVALID_PARAMETER;
 
-       for (pdata = var->name; *pdata; ++pdata)
-               ;
-       ++pdata;
-
-       efi_memcpy_runtime(data, pdata, var->length);
+       efi_memcpy_runtime(data, var_data, var_data_size);
 
        return EFI_SUCCESS;
 }
-- 
2.34.1

Reply via email to