From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from 66-220-155-179.mail-mxout.facebook.com (66-220-155-179.mail-mxout.facebook.com [66.220.155.179]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 60097521892 for ; Tue, 13 Oct 2026 17:10:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=66.220.155.179 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791911444; cv=none; b=BTctFB/q5n+ympF5EozLzKo31S5mFQyDKgbaopBRWxTImb09ChtGuxJ9gm60YUTg15aELRNMBIyqNwpiwi/telp5b+2VKAvR19vhvkrwZowbbLIlVVF9mK1a5zDKwUSvZJWIhz2XoBb0BBIXqDJI0It7wlRpxgV3hz/NQ1X2JT8= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791911444; c=relaxed/simple; bh=Ubtx9GiB4223MFnp+EJecJAlX383G8Rry+mKp0vxDuA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Ll7QB18K3kb/G+RKklcjdqHNIez1+1Oxwd23qua2KzVhG2y/tqfHblI8iuKiJmXUFfsXWTYyaFV+jRNrbp5UFe/vrSFj1mdh1BYBS/nZLa9kBstaOeIHeWzM/eJrUHv9Xbx6wMqzn6rYQS2aWa3Y71S76tHxZI9lGby0zm9tYaQ= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.dev; spf=fail smtp.mailfrom=linux.dev; arc=none smtp.client-ip=66.220.155.179 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=linux.dev Received: by devvm16039.vll0.facebook.com (Postfix, from userid 128203) id 2FEF730FB5C65E; Tue, 13 Oct 2026 10:10:29 -0700 (PDT) From: Yonghong Song To: bpf@vger.kernel.org Cc: Alexei Starovoitov , Andrii Nakryiko , Daniel Borkmann , Eduard Zingerman , kernel-team@fb.com Subject: [PATCH bpf-next v3 09/11] selftests/bpf: Test trampolines on more BPF functions with stack args Date: Tue, 13 Oct 2026 10:10:29 -0700 Message-ID: <20261013171029.2137070-1-yonghong.song@linux.dev> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20261013170910.2126673-1-yonghong.song@linux.dev> References: <20261013170910.2126673-1-yonghong.song@linux.dev> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable 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 --- .../selftests/bpf/prog_tests/tracing_struct.c | 62 +++++++++++++++++++ .../bpf/progs/tracing_struct_int128_tgt.c | 32 +++++++++- .../bpf/progs/tracing_struct_int128_tracer.c | 26 ++++++++ 3 files changed, 119 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/prog_tests/tracing_struct.c b/to= ols/testing/selftests/bpf/prog_tests/tracing_struct.c index ad46eabe784f..4b874ef5e6ba 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 =3D err ?: bpf_program__set_attach_target(tracer->progs.stack_exit= , fd, "callee_stack"); + err =3D err ?: bpf_program__set_attach_target(tracer->progs.split_entr= y, fd, + "callee_split"); + err =3D 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"); } =20 out: @@ -236,6 +249,53 @@ static void test_int128_tgt_prog(void) #endif } =20 +/* + * A static function whose BTF is unreliable gets a trampoline that only= knows + * of the register arguments, so one taking stack arguments must be refu= sed. + */ +static void test_tgt_prog_unreliable(void) +{ +#if defined(__x86_64__) || defined(__aarch64__) + struct tracing_struct_int128_tracer *tracer =3D NULL; + struct tracing_struct_int128_tgt *tgt; + char log_buf[4096] =3D {}; + struct bpf_program *prog; + int err, fd; + + tgt =3D 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 =3D bpf_program__fd(tgt->progs.run); + + tracer =3D 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, sizeo= f(log_buf)); + err =3D bpf_program__set_attach_target(tracer->progs.unreliable_entry, = fd, + "callee_unreliable"); + if (!ASSERT_OK(err, "set_attach_target")) + goto out; + + err =3D 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 +} + /* * A trampoline on a function of a tail_call_reachable program keeps the= tail * call counter pointer on its stack, and has to hand the function its s= tack @@ -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..8c24f5841bf2 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 { }; =20 __u64 base; -__u64 ret_odd, ret_stack; +__u64 ret_odd, ret_stack, ret_split, ret_unreliable; =20 #if defined(__clang__) =20 @@ -44,6 +44,28 @@ static __noinline __u64 callee_stack(__u64 a, __u64 b,= __u64 c, __u64 d, i * 10; } =20 +/* + * x86-64 BPF code passes h split between r9 and its first stack slot; + * arm64 passes it in x5 and x6, so nothing is split there. + */ +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 +=3D 1; + return *p + b * 2 + c * 3 + d * 4 + e * 5 + f * 6; +} + #else =20 const volatile bool has_stack_arg =3D false; @@ -60,6 +82,14 @@ int run(void *ctx) #if defined(__BPF_FEATURE_STACK_ARGUMENT) ret_stack =3D callee_stack(base + 1, base + 2, base + 3, base + 4, base + 5, base + 6, base + 7, v, base + 10); + ret_split =3D callee_split(base + 1, base + 2, base + 3, base + 4, + base + 5, v, base + 10); + { + __u64 x =3D base; + + ret_unreliable =3D 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_trac= er.c b/tools/testing/selftests/bpf/progs/tracing_struct_int128_tracer.c index e631b6f2378f..fb6172ef2b29 100644 --- a/tools/testing/selftests/bpf/progs/tracing_struct_int128_tracer.c +++ b/tools/testing/selftests/bpf/progs/tracing_struct_int128_tracer.c @@ -53,4 +53,30 @@ int stack_exit(unsigned long long *ctx) return 0; } =20 +long split_e, split_lo, split_hi, split_i, split_ret; + +SEC("fentry/callee_split") +int split_entry(unsigned long long *ctx) +{ + split_e =3D ctx[4]; + split_lo =3D ctx[5 + LO]; + split_hi =3D ctx[5 + HI]; + split_i =3D ctx[7]; + return 0; +} + +SEC("fexit/callee_split") +int split_exit(unsigned long long *ctx) +{ + split_ret =3D 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") =3D "GPL"; --=20 2.53.0-Meta