[PATCH] efi: pass NUL-inclusive sizes to ucs2_as_utf8()

From: Vincent Mailhol

Date: Tue Sep 08 2026 - 17:12:55 EST


An upcoming change will update ucs2_as_utf8() to expose a strscpy()
style API where the size argument is the destination buffer size,
including space for the final NUL terminator.

Some EFI callers currently pass the exact number of UTF-8 payload bytes
that they expect to copy and add the terminator themselves afterwards.
Extend those sizes to include the final NUL terminator so the upcoming
contract change does not truncate the converted output by one byte.

Signed-off-by: Vincent Mailhol <mailhol@xxxxxxxxxx>
---
Hi Ard,

I saw that you pushed on efi-libstub-native-utf16 WIP branch [1] and did
some testing, despite those changes not yet submitted for review.

There is an off-by-one error following your ucs2_as_utf8() code
refactor. This patch prevents the issue. It should be cherry-picked just
before your "efi/libstub: Use ucs2_string library for UTF-16 to UTF-8
conversion" commit.

There is one final off-by-one in "efi/libstub: Use ucs2_string library
for UTF-16 to UTF-8 conversion" itself. This is the fix:

---8<---
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index e9b714ca811db..db0bde514f7fd 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -379,8 +379,7 @@ char *efi_convert_cmdline(efi_loaded_image_t *image)
if (status != EFI_SUCCESS)
return NULL;

- ucs2_as_utf8(cmdline_addr, options, options_bytes - 1);
- cmdline_addr[options_bytes - 1] = '\0';
+ ucs2_as_utf8(cmdline_addr, options, options_bytes);

return cmdline_addr;
}
---8<---

[1] https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efi-libstub-native-utf16
---
drivers/firmware/efi/efi.c | 2 +-
fs/efivarfs/vars.c | 5 ++---
2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 6d987d7f97781..221804e7d5390 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -304,7 +304,7 @@ static __init int efivar_ssdt_load(void)
}

limit = min(EFIVAR_SSDT_NAME_MAX, name_size);
- ucs2_as_utf8(utf8_name, name, limit - 1);
+ ucs2_as_utf8(utf8_name, name, limit);
if (strncmp(utf8_name, efivar_ssdt, limit) != 0)
continue;

diff --git a/fs/efivarfs/vars.c b/fs/efivarfs/vars.c
index 6833c3d24b541..1ddc89e13518f 100644
--- a/fs/efivarfs/vars.c
+++ b/fs/efivarfs/vars.c
@@ -237,7 +237,7 @@ efivar_get_utf8name(const efi_char16_t *name16, efi_guid_t *vendor)
if (!name)
return NULL;

- ucs2_as_utf8(name, name16, len);
+ ucs2_as_utf8(name, name16, len + 1);

name[len] = '-';

@@ -264,8 +264,7 @@ efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data,
if (!utf8_name)
return false;

- ucs2_as_utf8(utf8_name, var_name, utf8_size);
- utf8_name[utf8_size] = '\0';
+ ucs2_as_utf8(utf8_name, var_name, utf8_size + 1);

for (i = 0; variable_validate[i].name[0] != '\0'; i++) {
const char *name = variable_validate[i].name;
--
2.43.0