From: Yonghong Song <yonghong.song@linux.dev>
To: bpf@vger.kernel.org
Cc: Alexei Starovoitov <ast@kernel.org>,
Andrii Nakryiko <andrii@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Eduard Zingerman <eddyz87@gmail.com>,
kernel-team@fb.com
Subject: [PATCH bpf-next v2 09/11] selftests/bpf: Test trampolines on more BPF functions with stack args
Date: Mon, 12 Oct 2026 17:35:15 -0700 [thread overview]
Message-ID: <20261013003515.1860439-1-yonghong.song@linux.dev> (raw)
In-Reply-To: <20261013003429.1853052-1-yonghong.song@linux.dev>
Add two functions to the BPF target program of the int128_tgt_prog test.
callee_split() takes a struct holding an __int128 after five u64s, so
on x86-64 it is passed split between r9 and the stack. fentry and fexit
programs check that the trampoline takes it from there and hands it back
there.
callee_unreliable() takes six u64-sized arguments, the first a plain
pointer, which makes its BTF unreliable while the sixth is still passed
on the stack. The new tgt_prog_unreliable subtest checks that an fentry
program cannot be attached to it.
Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
---
.../selftests/bpf/prog_tests/tracing_struct.c | 62 +++++++++++++++++++
.../bpf/progs/tracing_struct_int128_tgt.c | 29 ++++++++-
.../bpf/progs/tracing_struct_int128_tracer.c | 26 ++++++++
3 files changed, 116 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/bpf/prog_tests/tracing_struct.c b/tools/testing/selftests/bpf/prog_tests/tracing_struct.c
index ad46eabe784f..e68fd5627ec1 100644
--- a/tools/testing/selftests/bpf/prog_tests/tracing_struct.c
+++ b/tools/testing/selftests/bpf/prog_tests/tracing_struct.c
@@ -194,9 +194,15 @@ static void test_int128_tgt_prog(void)
"callee_stack");
err = err ?: bpf_program__set_attach_target(tracer->progs.stack_exit, fd,
"callee_stack");
+ err = err ?: bpf_program__set_attach_target(tracer->progs.split_entry, fd,
+ "callee_split");
+ err = err ?: bpf_program__set_attach_target(tracer->progs.split_exit, fd,
+ "callee_split");
} else {
bpf_program__set_autoload(tracer->progs.stack_entry, false);
bpf_program__set_autoload(tracer->progs.stack_exit, false);
+ bpf_program__set_autoload(tracer->progs.split_entry, false);
+ bpf_program__set_autoload(tracer->progs.split_exit, false);
}
if (!ASSERT_OK(err, "set_attach_target"))
goto out;
@@ -226,6 +232,13 @@ static void test_int128_tgt_prog(void)
ASSERT_EQ(tracer->bss->stack_i, 10, "stack:i");
ASSERT_EQ(tgt->bss->ret_stack, 385, "stack ret");
ASSERT_EQ(tracer->bss->stack_ret, 385, "stack fexit ret");
+
+ ASSERT_EQ(tracer->bss->split_e, 5, "split:e");
+ ASSERT_EQ(tracer->bss->split_lo, 8, "split:h.lo");
+ ASSERT_EQ(tracer->bss->split_hi, 9, "split:h.hi");
+ ASSERT_EQ(tracer->bss->split_i, 10, "split:i");
+ ASSERT_EQ(tgt->bss->ret_split, 246, "split ret");
+ ASSERT_EQ(tracer->bss->split_ret, 246, "split fexit ret");
}
out:
@@ -241,6 +254,53 @@ static void test_int128_tgt_prog(void)
* call counter pointer on its stack, and has to hand the function its stack
* arguments past it.
*/
+/*
+ * A static function whose BTF is unreliable gets a trampoline that only knows
+ * of the register arguments, so one taking stack arguments must be refused.
+ */
+static void test_tgt_prog_unreliable(void)
+{
+#if defined(__x86_64__) || defined(__aarch64__)
+ struct tracing_struct_int128_tracer *tracer = NULL;
+ struct tracing_struct_int128_tgt *tgt;
+ char log_buf[4096] = {};
+ struct bpf_program *prog;
+ int err, fd;
+
+ tgt = tracing_struct_int128_tgt__open_and_load();
+ if (!ASSERT_OK_PTR(tgt, "tgt__open_and_load"))
+ return;
+ if (!tgt->rodata->has_stack_arg) {
+ test__skip();
+ goto out;
+ }
+ fd = bpf_program__fd(tgt->progs.run);
+
+ tracer = tracing_struct_int128_tracer__open();
+ if (!ASSERT_OK_PTR(tracer, "tracer__open"))
+ goto out;
+
+ bpf_object__for_each_program(prog, tracer->obj)
+ bpf_program__set_autoload(prog, false);
+ bpf_program__set_autoload(tracer->progs.unreliable_entry, true);
+ bpf_program__set_log_buf(tracer->progs.unreliable_entry, log_buf, sizeof(log_buf));
+ err = bpf_program__set_attach_target(tracer->progs.unreliable_entry, fd,
+ "callee_unreliable");
+ if (!ASSERT_OK(err, "set_attach_target"))
+ goto out;
+
+ err = tracing_struct_int128_tracer__load(tracer);
+ ASSERT_ERR(err, "tracer__load");
+ ASSERT_HAS_SUBSTR(log_buf, "unreliable BTF and stack arguments", "log");
+
+out:
+ tracing_struct_int128_tracer__destroy(tracer);
+ tracing_struct_int128_tgt__destroy(tgt);
+#else
+ test__skip();
+#endif
+}
+
static void test_stack_arg_tailcall(void)
{
#if defined(__x86_64__) || defined(__aarch64__)
@@ -328,6 +388,8 @@ void test_tracing_struct(void)
test_int128_args();
if (test__start_subtest("int128_tgt_prog"))
test_int128_tgt_prog();
+ if (test__start_subtest("tgt_prog_unreliable"))
+ test_tgt_prog_unreliable();
if (test__start_subtest("stack_arg_tailcall"))
test_stack_arg_tailcall();
if (test__start_subtest("union_args"))
diff --git a/tools/testing/selftests/bpf/progs/tracing_struct_int128_tgt.c b/tools/testing/selftests/bpf/progs/tracing_struct_int128_tgt.c
index 2ec8f741d48b..d1f9c3ccc99c 100644
--- a/tools/testing/selftests/bpf/progs/tracing_struct_int128_tgt.c
+++ b/tools/testing/selftests/bpf/progs/tracing_struct_int128_tgt.c
@@ -8,7 +8,7 @@ struct int128_arg {
};
__u64 base;
-__u64 ret_odd, ret_stack;
+__u64 ret_odd, ret_stack, ret_split, ret_unreliable;
#if defined(__clang__)
@@ -44,6 +44,25 @@ static __noinline __u64 callee_stack(__u64 a, __u64 b, __u64 c, __u64 d,
i * 10;
}
+/* BPF code splits h between the last argument register and the stack. */
+static __noinline __u64 callee_split(__u64 a, __u64 b, __u64 c, __u64 d,
+ __u64 e, struct int128_arg h, __u64 i)
+{
+ return a + b * 2 + c * 3 + d * 4 + e * 5 + (__u64)h.v * 6 +
+ (__u64)((unsigned __int128)h.v >> 64) * 7 + i * 8;
+}
+
+/*
+ * A plain pointer makes the BTF of a static function unreliable, but f is
+ * still passed on the stack. The store keeps p a pointer.
+ */
+static __noinline __u64 callee_unreliable(__u64 *p, __u64 b, __u64 c, __u64 d,
+ __u64 e, __u64 f)
+{
+ *p += 1;
+ return *p + b * 2 + c * 3 + d * 4 + e * 5 + f * 6;
+}
+
#else
const volatile bool has_stack_arg = false;
@@ -60,6 +79,14 @@ int run(void *ctx)
#if defined(__BPF_FEATURE_STACK_ARGUMENT)
ret_stack = callee_stack(base + 1, base + 2, base + 3, base + 4,
base + 5, base + 6, base + 7, v, base + 10);
+ ret_split = callee_split(base + 1, base + 2, base + 3, base + 4,
+ base + 5, v, base + 10);
+ {
+ __u64 x = base;
+
+ ret_unreliable = callee_unreliable(&x, base + 2, base + 3,
+ base + 4, base + 5, base + 6);
+ }
#endif
#endif
return 0;
diff --git a/tools/testing/selftests/bpf/progs/tracing_struct_int128_tracer.c b/tools/testing/selftests/bpf/progs/tracing_struct_int128_tracer.c
index 133f24fc9158..612d6f578ecb 100644
--- a/tools/testing/selftests/bpf/progs/tracing_struct_int128_tracer.c
+++ b/tools/testing/selftests/bpf/progs/tracing_struct_int128_tracer.c
@@ -41,4 +41,30 @@ int stack_exit(unsigned long long *ctx)
return 0;
}
+long split_e, split_lo, split_hi, split_i, split_ret;
+
+SEC("fentry/callee_split")
+int split_entry(unsigned long long *ctx)
+{
+ split_e = ctx[4];
+ split_lo = ctx[5];
+ split_hi = ctx[6];
+ split_i = ctx[7];
+ return 0;
+}
+
+SEC("fexit/callee_split")
+int split_exit(unsigned long long *ctx)
+{
+ split_ret = ctx[8];
+ return 0;
+}
+
+/* Refused: the trampoline would lose the stack argument. */
+SEC("?fentry/callee_unreliable")
+int unreliable_entry(unsigned long long *ctx)
+{
+ return 0;
+}
+
char _license[] SEC("license") = "GPL";
--
2.53.0-Meta
next prev parent reply other threads:[~2026-10-13 0:35 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-13 0:34 [PATCH bpf-next v2 00/11] bpf: Follow up by-value struct and __int128 argument support Yonghong Song
2026-10-13 0:34 ` [PATCH bpf-next v2 01/11] bpf, x86: Pass a trampoline's stack arguments by the calling convention Yonghong Song
2026-10-13 0:34 ` [PATCH bpf-next v2 02/11] selftests/bpf: Test trampoline stack args in a program that can tail call Yonghong Song
2026-10-13 0:34 ` [PATCH bpf-next v2 03/11] selftests/bpf: Test by-value __int128 kfunc arguments at an odd slot Yonghong Song
2026-10-13 0:34 ` [PATCH bpf-next v2 04/11] bpf: Describe a BPF function to its trampoline as one u64 per slot Yonghong Song
2026-10-13 0:34 ` [PATCH bpf-next v2 05/11] bpf, x86: Place trampoline arguments by the x86-64 calling convention Yonghong Song
2026-10-13 1:28 ` bot+bpf-ci
2026-10-13 0:34 ` [PATCH bpf-next v2 06/11] selftests/bpf: Test trampoline args around a 16-byte aligned stack arg Yonghong Song
2026-10-13 0:43 ` sashiko-bot
2026-10-13 14:07 ` Yonghong Song
2026-10-13 0:35 ` [PATCH bpf-next v2 07/11] selftests/bpf: Test trampoline args of a BPF function at an odd slot Yonghong Song
2026-10-13 0:35 ` [PATCH bpf-next v2 08/11] bpf: Refuse a trampoline on an unreliable static function with stack args Yonghong Song
2026-10-13 0:35 ` Yonghong Song [this message]
2026-10-13 0:51 ` [PATCH bpf-next v2 09/11] selftests/bpf: Test trampolines on more BPF functions " sashiko-bot
2026-10-13 14:25 ` Yonghong Song
2026-10-13 1:28 ` bot+bpf-ci
2026-10-13 14:31 ` Yonghong Song
2026-10-13 0:35 ` [PATCH bpf-next v2 10/11] bpf, x86: Pass a kfunc's 16-byte aligned stack argument 16-byte aligned Yonghong Song
2026-10-13 0:35 ` [PATCH bpf-next v2 11/11] selftests/bpf: Test that a kfunc gets a 16-byte aligned __int128 aligned 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=20261013003515.1860439-1-yonghong.song@linux.dev \
--to=yonghong.song@linux.dev \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=kernel-team@fb.com \
/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