Introduce a new helper efi_capsule_update_info_gen_ids() which populates
the capsule update fw images image_type_id field. This allows for
determinstic UUIDs to be used that can scale to a large number of
different boards and board variants without the need to maintain a big
list.

We call this from efi_fill_image_desc_array() to populate the UUIDs
lazily on-demand.

This is behind an additional config option as it depends on V5 UUIDs and
the SHA1 implementation.

Signed-off-by: Caleb Connolly <caleb.conno...@linaro.org>
---
 lib/efi_loader/Kconfig        | 23 +++++++++++++++
 lib/efi_loader/efi_capsule.c  |  1 +
 lib/efi_loader/efi_firmware.c | 66 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 90 insertions(+)

diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index 430bb7f0f7dc..e90caf4f8e14 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -235,8 +235,31 @@ config EFI_CAPSULE_ON_DISK_EARLY
          If this option is enabled, capsules will be enforced to be
          executed as part of U-Boot initialisation so that they will
          surely take place whatever is set to distro_bootcmd.
 
+config EFI_CAPSULE_DYNAMIC_UUIDS
+       bool "Dynamic UUIDs for capsules"
+       depends on EFI_HAVE_CAPSULE_SUPPORT
+       select UUID_GEN_V5
+       help
+         Select this option if you want to use dynamically generated v5
+         UUIDs for your board. To make use of this feature, your board
+         code should call efi_capsule_update_info_gen_ids() with a seed
+         UUID to generate the image_type_id field for each fw_image.
+
+         The CapsuleUpdate payloads are expected to generate matching UUIDs
+         using the same scheme.
+
+config EFI_CAPSULE_NAMESPACE_UUID
+       string "Namespace UUID for dynamic UUIDs"
+       depends on EFI_CAPSULE_DYNAMIC_UUIDS
+       help
+         Define the namespace or "salt" UUID used to generate the per-image
+         UUIDs. This should be a UUID in the standard 8-4-4-4-12 format.
+
+         Device vendors are expected to generate their own namespace UUID
+         to avoid conflicts with existing products.
+
 config EFI_CAPSULE_FIRMWARE
        bool
 
 config EFI_CAPSULE_FIRMWARE_MANAGEMENT
diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
index 0937800e588f..ac02e79ae7d8 100644
--- a/lib/efi_loader/efi_capsule.c
+++ b/lib/efi_loader/efi_capsule.c
@@ -19,8 +19,9 @@
 #include <mapmem.h>
 #include <sort.h>
 #include <sysreset.h>
 #include <asm/global_data.h>
+#include <uuid.h>
 
 #include <crypto/pkcs7.h>
 #include <crypto/pkcs7_parser.h>
 #include <linux/err.h>
diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c
index ba5aba098c0f..a8dafe4f01a5 100644
--- a/lib/efi_loader/efi_firmware.c
+++ b/lib/efi_loader/efi_firmware.c
@@ -244,8 +244,71 @@ void efi_firmware_fill_version_info(struct 
efi_firmware_image_descriptor *image_
 
        free(var_state);
 }
 
+#if CONFIG_IS_ENABLED(EFI_CAPSULE_DYNAMIC_UUIDS)
+/**
+ * efi_capsule_update_info_gen_ids - generate GUIDs for the images
+ *
+ * Generate the image_type_id for each image in the update_info.images array
+ * using the first compatible from the device tree and a salt
+ * UUID defined at build time.
+ *
+ * Returns:            status code
+ */
+static efi_status_t efi_capsule_update_info_gen_ids(void)
+{
+       int ret, i;
+       struct uuid namespace;
+       const char *compatible; /* Full array including null bytes */
+       struct efi_fw_image *fw_array;
+
+       fw_array = update_info.images;
+       /* Check if we need to run (there are images and we didn't already 
generate their IDs) */
+       if (!update_info.num_images ||
+           memchr_inv(&fw_array[0].image_type_id, 0, 
sizeof(fw_array[0].image_type_id)))
+               return EFI_SUCCESS;
+
+       ret = uuid_str_to_bin(CONFIG_EFI_CAPSULE_NAMESPACE_UUID,
+                       (unsigned char *)&namespace, UUID_STR_FORMAT_GUID);
+       if (ret) {
+               log_debug("%s: CONFIG_EFI_CAPSULE_NAMESPACE_UUID is invalid: 
%d\n", __func__, ret);
+               return EFI_UNSUPPORTED;
+       }
+
+       compatible = ofnode_read_string(ofnode_root(), "compatible");
+
+       if (!compatible) {
+               log_debug("%s: model or compatible not defined\n", __func__);
+               return EFI_UNSUPPORTED;
+       }
+
+       if (!update_info.num_images) {
+               log_debug("%s: no fw_images, make sure update_info.num_images 
is set\n", __func__);
+               return -ENODATA;
+       }
+
+       for (i = 0; i < update_info.num_images; i++) {
+               gen_uuid_v5(&namespace,
+                           (struct uuid *)&fw_array[i].image_type_id,
+                           compatible, strlen(compatible),
+                           fw_array[i].fw_name, 
u16_strsize(fw_array[i].fw_name)
+                               - sizeof(uint16_t),
+                           NULL);
+
+               log_debug("Image %ls UUID %pUs\n", fw_array[i].fw_name,
+                         &fw_array[i].image_type_id);
+       }
+
+       return EFI_SUCCESS;
+}
+#else
+static efi_status_t efi_capsule_update_info_gen_ids(void)
+{
+       return EFI_SUCCESS;
+}
+#endif
+
 /**
  * efi_fill_image_desc_array - populate image descriptor array
  * @image_info_size:           Size of @image_info
  * @image_info:                        Image information
@@ -282,8 +345,11 @@ static efi_status_t efi_fill_image_desc_array(
                return EFI_BUFFER_TOO_SMALL;
        }
        *image_info_size = total_size;
 
+       if (efi_capsule_update_info_gen_ids() != EFI_SUCCESS)
+               return EFI_UNSUPPORTED;
+
        fw_array = update_info.images;
        *descriptor_count = update_info.num_images;
        *descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
        *descriptor_size = sizeof(*image_info);

-- 
2.45.0

Reply via email to