BPF List
 help / color / mirror / Atom feed
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


  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