[PATCH bpf v2 1/2] bpf: allow UTF-8 literals in bpf_bprintf_prepare()

From: Yihan Ding

Date: Tue Apr 14 2026 - 23:22:45 EST


bpf_bprintf_prepare() only needs ASCII parsing for conversion
specifiers. Plain text can safely carry bytes >= 0x80, so allow
UTF-8 literals outside '%' sequences while keeping ASCII control
bytes rejected and format specifiers ASCII-only.

This keeps existing parsing rules for format directives unchanged,
while allowing helpers such as bpf_trace_printk() to emit UTF-8
literal text.

Fixes: 48cac3f4a96d ("bpf: Implement formatted output helpers with bstr_printf")
Suggested-by: Paul Chaignon <paul.chaignon@xxxxxxxxx>
Signed-off-by: Yihan Ding <dingyihan@xxxxxxxxxxxxx>
---
kernel/bpf/helpers.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index 6eb6c82ed2ee..6319b39c92f9 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -845,7 +845,13 @@ int bpf_bprintf_prepare(const char *fmt, u32 fmt_size, const u64 *raw_args,
data->buf = buffers->buf;

for (i = 0; i < fmt_size; i++) {
- if ((!isprint(fmt[i]) && !isspace(fmt[i])) || !isascii(fmt[i])) {
+ unsigned char c = fmt[i];
+
+ /*
+ * Permit bytes >= 0x80 in plain text so UTF-8 literals can pass
+ * through unchanged, while still rejecting ASCII control bytes.
+ */
+ if (isascii(c) && !isprint(c) && !isspace(c)) {
err = -EINVAL;
goto out;
}
@@ -867,6 +873,14 @@ int bpf_bprintf_prepare(const char *fmt, u32 fmt_size, const u64 *raw_args,
* always access fmt[i + 1], in the worst case it will be a 0
*/
i++;
+ /*
+ * The format parser below only understands ASCII conversion
+ * specifiers and modifiers, so reject non-ASCII after '%'.
+ */
+ if (!isascii((unsigned char)fmt[i])) {
+ err = -EINVAL;
+ goto out;
+ }

/* skip optional "[0 +-][num]" width formatting field */
while (fmt[i] == '0' || fmt[i] == '+' || fmt[i] == '-' ||
--
2.20.1