diff mbox series

[RFC,2/4] efi: add a helper to generate dynamic UUIDs

Message ID 20240426-b4-dynamic-uuid-v1-2-e8154e00ec44@linaro.org
State RFC
Delegated to: Ilias Apalodimas
Headers show
Series efi: CapsuleUpdate: support for dynamic GUIDs | expand

Commit Message

Caleb Connolly April 26, 2024, 2:19 p.m. UTC
Introduce a new helper efi_capsule_update_info_gen_ids() which takes
several strings to identify the currently running board as well as a
platform specific salt UUID and uses this data to populate 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.

Generating capsule updates can be done using the same namespace, soc,
model, compatible, and fw_image name strings.

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

Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
 include/efi_loader.h         | 28 ++++++++++++++++++++++++++++
 lib/efi_loader/Kconfig       | 14 ++++++++++++++
 lib/efi_loader/efi_capsule.c | 33 +++++++++++++++++++++++++++++++++
 3 files changed, 75 insertions(+)

Comments

Ilias Apalodimas May 24, 2024, 6:37 a.m. UTC | #1
[...]


>  config EFI_CAPSULE_FIRMWARE_MANAGEMENT
> diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
> index de0d49ebebda..9ef67d1b4405 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>
> @@ -403,8 +404,40 @@ out:
>         return status;
>  }
>  #endif /* CONFIG_EFI_CAPSULE_AUTHENTICATE */
>
> +#if CONFIG_IS_ENABLED(EFI_CAPSULE_DYNAMIC_UUIDS)
> +int efi_capsule_update_info_gen_ids(efi_guid_t *namespace, const char *soc, const char *model, const char *compatible)
> +{
> +       int i;

Perhaps irrelevant to this patch, but do we need to define the name
space in platform code?
Can't we just put it on a Kconfig and do the dynamic UUIID generation
in efi_capsule.c?

Thanks
/Ilias
> +
> +       if (!soc || !model || !compatible) {
> +               log_err("%s: soc, model, or compatible not defined\n", __func__);
> +               return -EINVAL;
> +       }
> +
> +       if (!update_info.num_images) {
> +               log_err("%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((struct uuid*)namespace,
> +                           (struct uuid *)&update_info.images[i].image_type_id,
> +                           soc, strlen(soc),
> +                           model, strlen(model),
> +                           compatible, strlen(compatible),
> +                           update_info.images[i].fw_name, u16_strlen(update_info.images[i].fw_name),
> +                           NULL);
> +
> +               log_debug("Image %ls generated UUID %pUs\n", update_info.images[i].fw_name,
> +                         &update_info.images[i].image_type_id);
> +       }
> +
> +       return 0;
> +}
> +#endif
> +
>  static __maybe_unused bool fwu_empty_capsule(struct efi_capsule_header *capsule)
>  {
>         return !guidcmp(&capsule->capsule_guid,
>                         &fwu_guid_os_request_fw_revert) ||
>
> --
> 2.44.0
>
Caleb Connolly May 24, 2024, 12:17 p.m. UTC | #2
On 24/05/2024 08:37, Ilias Apalodimas wrote:
> [...]
> 
> 
>>   config EFI_CAPSULE_FIRMWARE_MANAGEMENT
>> diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
>> index de0d49ebebda..9ef67d1b4405 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>
>> @@ -403,8 +404,40 @@ out:
>>          return status;
>>   }
>>   #endif /* CONFIG_EFI_CAPSULE_AUTHENTICATE */
>>
>> +#if CONFIG_IS_ENABLED(EFI_CAPSULE_DYNAMIC_UUIDS)
>> +int efi_capsule_update_info_gen_ids(efi_guid_t *namespace, const char *soc, const char *model, const char *compatible)
>> +{
>> +       int i;
> 
> Perhaps irrelevant to this patch, but do we need to define the name
> space in platform code?
> Can't we just put it on a Kconfig and do the dynamic UUIID generation
> in efi_capsule.c?

Having the namespace be a kconfig option probably makes sense, then it 
could be the thing vendors have to populate for their production boards 
(and they could just have one for all of their products across many 
architectures). So by setting one option they'd have totally unique 
GUIDs for everything.

> 
> Thanks
> /Ilias
>> +
>> +       if (!soc || !model || !compatible) {
>> +               log_err("%s: soc, model, or compatible not defined\n", __func__);
>> +               return -EINVAL;
>> +       }
>> +
>> +       if (!update_info.num_images) {
>> +               log_err("%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((struct uuid*)namespace,
>> +                           (struct uuid *)&update_info.images[i].image_type_id,
>> +                           soc, strlen(soc),
>> +                           model, strlen(model),
>> +                           compatible, strlen(compatible),
>> +                           update_info.images[i].fw_name, u16_strlen(update_info.images[i].fw_name),
>> +                           NULL);
>> +
>> +               log_debug("Image %ls generated UUID %pUs\n", update_info.images[i].fw_name,
>> +                         &update_info.images[i].image_type_id);
>> +       }
>> +
>> +       return 0;
>> +}
>> +#endif
>> +
>>   static __maybe_unused bool fwu_empty_capsule(struct efi_capsule_header *capsule)
>>   {
>>          return !guidcmp(&capsule->capsule_guid,
>>                          &fwu_guid_os_request_fw_revert) ||
>>
>> --
>> 2.44.0
>>
Ilias Apalodimas May 24, 2024, 12:20 p.m. UTC | #3
On Fri, 24 May 2024 at 15:17, Caleb Connolly <caleb.connolly@linaro.org> wrote:
>
>
>
> On 24/05/2024 08:37, Ilias Apalodimas wrote:
> > [...]
> >
> >
> >>   config EFI_CAPSULE_FIRMWARE_MANAGEMENT
> >> diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
> >> index de0d49ebebda..9ef67d1b4405 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>
> >> @@ -403,8 +404,40 @@ out:
> >>          return status;
> >>   }
> >>   #endif /* CONFIG_EFI_CAPSULE_AUTHENTICATE */
> >>
> >> +#if CONFIG_IS_ENABLED(EFI_CAPSULE_DYNAMIC_UUIDS)
> >> +int efi_capsule_update_info_gen_ids(efi_guid_t *namespace, const char *soc, const char *model, const char *compatible)
> >> +{
> >> +       int i;
> >
> > Perhaps irrelevant to this patch, but do we need to define the name
> > space in platform code?
> > Can't we just put it on a Kconfig and do the dynamic UUIID generation
> > in efi_capsule.c?
>
> Having the namespace be a kconfig option probably makes sense, then it
> could be the thing vendors have to populate for their production boards
> (and they could just have one for all of their products across many
> architectures). So by setting one option they'd have totally unique
> GUIDs for everything.

Exactly and you would be able to reuse the entire machinery without
having to add platform code, since the GUID population would live in
the the efi firmware parts

Cheers
/Ilias
>
> >
> > Thanks
> > /Ilias
> >> +
> >> +       if (!soc || !model || !compatible) {
> >> +               log_err("%s: soc, model, or compatible not defined\n", __func__);
> >> +               return -EINVAL;
> >> +       }
> >> +
> >> +       if (!update_info.num_images) {
> >> +               log_err("%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((struct uuid*)namespace,
> >> +                           (struct uuid *)&update_info.images[i].image_type_id,
> >> +                           soc, strlen(soc),
> >> +                           model, strlen(model),
> >> +                           compatible, strlen(compatible),
> >> +                           update_info.images[i].fw_name, u16_strlen(update_info.images[i].fw_name),
> >> +                           NULL);
> >> +
> >> +               log_debug("Image %ls generated UUID %pUs\n", update_info.images[i].fw_name,
> >> +                         &update_info.images[i].image_type_id);
> >> +       }
> >> +
> >> +       return 0;
> >> +}
> >> +#endif
> >> +
> >>   static __maybe_unused bool fwu_empty_capsule(struct efi_capsule_header *capsule)
> >>   {
> >>          return !guidcmp(&capsule->capsule_guid,
> >>                          &fwu_guid_os_request_fw_revert) ||
> >>
> >> --
> >> 2.44.0
> >>
>
> --
> // Caleb (they/them)
diff mbox series

Patch

diff --git a/include/efi_loader.h b/include/efi_loader.h
index 69442f4e58de..7d6b6ff83229 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -1125,8 +1125,36 @@  struct efi_capsule_update_info {
 };
 
 extern struct efi_capsule_update_info update_info;
 
+#if CONFIG_IS_ENABLED(EFI_CAPSULE_DYNAMIC_UUIDS)
+/**
+ * efi_capsule_update_info_gen_ids - Generate image_type_id UUIDs
+ * for all firmware images based on a platform namespace UUID.
+ *
+ * @namespace: The arch/platform specific namespace salt. This should be
+ * hardcoded per platform and replaced by vendors.
+ * @soc: A string identifying the SoC used on this board.
+ * @model: The model string for the board.
+ * @compatible: The most specific (first) root compatible string.
+ *
+ * This can be called by board code to populate the image_type_id
+ * UUID fields deterministically based on the board's model. Allowing
+ * many boards to be supported without the need for a large hardcoded
+ * array of fw images. This works using v5 UUIDs.
+ */
+int efi_capsule_update_info_gen_ids(efi_guid_t *namespace, const char *soc,
+				    const char *model,
+				    const char *compatible);
+#else
+static inline int efi_capsule_update_info_gen_ids(efi_guid_t *namespace, const char *soc,
+						  const char *model,
+						  const char *compatible)
+{
+	return -ENOSYS;
+}
+#endif
+
 /**
  * Install the ESRT system table.
  *
  * Return:	status code
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index 430bb7f0f7dc..dd8fc1b08812 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -235,8 +235,22 @@  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_FIRMWARE
 	bool
 
 config EFI_CAPSULE_FIRMWARE_MANAGEMENT
diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
index de0d49ebebda..9ef67d1b4405 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>
@@ -403,8 +404,40 @@  out:
 	return status;
 }
 #endif /* CONFIG_EFI_CAPSULE_AUTHENTICATE */
 
+#if CONFIG_IS_ENABLED(EFI_CAPSULE_DYNAMIC_UUIDS)
+int efi_capsule_update_info_gen_ids(efi_guid_t *namespace, const char *soc, const char *model, const char *compatible)
+{
+	int i;
+
+	if (!soc || !model || !compatible) {
+		log_err("%s: soc, model, or compatible not defined\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!update_info.num_images) {
+		log_err("%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((struct uuid*)namespace,
+			    (struct uuid *)&update_info.images[i].image_type_id,
+			    soc, strlen(soc),
+			    model, strlen(model),
+			    compatible, strlen(compatible),
+			    update_info.images[i].fw_name, u16_strlen(update_info.images[i].fw_name),
+			    NULL);
+
+		log_debug("Image %ls generated UUID %pUs\n", update_info.images[i].fw_name,
+			  &update_info.images[i].image_type_id);
+	}
+
+	return 0;
+}
+#endif
+
 static __maybe_unused bool fwu_empty_capsule(struct efi_capsule_header *capsule)
 {
 	return !guidcmp(&capsule->capsule_guid,
 			&fwu_guid_os_request_fw_revert) ||