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 12/13] selftests/bpf: Add tests for callbacks returning more than 8 bytes
Date: Wed, 12 Aug 2026 14:22:11 -0700	[thread overview]
Message-ID: <1632b28d-00bd-4e22-a379-aa990a06d7fb@linux.dev> (raw)
In-Reply-To: <1401ba2c0512cfb3069383693bc55e1f977ad9bbf07dd9cca7e266bf517c571f@mail.kernel.org>



On 8/10/26 6:24 PM, bot+bpf-ci@kernel.org wrote:
>> selftests/bpf: Add tests for callbacks returning more than 8 bytes
>>
>> Add two __failure tests covering the callback return-size checks:
>>
>>   - timer_ret_pair_fail: a bpf_timer callback declared to return more than
>>     8 bytes, rejected by check_ld_imm() where the callback's PTR_TO_FUNC is
>>     created, with "callback function with >8-byte return value is not
>>     supported".
>>
>>   - exceptions_ret_pair_fail: an exception callback declared to return more
>>     than 8 bytes, rejected by do_check_common() when the callback
>>     subprogram is verified, with "exception cb cannot return value larger
>>     than 8 bytes".
>>
>> Both callback bodies are written in inline asm so that the tests do not
>> depend on LLVM 23 R0:R2 codegen and run on any compiler. The verifier reads
>> the return type from BTF rather than from the instructions, so the >8 byte
>> return prototype is supplied through __btf_func_path(), pointing at a
>> companion btf__*.c program that exists only to carry that BTF.
> Does __btf_func_path() actually supply the return type? Looking at
> fixup_btf_from_path() in tools/testing/selftests/bpf/test_loader.c, it
> appears to keep the prog's return type and parameter types while
> substituting only parameter names:
>
>    ret_type_id = fp->type;                    /* fp is the prog FUNC_PROTO */
>    for (j = 0; j < vlen; j++)
>        prog_param_types[j] = params[j].type;  /* prog param types */
>    new_proto_id = btf__add_func_proto(prog_btf, ret_type_id);
>    ...
>    pname = btf__name_by_offset(custom_btf, custom_params[j].name_off);
>    err = btf__add_func_param(prog_btf, pname ?: "", prog_param_types[j]);
>
> The comment at the call site says "Fix up __naked subprog BTF using a
> separate file with named params", and the >8 byte return type already
> comes from each test object's own BTF: exceptions_ret_pair_fail.c
> declares 'unsigned __int128 exception_cb_bad_ret_type3(u64 cookie)' and
> timer_ret_pair_fail.c declares 'static unsigned __int128
> timer_cb_ret_pair(...)'.
>
> The companion btf__*.c objects supply parameter names, which are needed
> because clang emits anonymous parameters for __naked functions and
> btf_func_check() in kernel/bpf/btf.c rejects a BTF_KIND_FUNC whose
> FUNC_PROTO has a typed-but-unnamed argument, which would make the whole
> object's BTF fail to load.
>
> Could the explanation be more precise about what __btf_func_path()
> actually provides?

__btf_func_path() provides precise function BTF which won't be
available for inline asm code.

>
>> Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
>> diff --git a/tools/testing/selftests/bpf/prog_tests/exceptions.c b/tools/testing/selftests/bpf/prog_tests/exceptions.c
>> index 3588d6f97fd4e..71d00c568d802 100644
>> --- a/tools/testing/selftests/bpf/prog_tests/exceptions.c
>> +++ b/tools/testing/selftests/bpf/prog_tests/exceptions.c
>> @@ -5,6 +5,7 @@
>>   #include "exceptions.skel.h"
>>   #include "exceptions_ext.skel.h"
>>   #include "exceptions_fail.skel.h"
>> +#include "exceptions_ret_pair_fail.skel.h"
>>   #include "exceptions_assert.skel.h"
>>
>>   static char log_buf[1024 * 1024];
>> @@ -12,6 +13,7 @@ static char log_buf[1024 * 1024];
>>   static void test_exceptions_failure(void)
>>   {
>>   	RUN_TESTS(exceptions_fail);
>> +	RUN_TESTS(exceptions_ret_pair_fail);
>>   }
>>
>>   static void test_exceptions_success(void)
>> diff --git a/tools/testing/selftests/bpf/prog_tests/timer.c b/tools/testing/selftests/bpf/prog_tests/timer.c
>> index 09ff21e1ad2f0..593e56d8964ea 100644
>> --- a/tools/testing/selftests/bpf/prog_tests/timer.c
>> +++ b/tools/testing/selftests/bpf/prog_tests/timer.c
>> @@ -6,6 +6,7 @@
>>   #include <sys/syscall.h>
>>   #include "timer.skel.h"
>>   #include "timer_failure.skel.h"
>> +#include "timer_ret_pair_fail.skel.h"
>>   #include "timer_interrupt.skel.h"
>>
>>   #define NUM_THR 8
>> @@ -285,6 +286,7 @@ void serial_test_timer(void)
>>   	test_timer(timer);
>>
>>   	RUN_TESTS(timer_failure);
>> +	RUN_TESTS(timer_ret_pair_fail);
>>   }
>>
>>   void serial_test_timer_stress(void)
> [ ... ]
>
>> diff --git a/tools/testing/selftests/bpf/progs/exceptions_ret_pair_fail.c b/tools/testing/selftests/bpf/progs/exceptions_ret_pair_fail.c
>> new file mode 100644
>> index 0000000000000..842f86ad8659e
>> --- /dev/null
>> +++ b/tools/testing/selftests/bpf/progs/exceptions_ret_pair_fail.c
>> @@ -0,0 +1,30 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
>> +#include <vmlinux.h>
>> +#include <bpf/bpf_tracing.h>
>> +#include <bpf/bpf_helpers.h>
>> +
>> +#include "bpf_misc.h"
>> +#include "bpf_experimental.h"
>> +
>> +__naked __noinline __used
>> +unsigned __int128 exception_cb_bad_ret_type3(u64 cookie)
>> +{
>> +	asm volatile (
>> +	"r0 = r1;"
>> +	"r2 = 0;"
>> +	"exit;"
>> +	::: __clobber_all);
>> +}
>> +
>> +SEC("?tc")
>> +__exception_cb(exception_cb_bad_ret_type3)
>> +__failure __msg("exception cb cannot return value larger than 8 bytes")
>> +__btf_func_path("btf__exceptions_ret_pair_fail.bpf.o")
>> +int reject_exception_cb_ret_pair(void *ctx)
>> +{
>> +	bpf_throw(0);
>> +	return 0;
>> +}
>> +
>> +char _license[] SEC("license") = "GPL";
> A subsystem pattern flags this as potentially concerning:
> exceptions_ret_pair_fail.c is a new prog file added for one narrow
> variant of behaviour tools/testing/selftests/bpf/progs/exceptions_fail.c
> already covers: rejected exception-callback return types.
>
> exceptions_fail.c already holds exception_cb_bad_ret_type1(),
> exception_cb_bad_ret_type2() and the corresponding '__failure
> __msg("exception cb cannot return void")' case. The new callback is even
> named exception_cb_bad_ret_type3, continuing that file's numbering while
> living in a different file, so a reader grepping exceptions_fail.c for
> the series will not find it next to its siblings.
>
> There is a concrete technical reason the exceptions case cannot simply
> be appended to exceptions_fail.c: __btf_func_path also sets
> bpf_object_open_opts.btf_custom_path, and libbpf uses that as the CO-RE
> target BTF for the whole object. exceptions_fail.c includes <vmlinux.h>,
> which applies preserve_access_index to all records, and it dereferences
> vmlinux structs (ctx->len, ctx->protocol, ctx->tstamp), so it does have
> CO-RE relocations that would then be resolved against the 10-line
> companion BTF. That makes the split legitimate here; the remaining point
> is only that the shared naming (exception_cb_bad_ret_type3) does not
> reflect the split.
>
> Is the naming pattern worth revisiting given that the test lives in a
> separate file?

Right, the prog itself is in a dedicated file. But user space part
is in prog_tests/exceptions.c.

>
>> diff --git a/tools/testing/selftests/bpf/progs/timer_ret_pair_fail.c b/tools/testing/selftests/bpf/progs/timer_ret_pair_fail.c
>> new file mode 100644
>> index 0000000000000..29fd294dfd49b
>> --- /dev/null
>> +++ b/tools/testing/selftests/bpf/progs/timer_ret_pair_fail.c
>> @@ -0,0 +1,49 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
>> +
>> +#include <linux/bpf.h>
>> +#include <time.h>
>> +#include <bpf/bpf_helpers.h>
>> +#include <bpf/bpf_tracing.h>
>> +#include "bpf_misc.h"
>> +
>> +char _license[] SEC("license") = "GPL";
>> +
>> +struct elem {
>> +	struct bpf_timer t;
>> +};
>> +
>> +struct {
>> +	__uint(type, BPF_MAP_TYPE_ARRAY);
>> +	__uint(max_entries, 1);
>> +	__type(key, int);
>> +	__type(value, struct elem);
>> +} timer_map SEC(".maps");
>> +
>> +__naked __noinline __used
>> +static unsigned __int128 timer_cb_ret_pair(void *map, int *key, struct bpf_timer *timer)
>> +{
>> +	asm volatile (
>> +		"r0 = 0;"
>> +		"r2 = 0;"
>> +		"exit;"
>> +		::: __clobber_all
>> +	);
>> +}
>> +
>> +SEC("fentry/bpf_fentry_test1")
>> +__failure __msg("callback function with >8-byte return value is not supported")
>> +__btf_func_path("btf__timer_ret_pair_fail.bpf.o")
>> +long BPF_PROG2(test_bad_ret_pair, int, a)
>> +{
>> +	int key = 0;
>> +	struct bpf_timer *timer;
>> +
>> +	timer = bpf_map_lookup_elem(&timer_map, &key);
>> +	if (timer) {
>> +		bpf_timer_init(timer, &timer_map, CLOCK_BOOTTIME);
>> +		bpf_timer_set_callback(timer, timer_cb_ret_pair);
>> +	}
>> +
>> +	return 0;
>> +}
> A subsystem pattern flags this as potentially concerning:
> timer_ret_pair_fail.c is a new prog file added for one narrow variant (a
> callback whose declared return value is larger than 8 bytes) of
> behaviour that tools/testing/selftests/bpf/progs/timer_failure.c already
> covers more generally: bad bpf_timer callback return values.
>
> The two files are near-identical scaffolding - the same '#include
> <linux/bpf.h> / <time.h> / bpf_helpers.h / bpf_tracing.h / bpf_misc.h'
> set, the same 'struct elem { struct bpf_timer t; }', the same
> BPF_MAP_TYPE_ARRAY 'timer_map' with max_entries 1, the same
> SEC("fentry/bpf_fentry_test1") + BPF_PROG2 entry program, and the same
> '__naked __noinline __used static' callback idiom already used by
> timer_cb_ret_bad().
>
> The new program adds ~10 lines of actual test content on top of ~35
> lines of copied setup, plus a new skeleton, plus a companion
> btf__timer_ret_pair_fail.c, plus the RUN_TESTS()/#include churn in
> prog_tests/timer.c. Adding it as a third program inside timer_failure.c
> would reuse all of that. Since __btf_func_path is a per-program tag
> consumed per-subtest in run_subtest(), and timer_failure.c has no CO-RE
> relocations (it includes uapi <linux/bpf.h>, not <vmlinux.h>), the
> btf_custom_path side effect of the tag would not affect the existing
> subtests in that object.
>
> A separate file is defensible for symmetry with the exceptions half of
> the patch, where a separate file IS required due to CO-RE relocations.
> Should the new timer case be a new subtest in timer_failure.c, or does
> the symmetry with exceptions_ret_pair_fail.c make the separate file
> structure clearer?

In this case, the prog is in timer_failure.c for failure testing.

>
>
> ---
> 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 21:22 UTC|newest]

Thread overview: 44+ 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
2026-08-12 22:47   ` Eduard Zingerman
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-12 23:15   ` Eduard Zingerman
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-12 23:29       ` Eduard Zingerman
2026-08-13  0:09   ` Eduard Zingerman
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 [this message]
2026-08-13  0:10   ` Eduard Zingerman
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=1632b28d-00bd-4e22-a379-aa990a06d7fb@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