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, Leon Hwang <leon.hwang@linux.dev>
Subject: [PATCH bpf-next v3 1/3] bpf: Reject >8 byte return values on return-reading trampoline paths
Date: Fri, 10 Jul 2026 15:52:11 -0700 [thread overview]
Message-ID: <20260710225211.4013521-1-yonghong.song@linux.dev> (raw)
In-Reply-To: <20260710225206.4013062-1-yonghong.song@linux.dev>
btf_distill_func_proto() builds the function model used for the
fentry/fexit/fmod_ret/fsession trampolines and struct_ops. It has
accepted a 16-byte __int128 return value since the trampoline was
introduced: __get_type_size() returns the integer's type size, and the
return-type check only rejected ret < 0.
But the BPF trampoline preserves only 8 bytes of the return value (RAX on
x86, i.e. R0). For an attach type that reads the target's return value the
second half (RDX / R3) is neither saved nor restored, so a program
attached to a function returning a 16-byte value corrupts the value seen
by the real caller and itself observes only half of it. struct_ops
trampolines have the same limitation.
This affects the attach types that read the target's return value: fexit,
fmod_ret and fsession (plus the _multi variants of fexit and fsession),
and struct_ops. fentry/fentry_multi run before the target returns and are
unaffected.
Reject a >8 byte return value for these attach types in
bpf_check_attach_target() and bpf_check_attach_btf_id_multi(), and for
struct_ops in bpf_struct_ops_desc_init().
Fixes: fec56f5890d9 ("bpf: Introduce BPF trampoline")
Cc: Leon Hwang <leon.hwang@linux.dev>
Reviewed-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
---
kernel/bpf/bpf_struct_ops.c | 12 ++++++++++++
kernel/bpf/verifier.c | 25 +++++++++++++++++++++++++
2 files changed, 37 insertions(+)
diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c
index 51b16e5f5534..4e7a48c02be5 100644
--- a/kernel/bpf/bpf_struct_ops.c
+++ b/kernel/bpf/bpf_struct_ops.c
@@ -445,6 +445,18 @@ int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
goto errout;
}
+ /*
+ * A >8 byte return value is passed back in a register pair,
+ * which the struct_ops trampoline does not preserve (only
+ * 8 bytes of the return value are saved and restored).
+ */
+ if (st_ops->func_models[i].ret_size > 8) {
+ pr_warn("func ptr %s in struct %s has a >8 byte return value, which is not supported\n",
+ mname, st_ops->name);
+ err = -EOPNOTSUPP;
+ goto errout;
+ }
+
stub_func_addr = *(void **)(st_ops->cfi_stubs + moff);
err = prepare_arg_info(btf, st_ops->name, mname,
func_proto, stub_func_addr,
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 6515d4d3c003..26d281b77a6e 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -18873,6 +18873,20 @@ static int btf_id_allow_sleepable(u32 btf_id, unsigned long addr, const struct b
return -EINVAL;
}
+static bool attach_uses_trampoline_retval(enum bpf_attach_type type)
+{
+ switch (type) {
+ case BPF_MODIFY_RETURN:
+ case BPF_TRACE_FEXIT:
+ case BPF_TRACE_FEXIT_MULTI:
+ case BPF_TRACE_FSESSION:
+ case BPF_TRACE_FSESSION_MULTI:
+ return true;
+ default:
+ return false;
+ }
+}
+
int bpf_check_attach_target(struct bpf_verifier_log *log,
const struct bpf_prog *prog,
const struct bpf_prog *tgt_prog,
@@ -19137,6 +19151,14 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
if (ret < 0)
return ret;
+ if (tgt_info->fmodel.ret_size > 8 &&
+ attach_uses_trampoline_retval(prog->expected_attach_type)) {
+ bpf_log(log,
+ "Attach to function %s with a >8 byte return value is not supported for this attach type\n",
+ tname);
+ return -EOPNOTSUPP;
+ }
+
/*
* *.multi programs don't need an address during program
* verification, we just take the module ref if needed.
@@ -19413,6 +19435,9 @@ int bpf_check_attach_btf_id_multi(struct btf *btf, struct bpf_prog *prog, u32 bt
err = btf_distill_func_proto(NULL, btf, t, tname, &tgt_info->fmodel);
if (err < 0)
return err;
+ if (tgt_info->fmodel.ret_size > 8 &&
+ attach_uses_trampoline_retval(prog->expected_attach_type))
+ return -EOPNOTSUPP;
if (btf_is_module(btf)) {
/* The bpf program already holds reference to module. */
if (WARN_ON_ONCE(!prog->aux->mod))
--
2.53.0-Meta
next prev parent reply other threads:[~2026-07-10 22:52 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-10 22:52 [PATCH bpf-next v3 0/3] bpf: Fix trampoline handling of 128-bit values Yonghong Song
2026-07-10 22:52 ` Yonghong Song [this message]
2026-07-10 22:52 ` [PATCH bpf-next v3 2/3] bpf, x86: Fix trampoline stack size for 128-bit arguments Yonghong Song
2026-07-10 22:52 ` [PATCH bpf-next v3 3/3] selftests/bpf: Add tests for >8 byte return value and " Yonghong Song
2026-07-11 1:02 ` [PATCH bpf-next v3 0/3] bpf: Fix trampoline handling of 128-bit values Kumar Kartikeya Dwivedi
2026-07-11 3:58 ` Yonghong Song
2026-07-11 12:18 ` Leon Hwang
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=20260710225211.4013521-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 \
--cc=leon.hwang@linux.dev \
/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