Message ID | 20240426-b4-dynamic-uuid-v1-2-e8154e00ec44@linaro.org |
---|---|
State | New |
Headers | show |
Series | efi: CapsuleUpdate: support for dynamic GUIDs | expand |
[...] > 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 >
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 >>
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 --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) ||
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(+)