]> git.proxmox.com Git - efi-boot-shim.git/commitdiff
Add a function to parse the SBAT metadata from the .sbat section
authorJavier Martinez Canillas <javierm@redhat.com>
Wed, 10 Feb 2021 00:26:46 +0000 (01:26 +0100)
committerPeter Jones <pjones@redhat.com>
Sat, 13 Feb 2021 16:02:59 +0000 (11:02 -0500)
Parse the SBAT [0] Version-Based Revocation Metadata that's contained in a
.sbat data section of the loaded PE binary. This information is used along
with data in a SBAT variable to determine if a EFI binary has been revoked.

[0]: https://github.com/rhboot/shim/blob/sbat/SBAT.md

Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
include/sbat.h
pe.c
sbat.c

index acda5ef68b1715a4d95f1c2826559de9809c6e1f..ab2325bd0f04c1f0a0a509949e1d97cfd45e13db 100644 (file)
@@ -6,5 +6,24 @@
 #ifndef SBAT_H_
 #define SBAT_H_
 
+#include "shim.h"
+
+struct sbat_entry {
+       const CHAR8 *component_name;
+       const CHAR8 *component_generation;
+       const CHAR8 *vendor_name;
+       const CHAR8 *vendor_package_name;
+       const CHAR8 *vendor_version;
+       const CHAR8 *vendor_url;
+};
+
+struct sbat {
+       unsigned int size;
+       struct sbat_entry **entries;
+};
+
+EFI_STATUS parse_sbat(char *sbat_base, size_t sbat_size, char *buffer,
+                     struct sbat *sbat);
+
 #endif /* !SBAT_H_ */
 // vim:fenc=utf-8:tw=75:noet
diff --git a/pe.c b/pe.c
index 9987252d4a2547198cf30fd1b8a3826bf94371eb..f3e9349067c481f47e1a0c411a7f1bf6e9f5b558 100644 (file)
--- a/pe.c
+++ b/pe.c
@@ -1039,9 +1039,41 @@ handle_image (void *data, unsigned int datasize,
        }
 
        if (secure_mode ()) {
+               int res;
+               unsigned int i;
+               struct sbat sbat = { 0 };
+               struct sbat_entry *entry = NULL;
+
+               if (SBATBase && SBATSize) {
+                       res = parse_sbat(SBATBase, SBATSize, buffer, &sbat);
+                       if (res < 0) {
+                               console_print(L"SBAT data not correct: %r\n", res);
+                               return EFI_UNSUPPORTED;
+                       }
+
+                       dprint(L"SBAT data\n");
+                       for (i = 0; i < sbat.size; i++) {
+                               entry = sbat.entries[i];
+                               dprint(L"%a, %a, %a, %a, %a, %a\n",
+                                      entry->component_name,
+                                      entry->component_generation,
+                                      entry->vendor_name,
+                                      entry->vendor_package_name,
+                                      entry->vendor_version,
+                                      entry->vendor_url);
+                       }
+               } else {
+                       perror(L"SBAT data not found\n");
+                       return EFI_UNSUPPORTED;
+               }
+
                efi_status = verify_buffer(data, datasize,
                                           &context, sha256hash, sha1hash);
 
+               if (sbat.entries)
+                       for (i = 0; i < sbat.size; i++)
+                               FreePool(sbat.entries[i]);
+
                if (EFI_ERROR(efi_status)) {
                        if (verbose)
                                console_print(L"Verification failed: %r\n", efi_status);
diff --git a/sbat.c b/sbat.c
index c03e243acf3b940d5db086afa8459f8eb8c1ed67..f64d0f2cc18b61d93d5f0c9f366ada363d78ca5b 100644 (file)
--- a/sbat.c
+++ b/sbat.c
@@ -3,6 +3,121 @@
  * sbat.c - parse SBAT data from the .sbat section data
  */
 
-#include "shim.h"
+#include "sbat.h"
+
+CHAR8 *
+get_sbat_field(CHAR8 *current, CHAR8 *end, const CHAR8 ** field, char delim)
+{
+        CHAR8 *offset;
+
+        if (!field || !current || !end || current >= end)
+                return NULL;
+
+        offset = strchrnula(current, delim);
+        *field = current;
+
+        if (!*offset)
+                return NULL;
+
+        *offset = '\0';
+        return offset + 1;
+}
+
+EFI_STATUS parse_sbat_entry(CHAR8 **current, CHAR8 *end,
+                           struct sbat_entry **sbat_entry)
+{
+       struct sbat_entry *entry = NULL;
+
+       entry = AllocateZeroPool(sizeof(*entry));
+       if (!entry)
+               return EFI_OUT_OF_RESOURCES;
+
+       *current = get_sbat_field(*current, end, &entry->component_name, ',');
+       if (!entry->component_name)
+               goto error;
+
+       *current = get_sbat_field(*current, end, &entry->component_generation,',');
+       if (!entry->component_generation)
+               goto error;
+
+       *current = get_sbat_field(*current, end, &entry->vendor_name,',');
+       if (!entry->vendor_name)
+               goto error;
+
+       *current = get_sbat_field(*current, end, &entry->vendor_package_name, ',');
+       if (!entry->vendor_package_name)
+               goto error;
+
+       *current = get_sbat_field(*current, end, &entry->vendor_version,',');
+       if (!entry->vendor_version)
+               goto error;
+
+       *current = get_sbat_field(*current, end, &entry->vendor_url,'\n');
+       if (!entry->vendor_url)
+               goto error;
+
+       *sbat_entry = entry;
+
+       return EFI_SUCCESS;
+
+error:
+       FreePool(entry);
+       return EFI_INVALID_PARAMETER;
+}
+
+EFI_STATUS parse_sbat(char *sbat_base, size_t sbat_size, char *buffer,
+                     struct sbat *sbat)
+{
+       CHAR8 *current = (CHAR8 *) sbat_base;
+       CHAR8 *end = (CHAR8 *) sbat_base + sbat_size;
+       EFI_STATUS efi_status = EFI_SUCCESS;
+       struct sbat_entry *entry;
+       struct sbat_entry **entries;
+       unsigned int i;
+
+       while ((*current == '\r' || *current == '\n') && current < end)
+               current++;
+
+       if (current == end)
+               return EFI_INVALID_PARAMETER;
+
+       while ((*end == '\r' || *end == '\n') && end < current)
+               end--;
+
+       *(end - 1) = '\0';
+
+       do {
+               entry = NULL;
+               efi_status = parse_sbat_entry(&current, end, &entry);
+               if (EFI_ERROR(efi_status))
+                       goto error;
+
+               if (end < current) {
+                       efi_status = EFI_INVALID_PARAMETER;
+                       goto error;
+               }
+
+               if (entry) {
+                       entries = ReallocatePool(sbat->entries,
+                                                sbat->size * sizeof(entry),
+                                                (sbat->size + 1) * sizeof(entry));
+                       if (!entries) {
+                               efi_status = EFI_OUT_OF_RESOURCES;
+                               goto error;
+                       }
+
+                       sbat->entries = entries;
+                       sbat->entries[sbat->size] = entry;
+                       sbat->size++;
+               }
+       } while (entry && *current != '\0');
+
+       return efi_status;
+error:
+       perror(L"Failed to parse SBAT data: %r\n", efi_status);
+       for (i = 0; i < sbat->size; i++)
+               FreePool(sbat->entries[i]);
+       return efi_status;
+}
 
 // vim:fenc=utf-8:tw=75:noet