BPF List
 help / color / mirror / Atom feed
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 v9 05/23] bpf: Mark covered call sites and check a program can take a table
Date: Thu,  8 Oct 2026 00:50:25 -0700	[thread overview]
Message-ID: <20261008075025.2996787-1-yonghong.song@linux.dev> (raw)
In-Reply-To: <20261008074959.2993751-1-yonghong.song@linux.dev>

 - bpf_exc_prepare(), run before the CFG walk, records the landing pad of
   every call in a cleanup record's range that can unwind: a BPF-to-BPF
   call, direct or indirect, or bpf_unwind().

 - bpf_exc_check_prog() refuses a table where pad dispatch cannot work:

     - an offloaded program, or one without a JIT that dispatches pads
     - a verifier_ops gen_epilogue, as bpf_qdisc's: it is planted on the
       exits bpf_convert_ctx_accesses() sees, and the exits an unwind
       returns through are added after it
     - an exception callback or a bpf_throw() anywhere: a throw leaves
       without rewriting return addresses, so no pad would run

   It runs after check_attach_btf_id(), since a struct_ops program's
   gen_epilogue is only known then, and marks what passes jit_required.
   bpf_jit_supports_cleanup_pads() says no until the arch patches.

Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
---
 include/linux/filter.h |  1 +
 kernel/bpf/core.c      |  5 +++
 kernel/bpf/exception.c | 70 ++++++++++++++++++++++++++++++++++++++++++
 kernel/bpf/exception.h |  2 ++
 kernel/bpf/verifier.c  |  9 ++++++
 5 files changed, 87 insertions(+)

diff --git a/include/linux/filter.h b/include/linux/filter.h
index 9339c6131f8f..c8ca863e352a 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -1248,6 +1248,7 @@ bool bpf_jit_supports_stack_args(void);
 bool bpf_jit_supports_arena_args(void);
 bool bpf_jit_supports_far_kfunc_call(void);
 bool bpf_jit_supports_exceptions(void);
+bool bpf_jit_supports_cleanup_pads(void);
 bool bpf_jit_supports_ptr_xchg(void);
 bool bpf_jit_supports_arena(void);
 bool bpf_jit_supports_arena_scalar(void);
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 05c89396119a..078bcccaf242 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -3528,6 +3528,11 @@ void __weak arch_bpf_stack_walk(bool (*consume_fn)(void *cookie, u64 ip, u64 sp,
 {
 }
 
+bool __weak bpf_jit_supports_cleanup_pads(void)
+{
+	return false;
+}
+
 bool __weak bpf_jit_supports_timed_may_goto(void)
 {
 	return false;
diff --git a/kernel/bpf/exception.c b/kernel/bpf/exception.c
index 3ea1bff5cc90..d85ca358b463 100644
--- a/kernel/bpf/exception.c
+++ b/kernel/bpf/exception.c
@@ -141,6 +141,76 @@ int bpf_exc_check_info(struct bpf_verifier_env *env, const union bpf_attr *attr,
 BTF_ID_LIST_SINGLE(bpf_unwind_id, func, bpf_unwind)
 BTF_ID_LIST_SINGLE(bpf_unwind_resume_id, func, bpf_unwind_resume)
 
+static int reject_throw(struct bpf_verifier_env *env)
+{
+	u32 i;
+
+	for (i = 0; i < env->prog->len; i++) {
+		if (!bpf_is_throw_kfunc(&env->prog->insnsi[i]))
+			continue;
+		verbose(env,
+			"exception cleanup cannot be combined with bpf_throw at insn %u\n",
+			i);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void mark_call_sites(struct bpf_verifier_env *env)
+{
+	u32 i, j;
+
+	for (i = 0; i < env->cleanup_info_cnt; i++) {
+		struct bpf_cleanup_info *rec = &env->cleanup_info[i];
+
+		for (j = rec->begin_off; j < rec->end_off; j++) {
+			struct bpf_insn *insn = &env->prog->insnsi[j];
+
+			if (!bpf_pseudo_call(insn) && !bpf_is_callx(insn) &&
+			    !bpf_is_unwind_kfunc(insn))
+				continue;
+			env->insn_aux_data[j].cleanup_pad = rec->landing_pad_off + 1;
+		}
+	}
+}
+
+int bpf_exc_check_prog(struct bpf_verifier_env *env)
+{
+	int err;
+
+	if (bpf_prog_is_offloaded(env->prog->aux)) {
+		verbose(env,
+			"exception cleanup is not supported for offloaded programs\n");
+		return -EINVAL;
+	}
+	if (!bpf_jit_supports_cleanup_pads() || !env->prog->jit_requested) {
+		verbose(env,
+			"exception cleanup needs a JIT that can dispatch landing pads\n");
+		return -EOPNOTSUPP;
+	}
+	if (env->ops->gen_epilogue) {
+		verbose(env,
+			"exception cleanup is not supported for a program with an epilogue\n");
+		return -EOPNOTSUPP;
+	}
+	if (env->exception_callback_subprog) {
+		verbose(env,
+			"exception cleanup cannot be combined with an exception callback\n");
+		return -EINVAL;
+	}
+	err = reject_throw(env);
+	if (err)
+		return err;
+	env->prog->jit_required = 1;
+	return 0;
+}
+
+void bpf_exc_prepare(struct bpf_verifier_env *env)
+{
+	if (env->cleanup_info_cnt)
+		mark_call_sites(env);
+}
+
 bool bpf_is_unwind_kfunc(const struct bpf_insn *insn)
 {
 	return bpf_pseudo_kfunc_call(insn) && insn->off == 0 &&
diff --git a/kernel/bpf/exception.h b/kernel/bpf/exception.h
index d5c6ac459870..9b75e556c82e 100644
--- a/kernel/bpf/exception.h
+++ b/kernel/bpf/exception.h
@@ -12,6 +12,8 @@ struct bpf_insn;
 
 int bpf_exc_check_info(struct bpf_verifier_env *env, const union bpf_attr *attr,
 		       bpfptr_t uattr);
+void bpf_exc_prepare(struct bpf_verifier_env *env);
+int bpf_exc_check_prog(struct bpf_verifier_env *env);
 int bpf_exc_pad_of_call(struct bpf_verifier_env *env, u32 idx);
 bool bpf_is_unwind_kfunc(const struct bpf_insn *insn);
 bool bpf_is_unwind_resume_kfunc(const struct bpf_insn *insn);
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 60413bf0ad3f..0cf30220b777 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -22711,6 +22711,9 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr,
 	if (ret < 0)
 		goto skip_full_check;
 
+	/* The CFG needs an edge from a call in a cleanup range to its pad. */
+	bpf_exc_prepare(env);
+
 	/* Validate instructions and resolve the program's referenced resources. */
 	ret = check_and_resolve_insns(env);
 	if (ret < 0)
@@ -22748,6 +22751,12 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr,
 	if (ret)
 		goto skip_full_check;
 
+	if (env->cleanup_info_cnt) {
+		ret = bpf_exc_check_prog(env);
+		if (ret)
+			goto skip_full_check;
+	}
+
 	ret = bpf_compute_const_regs(env);
 	if (ret < 0)
 		goto skip_full_check;
-- 
2.53.0-Meta


  parent reply	other threads:[~2026-10-08  7:50 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-08  7:49 [PATCH bpf-next v9 00/23] bpf: Run exception cleanup landing pads when bpf_unwind() unwinds Yonghong Song
2026-10-08  7:50 ` [PATCH bpf-next v9 01/23] bpf: Pack bpf_insn_aux_data flags into bit fields Yonghong Song
2026-10-08  7:50 ` [PATCH bpf-next v9 02/23] bpf: Accept the compiler's exception cleanup table at program load Yonghong Song
2026-10-08  7:50 ` [PATCH bpf-next v9 03/23] bpf: Add the bpf_unwind() and bpf_unwind_resume() kfuncs Yonghong Song
2026-10-08  7:50 ` [PATCH bpf-next v9 04/23] bpf: Keep a call site's landing pad in insn_aux_data, add lookups Yonghong Song
2026-10-08  8:01   ` sashiko-bot
2026-10-08 15:58     ` Yonghong Song
2026-10-08  7:50 ` Yonghong Song [this message]
2026-10-08  7:50 ` [PATCH bpf-next v9 06/23] bpf: Make exception landing pads reachable in the CFG Yonghong Song
2026-10-08  7:50 ` [PATCH bpf-next v9 07/23] bpf: Verify an unwind through landing pads and epilogues Yonghong Song
2026-10-08  8:57   ` bot+bpf-ci
2026-10-08 16:07     ` Yonghong Song
2026-10-08  7:50 ` [PATCH bpf-next v9 08/23] bpf: Refuse a landing pad that does not resume Yonghong Song
2026-10-08  8:57   ` bot+bpf-ci
2026-10-08 16:11     ` Yonghong Song
2026-10-08  7:50 ` [PATCH bpf-next v9 09/23] bpf: Do not use a private stack for a program that can unwind Yonghong Song
2026-10-08  7:50 ` [PATCH bpf-next v9 10/23] bpf: Prepare JITed programs for dispatching cleanup pads Yonghong Song
2026-10-08  7:50 ` [PATCH bpf-next v9 11/23] bpf: Dispatch cleanup pads by rewriting return addresses Yonghong Song
2026-10-08  7:51 ` [PATCH bpf-next v9 12/23] bpf: Refuse a trampoline that calls a subprog that can unwind Yonghong Song
2026-10-08  8:14   ` sashiko-bot
2026-10-08 16:19     ` Yonghong Song
2026-10-08  7:51 ` [PATCH bpf-next v9 13/23] bpf, x86: Dispatch exception cleanup pads at run time Yonghong Song
2026-10-08  7:51 ` [PATCH bpf-next v9 14/23] bpf, arm64: " Yonghong Song
2026-10-08  8:39   ` bot+bpf-ci
2026-10-08 16:23     ` Yonghong Song
2026-10-08  7:51 ` [PATCH bpf-next v9 15/23] libbpf: Resolve the compiler's _Unwind_Resume to the kernel's kfunc Yonghong Song
2026-10-08  7:51 ` [PATCH bpf-next v9 16/23] libbpf: Add cleanup_info to bpf_prog_load_opts Yonghong Song
2026-10-08  8:12   ` sashiko-bot
2026-10-08 16:25     ` Yonghong Song
2026-10-08  7:51 ` [PATCH bpf-next v9 17/23] libbpf: Collect .bpf_cleanup records and pass them to the kernel Yonghong Song
2026-10-08  7:51 ` [PATCH bpf-next v9 18/23] libbpf: Carry the exception cleanup table through the light skeleton Yonghong Song
2026-10-08  7:51 ` [PATCH bpf-next v9 19/23] libbpf: Let the static linker carry .bpf_cleanup relocations Yonghong Song
2026-10-08  8:14   ` sashiko-bot
2026-10-08 16:26     ` Yonghong Song
2026-10-08  7:51 ` [PATCH bpf-next v9 20/23] selftests/bpf: Add end-to-end and negative .bpf_cleanup exception tests Yonghong Song
2026-10-08  7:51 ` [PATCH bpf-next v9 21/23] selftests/bpf: Add __set_global() and __ret_global() test tags Yonghong Song
2026-10-08  7:51 ` [PATCH bpf-next v9 22/23] selftests/bpf: Cover more accepted .bpf_cleanup exception shapes Yonghong Song
2026-10-08  7:51 ` [PATCH bpf-next v9 23/23] selftests/bpf: Load an exception cleanup program from a light skeleton 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=20261008075025.2996787-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