Commit b960430e authored by Yihan Ding's avatar Yihan Ding Committed by Alexei Starovoitov
Browse files

bpf: allow UTF-8 literals in bpf_bprintf_prepare()



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.

Update test_snprintf_negative() in the same commit so selftests keep
matching the new plain-text vs format-specifier split during bisection.

Fixes: 48cac3f4 ("bpf: Implement formatted output helpers with bstr_printf")
Signed-off-by: default avatarYihan Ding <dingyihan@uniontech.com>
Acked-by: default avatarPaul Chaignon <paul.chaignon@gmail.com>
Link: https://lore.kernel.org/r/20260416120142.1420646-2-dingyihan@uniontech.com


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 766bf026
Loading
Loading
Loading
Loading
+16 −1
Original line number Diff line number Diff line
@@ -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,15 @@ 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++;
		c = fmt[i];
		/*
		 * The format parser below only understands ASCII conversion
		 * specifiers and modifiers, so reject non-ASCII after '%'.
		 */
		if (!isascii(c)) {
			err = -EINVAL;
			goto out;
		}

		/* skip optional "[0 +-][num]" width formatting field */
		while (fmt[i] == '0' || fmt[i] == '+'  || fmt[i] == '-' ||
+2 −1
Original line number Diff line number Diff line
@@ -114,7 +114,8 @@ static void test_snprintf_negative(void)
	ASSERT_ERR(load_single_snprintf("%--------"), "invalid specifier 5");
	ASSERT_ERR(load_single_snprintf("%lc"), "invalid specifier 6");
	ASSERT_ERR(load_single_snprintf("%llc"), "invalid specifier 7");
	ASSERT_ERR(load_single_snprintf("\x80"), "non ascii character");
	ASSERT_OK(load_single_snprintf("\x80"), "non ascii plain text");
	ASSERT_ERR(load_single_snprintf("%\x80"), "non ascii in specifier");
	ASSERT_ERR(load_single_snprintf("\x1"), "non printable character");
	ASSERT_ERR(load_single_snprintf("%p%"), "invalid specifier 8");
	ASSERT_ERR(load_single_snprintf("%s%"), "invalid specifier 9");