From: Yonghong Song <yonghong.song@linux.dev>
To: bot+bpf-ci@kernel.org, bpf@vger.kernel.org
Cc: ast@kernel.org, andrii@kernel.org, daniel@iogearbox.net,
eddyz87@gmail.com, kernel-team@fb.com, martin.lau@kernel.org,
clm@meta.com, ihor.solodrai@linux.dev
Subject: Re: [PATCH bpf-next v4 09/13] bpf: Enable aggregate return types up to 16 bytes
Date: Wed, 12 Aug 2026 13:29:41 -0700 [thread overview]
Message-ID: <cf7fe702-6f29-4137-a589-39974d5fca88@linux.dev> (raw)
In-Reply-To: <e9d300a2448796c238e4f3b84d45e7abdbb5fcda4f4912fd3361437836bcd27d@mail.kernel.org>
On 8/10/26 6:24 PM, bot+bpf-ci@kernel.org wrote:
>> 8 bytes, R0 alone for <=8 bytes), enabling the R0:R2 register-pair return
> convention end-to-end.
>
>> diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
>> index 6606187ed4f43..5551abcea1d39 100644
>> --- a/kernel/bpf/btf.c
>> +++ b/kernel/bpf/btf.c
> [ ... ]
>
>> @@ -7965,7 +7970,7 @@ static int btf_scan_type_tags(struct bpf_verifier_env *env,
>>
>> /* Check whether the type is a valid return type. */
>> static int btf_validate_return_type(struct bpf_verifier_env *env, struct btf *btf,
>> - const struct btf_type *t, int subprog)
>> + const struct btf_type *t, int subprog, bool is_global)
>> {
>> u32 tags = 0;
>> int err;
>> @@ -7988,6 +7993,35 @@ static int btf_validate_return_type(struct bpf_verifier_env *env, struct btf *bt
>> if (btf_type_is_void(t) || btf_type_is_int(t) || btf_is_any_enum(t))
>> return 0;
>>
>> + if (btf_type_is_struct(t) && t->size <= 16) {
>> + /*
>> + * A >8 byte struct/union is returned in the R0:R2 register pair.
>> + * A global function is verified in isolation, so its caller models
>> + * the return as an opaque R0:R2 scalar pair; it must therefore
>> + * contain only scalars, otherwise a pointer field would be
>> + * laundered into a scalar and escape provenance and reference
>> + * tracking. That requirement is enforced here: do_check_common()
>> + * propagates the error for global functions and for the main
>> + * program.
>> + *
>> + * A local (static) function is verified inline and its R0:R2 are
>> + * copied as precise register state (with the JIT forced on when
>> + * the pair is consumed), so a pointer field stays tracked and needs
>> + * no such restriction. Accepting it here is not by itself what
>> + * makes it legal: btf_check_subprog_call() drops any error other
>> + * than -EFAULT. What it avoids is needlessly marking the
>> + * subprogram's BTF unreliable.
>> + *
>> + * The main program (subprog 0) takes the scalar-only path as well,
>> + * but its return value is the program's exit code, so a >8 byte
>> + * return is rejected separately at BPF_EXIT.
>> + */
>> + bool local_func = subprog && !is_global;
>> +
>> + if (local_func || __btf_type_is_scalar_struct(env, btf, t, 0))
>> + return 0;
>> + }
>> +
>> return -EOPNOTSUPP;
>> }
> Does the comment accurately describe the enforcement mechanism?
>
> The comment states "do_check_common() propagates the error for global
> functions and for the main program." That's true for global functions but
> appears incorrect for the main program. Looking at do_check_common() in
> kernel/bpf/verifier.c:18624:
>
> if (subprog || env->prog->type == BPF_PROG_TYPE_EXT) {
> ...
> ret = btf_prepare_func_args(env, subprog);
> if (ret)
> goto out; /* <- error propagated */
> } else {
> if (env->prog->aux->func_info_aux) {
> ret = btf_prepare_func_args(env, 0);
> if (ret || sub->arg_cnt != 1 || ...) {
> env->prog->aux->func_info_aux[0].unreliable = true;
> ...
> }
> }
> ...
> }
> ret = do_check(env);
>
> The main-program arm (subprog 0 of a non-EXT program) uses the return
> value only to set func_info_aux[0].unreliable, then unconditionally
> overwrites ret with do_check(env). The -EOPNOTSUPP from
> btf_validate_return_type() is therefore discarded.
>
> Concretely: a program whose entry function returns a pointer-containing
> struct like 'struct { void *p; }' (size 8) now takes the new struct
> branch, fails __btf_type_is_scalar_struct(), but the resulting error is
> silently dropped. The program continues to be verified.
>
> No memory-safety hole results: check_return_code() still refuses a pointer
> in R0 at exit ('R0 leaks addr as return value'), so the pointer-laundering
> scenario the comment worries about does not actually occur for the main
> program. The issue is that the comment states an enforcement mechanism that
> does not exist.
>
> Should the comment drop "and for the main program" and point at the
> BPF_EXIT check instead?
Yes, will do.
>
> Also: "btf_check_subprog_call() drops any error other than -EFAULT" is
> slightly inaccurate. btf_check_subprog_call() actually returns the error
> and marks the BTF unreliable; its callers, check_func_call() and
> push_callback_call(), do 'if (err == -EFAULT) return err;' and otherwise
> continue.
>
>
> ---
> AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
> See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
>
> CI run summary: https://github.com/kernel-patches/bpf/actions/runs/31446101762
next prev parent reply other threads:[~2026-08-12 20:29 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-11 0:09 [PATCH bpf-next v4 00/13] bpf: Support aggregate return values up to 16 bytes Yonghong Song
2026-08-11 0:09 ` [PATCH bpf-next v4 01/13] bpf: Factor check_global_ret_scalar_reg() out of the global return check Yonghong Song
2026-08-11 0:09 ` [PATCH bpf-next v4 02/13] bpf: Add helpers to describe the R0:R2 return register pair Yonghong Song
2026-08-11 1:24 ` bot+bpf-ci
2026-08-12 19:31 ` Yonghong Song
2026-08-12 20:07 ` Eduard Zingerman
2026-08-11 0:09 ` [PATCH bpf-next v4 03/13] bpf: Wire up JIT support for 16-byte kfunc returns Yonghong Song
2026-08-11 1:24 ` bot+bpf-ci
2026-08-12 19:48 ` Yonghong Song
2026-08-12 20:42 ` Eduard Zingerman
2026-08-11 0:09 ` [PATCH bpf-next v4 04/13] bpf: Track R2 of register-pair returns in precision backtracking Yonghong Song
2026-08-12 21:16 ` Eduard Zingerman
2026-08-11 0:09 ` [PATCH bpf-next v4 05/13] bpf: Account R2 of register-pair returns in live register analysis Yonghong Song
2026-08-11 1:09 ` bot+bpf-ci
2026-08-12 19:55 ` Yonghong Song
2026-08-12 21:21 ` Eduard Zingerman
2026-08-11 0:09 ` [PATCH bpf-next v4 06/13] bpf: Reject callbacks returning more than 8 bytes Yonghong Song
2026-08-12 21:41 ` Eduard Zingerman
2026-08-11 0:09 ` [PATCH bpf-next v4 07/13] bpf: Add verifier support for 16-byte returns in R0:R2 Yonghong Song
2026-08-11 1:24 ` bot+bpf-ci
2026-08-12 20:12 ` Yonghong Song
2026-08-12 22:12 ` Eduard Zingerman
2026-08-11 0:09 ` [PATCH bpf-next v4 08/13] bpf: Reject register-pair returns when the subprog BTF is unreliable Yonghong Song
2026-08-11 1:24 ` bot+bpf-ci
2026-08-12 20:26 ` Yonghong Song
2026-08-12 22:24 ` Eduard Zingerman
2026-08-11 0:09 ` [PATCH bpf-next v4 09/13] bpf: Enable aggregate return types up to 16 bytes Yonghong Song
2026-08-11 1:24 ` bot+bpf-ci
2026-08-12 20:29 ` Yonghong Song [this message]
2026-08-11 0:10 ` [PATCH bpf-next v4 10/13] selftests/bpf: Add C tests for 16-byte returns in R0:R2 Yonghong Song
2026-08-11 1:24 ` bot+bpf-ci
2026-08-12 20:49 ` Yonghong Song
2026-08-11 0:10 ` [PATCH bpf-next v4 11/13] selftests/bpf: Add inline-asm and subprog tests for R0:R2 returns Yonghong Song
2026-08-11 1:24 ` bot+bpf-ci
2026-08-12 21:08 ` Yonghong Song
2026-08-11 0:10 ` [PATCH bpf-next v4 12/13] selftests/bpf: Add tests for callbacks returning more than 8 bytes Yonghong Song
2026-08-11 1:24 ` bot+bpf-ci
2026-08-12 21:22 ` Yonghong Song
2026-08-11 0:10 ` [PATCH bpf-next v4 13/13] Documentation/bpf: Document up to 16-byte kfunc return values in R0:R2 Yonghong Song
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=cf7fe702-6f29-4137-a589-39974d5fca88@linux.dev \
--to=yonghong.song@linux.dev \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bot+bpf-ci@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=clm@meta.com \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=ihor.solodrai@linux.dev \
--cc=kernel-team@fb.com \
--cc=martin.lau@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox