diff options
| author | Ulises Mendez Martinez <umendez@google.com> | 2026-09-04 15:07:09 +0000 |
|---|---|---|
| committer | Josh Poimboeuf <jpoimboe@kernel.org> | 2026-09-13 18:15:43 -0700 |
| commit | 7e61560628d17ea6b1d8ee370f6d42694cff8758 (patch) | |
| tree | e6080164b2f4c4c419894bdb3ce4d956ca9a98c5 /lib/ucs2_string.c | |
| download | linux-stable-7e61560628d17ea6b1d8ee370f6d42694cff8758.tar.gz linux-stable-7e61560628d17ea6b1d8ee370f6d42694cff8758.zip | |
objtool: Validate disassembler headers in libopcodes probegrafted
commit 3f2de814c059 ("objtool: Fix libopcodes linking with static libraries")
tested for libopcodes availability by linking a test snippet with a forward
declaration of disassemble_init_for_target().
However, testing symbol linkage with an extern declaration only verifies
the presence of the library (.so/.a) and bypasses checking for development
headers (binutils-dev). On systems where libopcodes is present without
development headers installed, the probe succeeds, enabling BUILD_DISAS.
Subsequent compilation of objtool then fails:
fatal error: 'bfd.h' file not found
113 | #include <bfd.h>
Additionally, the probe invokes $(HOSTCC) without $(HOSTCFLAGS), ignoring
any sysroot or include flags specified for the host compiler.
Fix this by including <bfd.h> and <dis-asm.h> directly in the test snippet,
passing $(HOSTCFLAGS) so host compiler options are respected, and defining
PACKAGE="objtool" to satisfy the configuration check in <bfd.h>.
Fixes: 3f2de814c059 ("objtool: Fix libopcodes linking with static libraries")
Fixes: 436326bc525d ("objtool: fix build failure due to missing libopcodes check")
Reported-by: Alice Ryhl <aliceryhl@google.com>
Assisted-by: Antigravity:Gemini-Next
Signed-off-by: Ulises Mendez Martinez <umendez@google.com>
Link: https://patch.msgid.link/20260904150710.2997558-1-umendez@google.com
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Diffstat (limited to 'lib/ucs2_string.c')
| -rw-r--r-- | lib/ucs2_string.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/lib/ucs2_string.c b/lib/ucs2_string.c new file mode 100644 index 000000000..1f7dd4eb6 --- /dev/null +++ b/lib/ucs2_string.c @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/ucs2_string.h> +#include <linux/module.h> + +/* Return the number of unicode characters in data */ +unsigned long +ucs2_strnlen(const ucs2_char_t *s, size_t maxlength) +{ + unsigned long length = 0; + + while (length < maxlength && *s++ != 0) + length++; + return length; +} +EXPORT_SYMBOL(ucs2_strnlen); + +unsigned long +ucs2_strlen(const ucs2_char_t *s) +{ + return ucs2_strnlen(s, ~0UL); +} +EXPORT_SYMBOL(ucs2_strlen); + +/* + * Return the number of bytes is the length of this string + * Note: this is NOT the same as the number of unicode characters + */ +unsigned long +ucs2_strsize(const ucs2_char_t *data, unsigned long maxlength) +{ + return ucs2_strnlen(data, maxlength/sizeof(ucs2_char_t)) * sizeof(ucs2_char_t); +} +EXPORT_SYMBOL(ucs2_strsize); + +/** + * ucs2_strscpy() - Copy a UCS2 string into a sized buffer. + * + * @dst: Pointer to the destination buffer where to copy the string to. + * @src: Pointer to the source buffer where to copy the string from. + * @count: Size of the destination buffer, in UCS2 (16-bit) characters. + * + * Like strscpy(), only for UCS2 strings. + * + * Copy the source string @src, or as much of it as fits, into the destination + * buffer @dst. The behavior is undefined if the string buffers overlap. The + * destination buffer @dst is always NUL-terminated, unless it's zero-sized. + * + * Return: The number of characters copied into @dst (excluding the trailing + * %NUL terminator) or -E2BIG if @count is 0 or @src was truncated due to the + * destination buffer being too small. + */ +ssize_t ucs2_strscpy(ucs2_char_t *dst, const ucs2_char_t *src, size_t count) +{ + long res; + + /* + * Ensure that we have a valid amount of space. We need to store at + * least one NUL-character. + */ + if (count == 0 || WARN_ON_ONCE(count > INT_MAX / sizeof(*dst))) + return -E2BIG; + + /* + * Copy at most 'count' characters, return early if we find a + * NUL-terminator. + */ + for (res = 0; res < count; res++) { + ucs2_char_t c; + + c = src[res]; + dst[res] = c; + + if (!c) + return res; + } + + /* + * The loop above terminated without finding a NUL-terminator, + * exceeding the 'count': Enforce proper NUL-termination and return + * error. + */ + dst[count - 1] = 0; + return -E2BIG; +} +EXPORT_SYMBOL(ucs2_strscpy); + +int +ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len) +{ + while (1) { + if (len == 0) + return 0; + if (*a < *b) + return -1; + if (*a > *b) + return 1; + if (*a == 0) /* implies *b == 0 */ + return 0; + a++; + b++; + len--; + } +} +EXPORT_SYMBOL(ucs2_strncmp); + +unsigned long +ucs2_utf8size(const ucs2_char_t *src) +{ + unsigned long i; + unsigned long j = 0; + + for (i = 0; src[i]; i++) { + u16 c = src[i]; + + if (c >= 0x800) + j += 3; + else if (c >= 0x80) + j += 2; + else + j += 1; + } + + return j; +} +EXPORT_SYMBOL(ucs2_utf8size); + +/* + * copy at most maxlength bytes of whole utf8 characters to dest from the + * ucs2 string src. + * + * The return value is the number of characters copied, not including the + * final NUL character. + */ +unsigned long +ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, 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]; + + if (c >= 0x800) { + if (maxlength < 3) + break; + maxlength -= 3; + dest[j++] = 0xe0 | (c & 0xf000) >> 12; + dest[j++] = 0x80 | (c & 0x0fc0) >> 6; + dest[j++] = 0x80 | (c & 0x003f); + } else if (c >= 0x80) { + if (maxlength < 2) + break; + maxlength -= 2; + dest[j++] = 0xc0 | (c & 0x7c0) >> 6; + dest[j++] = 0x80 | (c & 0x03f); + } else { + maxlength -= 1; + dest[j++] = c & 0x7f; + } + } + if (maxlength) + dest[j] = '\0'; + return j; +} +EXPORT_SYMBOL(ucs2_as_utf8); + +MODULE_DESCRIPTION("UCS2 string handling"); +MODULE_LICENSE("GPL v2"); |
