All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.