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>,
kernel-team@fb.com, Martin KaFai Lau <martin.lau@kernel.org>
Subject: [PATCH bpf-next v3 6/7] bpf,x86: Fix exception unwinding with outgoing stack arguments
Date: Fri, 15 May 2026 15:51:06 -0700 [thread overview]
Message-ID: <20260515225106.824804-1-yonghong.song@linux.dev> (raw)
In-Reply-To: <20260515225035.821178-1-yonghong.song@linux.dev>
When a main program with exception_boundary has outgoing stack
arguments (e.g. from calling subprogs with >5 args), bpf_throw() fails
to correctly restore callee-saved registers, causing a kernel crash.
The x86 JIT allocates the outgoing stack arg area below the
callee-saved registers via 'sub rsp, outgoing_rsp' in the prologue.
When bpf_throw() unwinds, it captures the main program's sp (which
includes this outgoing area) and passes it to the exception callback.
The callback gets rsp and rbp, followed by pop_callee_regs, but rsp
points into the outgoing arg area rather than the callee-saved
registers, so the pops restore garbage values. Returning to the
kernel with corrupted callee-saved registers causes a crash.
Fix this by passing the main program's outgoing_rsp as the 4th
argument to the exception callback. The callback adjusts rsp with
'add rsp, rcx' before popping callee-saved registers, correctly
skipping the outgoing arg area. When outgoing_rsp is 0 (the common
case), this is a no-op.
Fixes: 324c3ca6eed6 ("bpf,x86: Implement JIT support for stack arguments")
Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
---
arch/x86/net/bpf_jit_comp.c | 9 ++++++++-
include/linux/bpf.h | 3 ++-
kernel/bpf/fixups.c | 1 +
kernel/bpf/helpers.c | 2 +-
4 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index ceefefb4da21..f4fdceedaad7 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -557,10 +557,15 @@ static void emit_prologue(u8 **pprog, u8 *ip, u32 stack_depth, bool ebpf_from_cb
/* Keep the same instruction layout. */
emit_nops(&prog, 3); /* nop3 */
}
- /* Exception callback receives FP as third parameter */
+ /*
+ * Exception callback receives:
+ * rsi = main program's SP, rdx = main program's FP,
+ * rcx = main program's outgoing stack arg area size
+ */
if (is_exception_cb) {
EMIT3(0x48, 0x89, 0xF4); /* mov rsp, rsi */
EMIT3(0x48, 0x89, 0xD5); /* mov rbp, rdx */
+ EMIT3(0x48, 0x01, 0xCC); /* add rsp, rcx */
/* The main frame must have exception_boundary as true, so we
* first restore those callee-saved regs from stack, before
* reusing the stack frame.
@@ -1789,6 +1794,8 @@ static int do_jit(struct bpf_verifier_env *env, struct bpf_prog *bpf_prog, int *
* Arg 6 goes into r9 register, not on stack.
*/
outgoing_rsp = out_stack_arg_cnt > 1 ? (out_stack_arg_cnt - 1) * 8 : 0;
+ if (bpf_prog->aux->exception_boundary)
+ bpf_prog->aux->stack_arg_adjust = outgoing_rsp;
emit_sub_rsp(&prog, outgoing_rsp);
if (arena_vm_start)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 242f9597d9ab..2a1616c769a9 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1735,7 +1735,8 @@ struct bpf_prog_aux {
int cgroup_atype; /* enum cgroup_bpf_attach_type */
struct bpf_map *cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE];
char name[BPF_OBJ_NAME_LEN];
- u64 (*bpf_exception_cb)(u64 cookie, u64 sp, u64 bp, u64, u64);
+ u64 (*bpf_exception_cb)(u64 cookie, u64 sp, u64 bp, u64 stack_arg_adjust, u64);
+ u16 stack_arg_adjust;
#ifdef CONFIG_SECURITY
void *security;
#endif
diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c
index 2cec4e8cd4a0..52aaf2863648 100644
--- a/kernel/bpf/fixups.c
+++ b/kernel/bpf/fixups.c
@@ -1265,6 +1265,7 @@ static int jit_subprogs(struct bpf_verifier_env *env)
prog->aux->real_func_cnt = env->subprog_cnt;
prog->aux->bpf_exception_cb = (void *)func[env->exception_callback_subprog]->bpf_func;
prog->aux->exception_boundary = func[0]->aux->exception_boundary;
+ prog->aux->stack_arg_adjust = func[0]->aux->stack_arg_adjust;
bpf_prog_jit_attempt_done(prog);
return 0;
out_free:
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index baa12b24bb64..53a0430f60b3 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -3301,7 +3301,7 @@ __bpf_kfunc void bpf_throw(u64 cookie)
* which skips compiler generated instrumentation to do the same.
*/
kasan_unpoison_task_stack_below((void *)(long)ctx.sp);
- ctx.aux->bpf_exception_cb(cookie, ctx.sp, ctx.bp, 0, 0);
+ ctx.aux->bpf_exception_cb(cookie, ctx.sp, ctx.bp, ctx.aux->stack_arg_adjust, 0);
WARN(1, "A call to BPF exception callback should never return\n");
}
--
2.53.0-Meta
next prev parent reply other threads:[~2026-05-15 22:51 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-15 22:50 [PATCH bpf-next v3 0/7] bpf: Follow-up fixes for stack argument support Yonghong Song
2026-05-15 22:50 ` [PATCH bpf-next v3 1/7] bpf: Validate outgoing stack args when btf_prepare_func_args fails Yonghong Song
2026-05-15 22:50 ` [PATCH bpf-next v3 2/7] selftests/bpf: Add test for stack arg read without caller write Yonghong Song
2026-05-15 22:50 ` [PATCH bpf-next v3 3/7] selftests/bpf: Log arg_track_join for stack arg slots in liveness analysis Yonghong Song
2026-05-15 22:50 ` [PATCH bpf-next v3 4/7] bpf: Fix arg_track_join log to use sa prefix for stack arg slots Yonghong Song
2026-05-15 22:51 ` [PATCH bpf-next v3 5/7] bpf: Clean up redundant stack arg checks for non-JITed programs Yonghong Song
2026-05-15 22:51 ` Yonghong Song [this message]
2026-05-15 22:51 ` [PATCH bpf-next v3 7/7] selftests/bpf: Add exception tests with stack arguments 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=20260515225106.824804-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=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.