From 0f5a86b29fcc1c1f4e4be5d5899de52217ecd5be Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Wed, 9 Sep 2026 10:10:03 +0200 Subject: [PATCH] lib/ucs2_string: Split out ucs2_as_utf8_l() taking a separate limit ucs2_as_utf8() takes a maxlength argument, which specifies how many bytes the function is permitted to store into the destination buffer. The same value is used as an upper bound for the ucs2_strnlen() invocation, which is reasonable in the general case, as each UCS-2 character produces at least one byte of UTF-8 output, and so there is never a need to process more than 'maxlength' UCS-2 characters. However, if the UCS-2 string is not NUL terminated, ucs2_strnlen() may read past the end of the buffer if 'maxlength' is set to a high value. Current callers pass UCS-2 strings that are expected to be NUL terminated, but for processing the load options in the EFI stub, a version is needed that takes a separate limit argument. So split that off from the current implementation. Reviewed-by: Vincent Mailhol Signed-off-by: Ard Biesheuvel --- include/linux/ucs2_string.h | 11 ++++++++++- lib/ucs2_string.c | 15 ++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/include/linux/ucs2_string.h b/include/linux/ucs2_string.h index c499ae809c7d..74f23ca5a967 100644 --- a/include/linux/ucs2_string.h +++ b/include/linux/ucs2_string.h @@ -14,7 +14,16 @@ ssize_t ucs2_strscpy(ucs2_char_t *dst, const ucs2_char_t *src, size_t count); int ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len); unsigned long ucs2_utf8size(const ucs2_char_t *src); +unsigned long +ucs2_as_utf8_l(u8 *dest, const ucs2_char_t *src, unsigned long limit, + unsigned long maxlength); + +static inline unsigned long ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, - unsigned long maxlength); + unsigned long maxlength) +{ + return ucs2_as_utf8_l(dest, src, ucs2_strnlen(src, maxlength), + maxlength); +} #endif /* _LINUX_UCS2_STRING_H_ */ diff --git a/lib/ucs2_string.c b/lib/ucs2_string.c index 185378e64d2e..32e167332840 100644 --- a/lib/ucs2_string.c +++ b/lib/ucs2_string.c @@ -123,18 +123,19 @@ ucs2_utf8size(const ucs2_char_t *src) EXPORT_SYMBOL(ucs2_utf8size); /* - * copy at most maxlength bytes of whole utf8 characters to dest from the - * ucs2 string src. + * Copy at most @limit whole utf8 characters to @dest from the ucs2 string + * @src, using no more than @maxlength bytes of buffer space. * - * The return value is the number of characters copied, not including the - * final NUL character. + * The return value is the number of bytes copied, not including the final NUL + * character. No NUL character will be appended if the output length equals + * @maxlength. */ unsigned long -ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, unsigned long maxlength) +ucs2_as_utf8_l(u8 *dest, const ucs2_char_t *src, unsigned long limit, + unsigned long maxlength) { unsigned int i; unsigned long j = 0; - unsigned long limit = ucs2_strnlen(src, maxlength); for (i = 0; maxlength && i < limit; i++) { u16 c = src[i]; @@ -161,7 +162,7 @@ ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, unsigned long maxlength) dest[j] = '\0'; return j; } -EXPORT_SYMBOL(ucs2_as_utf8); +EXPORT_SYMBOL(ucs2_as_utf8_l); #ifndef __DISABLE_EXPORTS MODULE_DESCRIPTION("UCS2 string handling");