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

From: Paul Chaignon

Date: Wed Apr 15 2026 - 06:46:22 EST


On Wed, Apr 15, 2026 at 11:21:25AM +0800, Yihan Ding wrote:
> 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>

I don't think this tag is appropriate here. If you want to give credit
for changes made after reviews, you can do so in the Changelogs of the
cover letter :)

> 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;
> + }

Acked-by: Paul Chaignon <paul.chaignon@xxxxxxxxx>

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