diff mbox series

[v7,03/11] efi: add a helper to generate dynamic UUIDs

Message ID 20240809-b4-dynamic-uuid-v7-3-8c44ab1f06a5@linaro.org
State Superseded
Headers show
Series efi: CapsuleUpdate: support for dynamic UUIDs | expand

Commit Message

Caleb Connolly Aug. 9, 2024, 12:56 a.m. UTC
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.

Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
 lib/efi_loader/Kconfig        | 12 ++++++++++
 lib/efi_loader/efi_capsule.c  |  1 +
 lib/efi_loader/efi_firmware.c | 55 ++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 67 insertions(+), 1 deletion(-)

Comments

Ilias Apalodimas Aug. 26, 2024, 2:42 p.m. UTC | #1
On Fri, 9 Aug 2024 at 03:56, Caleb Connolly <caleb.connolly@linaro.org> wrote:
>
> 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.
>
> Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
> ---
>  lib/efi_loader/Kconfig        | 12 ++++++++++
>  lib/efi_loader/efi_capsule.c  |  1 +
>  lib/efi_loader/efi_firmware.c | 55 ++++++++++++++++++++++++++++++++++++++++++-
>  3 files changed, 67 insertions(+), 1 deletion(-)
>
> diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
> index 1179c31bb136..85a31113fcf0 100644
> --- a/lib/efi_loader/Kconfig
> +++ b/lib/efi_loader/Kconfig
> @@ -236,8 +236,20 @@ 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_NAMESPACE_GUID
> +       string "Namespace for dynamic capsule GUIDs"
> +       # v4 UUID as a default for upstream U-Boot boards
> +       default "8c9f137e-91dc-427b-b2d6-b420faebaf2a"
> +       depends on EFI_HAVE_CAPSULE_SUPPORT
> +       help
> +         Define the namespace or "salt" GUID used to generate the per-image
> +         GUIDs. This should be a GUID in the standard 8-4-4-4-12 format.
> +
> +         Device vendors are expected to generate their own namespace GUID
> +         to avoid conflicts with upstream/community images.
> +
>  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 635088f25a13..f3a2388506cc 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..c0240e95cf13 100644
> --- a/lib/efi_loader/efi_firmware.c
> +++ b/lib/efi_loader/efi_firmware.c
> @@ -244,8 +244,57 @@ void efi_firmware_fill_version_info(struct efi_firmware_image_descriptor *image_
>
>         free(var_state);
>  }
>
> +/**
> + * efi_gen_capsule_guids - 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_gen_capsule_guids(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_GUID,
> +                       (unsigned char *)&namespace, UUID_STR_FORMAT_GUID);
> +       if (ret) {
> +               log_debug("%s: EFI_CAPSULE_NAMESPACE_GUID is invalid: %d\n", __func__, ret);
> +               return EFI_INVALID_PARAMETER;
> +       }
> +
> +       compatible = ofnode_read_string(ofnode_root(), "compatible");
> +       if (!compatible) {
> +               log_debug("%s: model or compatible not defined\n", __func__);
> +               return EFI_INVALID_PARAMETER;
> +       }
> +
> +       for (i = 0; i < update_info.num_images; i++) {
> +               gen_v5_guid(&namespace,
> +                           &fw_array[i].image_type_id,
> +                           compatible, strlen(compatible),
> +                           fw_array[i].fw_name, u16_strlen(fw_array[i].fw_name) * sizeof(uint16_t),
> +                           NULL);
> +
> +               log_debug("Image %ls UUID %pUl\n", fw_array[i].fw_name,
> +                         &fw_array[i].image_type_id);
> +       }
> +
> +       return EFI_SUCCESS;
> +}
> +
>  /**
>   * efi_fill_image_desc_array - populate image descriptor array
>   * @image_info_size:           Size of @image_info
>   * @image_info:                        Image information
> @@ -271,9 +320,9 @@ static efi_status_t efi_fill_image_desc_array(
>         u16 **package_version_name)
>  {
>         size_t total_size;
>         struct efi_fw_image *fw_array;
> -       int i;
> +       int i, ret;
>
>         total_size = sizeof(*image_info) * update_info.num_images;
>
>         if (*image_info_size < total_size) {
> @@ -282,8 +331,12 @@ static efi_status_t efi_fill_image_desc_array(
>                 return EFI_BUFFER_TOO_SMALL;
>         }
>         *image_info_size = total_size;
>
> +       ret = efi_gen_capsule_guids();

ret should be efi_status_t

> +       if (ret != EFI_SUCCESS)
> +               return ret;
> +
>         fw_array = update_info.images;
>         *descriptor_count = update_info.num_images;
>         *descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
>         *descriptor_size = sizeof(*image_info);
>
> --
> 2.46.0
>

with the fix above
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
diff mbox series

Patch

diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index 1179c31bb136..85a31113fcf0 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -236,8 +236,20 @@  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_NAMESPACE_GUID
+	string "Namespace for dynamic capsule GUIDs"
+	# v4 UUID as a default for upstream U-Boot boards
+	default "8c9f137e-91dc-427b-b2d6-b420faebaf2a"
+	depends on EFI_HAVE_CAPSULE_SUPPORT
+	help
+	  Define the namespace or "salt" GUID used to generate the per-image
+	  GUIDs. This should be a GUID in the standard 8-4-4-4-12 format.
+
+	  Device vendors are expected to generate their own namespace GUID
+	  to avoid conflicts with upstream/community images.
+
 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 635088f25a13..f3a2388506cc 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..c0240e95cf13 100644
--- a/lib/efi_loader/efi_firmware.c
+++ b/lib/efi_loader/efi_firmware.c
@@ -244,8 +244,57 @@  void efi_firmware_fill_version_info(struct efi_firmware_image_descriptor *image_
 
 	free(var_state);
 }
 
+/**
+ * efi_gen_capsule_guids - 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_gen_capsule_guids(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_GUID,
+			(unsigned char *)&namespace, UUID_STR_FORMAT_GUID);
+	if (ret) {
+		log_debug("%s: EFI_CAPSULE_NAMESPACE_GUID is invalid: %d\n", __func__, ret);
+		return EFI_INVALID_PARAMETER;
+	}
+
+	compatible = ofnode_read_string(ofnode_root(), "compatible");
+	if (!compatible) {
+		log_debug("%s: model or compatible not defined\n", __func__);
+		return EFI_INVALID_PARAMETER;
+	}
+
+	for (i = 0; i < update_info.num_images; i++) {
+		gen_v5_guid(&namespace,
+			    &fw_array[i].image_type_id,
+			    compatible, strlen(compatible),
+			    fw_array[i].fw_name, u16_strlen(fw_array[i].fw_name) * sizeof(uint16_t),
+			    NULL);
+
+		log_debug("Image %ls UUID %pUl\n", fw_array[i].fw_name,
+			  &fw_array[i].image_type_id);
+	}
+
+	return EFI_SUCCESS;
+}
+
 /**
  * efi_fill_image_desc_array - populate image descriptor array
  * @image_info_size:		Size of @image_info
  * @image_info:			Image information
@@ -271,9 +320,9 @@  static efi_status_t efi_fill_image_desc_array(
 	u16 **package_version_name)
 {
 	size_t total_size;
 	struct efi_fw_image *fw_array;
-	int i;
+	int i, ret;
 
 	total_size = sizeof(*image_info) * update_info.num_images;
 
 	if (*image_info_size < total_size) {
@@ -282,8 +331,12 @@  static efi_status_t efi_fill_image_desc_array(
 		return EFI_BUFFER_TOO_SMALL;
 	}
 	*image_info_size = total_size;
 
+	ret = efi_gen_capsule_guids();
+	if (ret != EFI_SUCCESS)
+		return ret;
+
 	fw_array = update_info.images;
 	*descriptor_count = update_info.num_images;
 	*descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
 	*descriptor_size = sizeof(*image_info);