[PATCH] test: lib/uuid: Fix endianness for dynamic GUIDs
Alexey Charkov <[email protected]>
| Newsgroups | org.u-boot-project.lists.u-boot |
|---|---|
| Message-ID | <[email protected]> |
If LIB_UUID is enabled on a big-endian board, such as when it is pulled in by EFI_PARTITION, its tests will fail due to the dynamic capsule GUIDs computed by lib_test_dynamic_uuid() using native endianness for the UTF-16 image name, instead of little-endian: malta # ut lib lib_test_dynamic_uuid Test: dynamic_uuid: uuid.c test/lib/uuid.c:114, lib_test_dynamic_uuid_case(): expected_uuid = uuid_str: Expected "985f2937-7c2e-5e9a-8a5e-8e063312964b", got "829f5cb0-1a07-5718-8774-4514bda82c39" Test 'dynamic_uuid' failed 1 times Tests run: 1, 2 ms, average: 2 ms, failures: 1 exit not allowed from main input shell. malta # Add explicit endianness conversion to the test and to other similar callers of gen_v5_guid() to make sure they work uniformly regardless of the host or target endianness. Signed-off-by: Alexey Charkov <[email protected]> --- This was uncovered [1] while adding tests for GPT partition labels on big endian boards, which pulls in PARTITION_UUIDS, which in turn pulls in LIB_UUID and its tests. Turns out no BE board in CI ever enabled LIB_UUID, so this went unnoticed to date. The immediate users of this code other than the test suite are EFI capsule updates, which is unlikely to be relevant for anything big endian (given that UEFI is little endian), but the test suite itself seems to be a good reason to get this fixed. No functional change on little endian either way. [1] https://git.u-boot-project.org/u-boot/contributors/alchark/u-boot/-/pipelines/1101 --- include/u-boot/uuid.h | 5 +++++ lib/efi_loader/efi_firmware.c | 19 ++++++++++++++++++- test/lib/uuid.c | 15 ++++++++++++++- tools/mkeficapsule.c | 3 ++- 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/include/u-boot/uuid.h b/include/u-boot/uuid.h index 7f8414dc906c..acdf3a85a6cb 100644 --- a/include/u-boot/uuid.h +++ b/include/u-boot/uuid.h @@ -149,6 +149,11 @@ struct efi_guid; /** * gen_v5_guid() - generate little endian v5 GUID from namespace and other seed data. * + * The seed data is hashed as raw bytes, so any of it that is not a byte string + * has to be supplied in a fixed byte order for the result to be reproducible. + * UTF-16 seed data, such as a firmware image name, must therefore be passed + * little-endian, which is the byte order the UEFI specification uses for it. + * * @namespace: pointer to UUID namespace salt * @guid: pointer to allocated GUID output * @...: NULL terminated list of seed data as pairs of pointers diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c index b41969c70fde..7f3b2da3ef89 100644 --- a/lib/efi_loader/efi_firmware.c +++ b/lib/efi_loader/efi_firmware.c @@ -279,15 +279,32 @@ static efi_status_t efi_gen_capsule_guids(void) } for (i = 0; i < update_info.num_images; i++) { + size_t len, j; + u16 *name_le; + if (!fw_array[i].fw_name) { log_err("fw_name is not defined. Not generating capsule GUIDs\n"); return EFI_INVALID_PARAMETER; } + + /* + * The name is hashed as UTF-16LE, so that a big-endian board + * arrives at the same GUID as mkeficapsule running on a + * little-endian build host. + */ + len = u16_strlen(fw_array[i].fw_name); + name_le = calloc(len, sizeof(*name_le)); + if (!name_le) + return EFI_OUT_OF_RESOURCES; + for (j = 0; j < len; j++) + name_le[j] = cpu_to_le16(fw_array[i].fw_name[j]); + 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), + name_le, len * sizeof(*name_le), NULL); + free(name_le); log_debug("Image %ls UUID %pUl\n", fw_array[i].fw_name, &fw_array[i].image_type_id); diff --git a/test/lib/uuid.c b/test/lib/uuid.c index d00e9563a472..1c66021af3ed 100644 --- a/test/lib/uuid.c +++ b/test/lib/uuid.c @@ -10,6 +10,7 @@ #include <charset.h> #include <u-boot/uuid.h> +#include <asm/byteorder.h> #include <test/lib.h> #include <test/test.h> #include <test/ut.h> @@ -102,12 +103,24 @@ static int lib_test_dynamic_uuid_case(struct unit_test_state *uts, for (j = 0; data->images[j]; j++) { const char *expected_uuid = data->expected_uuids[j]; const u16 *image = data->images[j]; + u16 image_le[64]; efi_guid_t uuid; char uuid_str[37]; + size_t len, k; + + /* + * u"..." is native-endian, but the name is hashed as UTF-16LE + * so that the GUID does not depend on the endianness of the + * board or of the host running mkeficapsule. + */ + len = u16_strlen(image); + ut_assert(len <= ARRAY_SIZE(image_le)); + for (k = 0; k < len; k++) + image_le[k] = cpu_to_le16(image[k]); gen_v5_guid(&namespace, &uuid, data->compatible, strlen(data->compatible), - image, u16_strlen(image) * sizeof(uint16_t), + image_le, len * sizeof(*image_le), NULL); uuid_bin_to_str((unsigned char *)&uuid, uuid_str, UUID_STR_FORMAT_GUID); diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c index ec640c57e8a5..55a58f07d56e 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -1004,8 +1004,9 @@ static int genguid(int argc, char **argv) return -1; } + /* The name is hashed as UTF-16LE, whatever this host is */ for (int i = 0; i < namelen; i++) - fw_image[i] = (uint16_t)argv[idx][i]; + fw_image[i] = cpu_to_le16((uint16_t)argv[idx][i]); gen_v5_guid((struct uuid *)&namespace, &image_type_id, compatible, strlen(compatible), --- base-commit: 964ad5b5c91b7be56e443e899d7f873e6aa8c9fc change-id: 20260827-uuid-be-56657e7aa80e Best regards, -- Alexey Charkov <[email protected]>