From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
To: bpf@vger.kernel.org
Cc: Eduard Zingerman <eddyz87@gmail.com>,
Alexei Starovoitov <ast@kernel.org>,
Andrii Nakryiko <andrii@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Emil Tsalapatis <emil@etsalapatis.com>,
kkd@meta.com, kernel-team@meta.com
Subject: [PATCH bpf-next v3 4/7] bpf: Report non-sleepable kfunc programs accurately
Date: Thu, 24 Sep 2026 19:06:38 +0200 [thread overview]
Message-ID: <20260924170646.2366016-5-memxor@gmail.com> (raw)
In-Reply-To: <20260924170646.2366016-1-memxor@gmail.com>
A sleepable kfunc call can fail either because the program is not
sleepable or because an otherwise sleepable program has entered a
non-sleepable critical section. check_kfunc_call() checks these
conditions separately. The first check is only gated by in_sleepable(),
so the shared diagnostic can blame an active RCU, preemption-disabled,
IRQ-disabled, or locked region even though leaving that region would not
make the program sleepable. Adding a second diagnostic entry point only
to force the program context would duplicate the API.
Reject the call once based on in_sleepable_context(). Teach the shared
bpf_diag_ctx_forbidden() reporter and non_sleepable_context_description()
to consider active RCU, preempt, IRQ, and lock regions only when the
program is sleepable, and to fall back to the non-sleepable program
otherwise. A non-sleepable program can still hold that context state, so
relying on the existing no-context fallback alone would keep blaming the
critical section.
Select the suggestion at the kfunc, helper, and global-function sites
according to that cause, and choose between the two existing kfunc
verifier messages the same way, so a sleepable program is told to leave
the critical section and a non-sleepable program is told to become
sleepable.
This avoids a diagnostic-only wrapper while retaining context history for
sleepable programs that enter a forbidden region.
Link: https://lore.kernel.org/bpf/2e42a1a2bf45f4d2aba7495bdc9f147558055740e2f3c8b9dae255f6c57fc13c@mail.kernel.org/
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
kernel/bpf/diagnostics.c | 21 +++++++-------
kernel/bpf/verifier.c | 62 ++++++++++++++++++++++++----------------
2 files changed, 48 insertions(+), 35 deletions(-)
diff --git a/kernel/bpf/diagnostics.c b/kernel/bpf/diagnostics.c
index 496d24064532..69c168e03732 100644
--- a/kernel/bpf/diagnostics.c
+++ b/kernel/bpf/diagnostics.c
@@ -1119,16 +1119,17 @@ void bpf_diag_ctx_forbidden(struct bpf_verifier_env *env, u32 insn_idx,
const char *constraint, *context;
u32 depth;
- if (env->cur_state->active_rcu_locks)
- ctx_kind = BPF_DIAG_CONTEXT_RCU;
- else if (env->cur_state->active_preempt_locks)
- ctx_kind = BPF_DIAG_CONTEXT_PREEMPT;
- else if (env->cur_state->active_irq_id)
- ctx_kind = BPF_DIAG_CONTEXT_IRQ;
- else if (env->cur_state->active_locks)
- ctx_kind = BPF_DIAG_CONTEXT_LOCK;
- else
- ctx_kind = BPF_DIAG_CONTEXT_NONE;
+ ctx_kind = BPF_DIAG_CONTEXT_NONE;
+ if (env->cur_state->in_sleepable) {
+ if (env->cur_state->active_rcu_locks)
+ ctx_kind = BPF_DIAG_CONTEXT_RCU;
+ else if (env->cur_state->active_preempt_locks)
+ ctx_kind = BPF_DIAG_CONTEXT_PREEMPT;
+ else if (env->cur_state->active_irq_id)
+ ctx_kind = BPF_DIAG_CONTEXT_IRQ;
+ else if (env->cur_state->active_locks)
+ ctx_kind = BPF_DIAG_CONTEXT_LOCK;
+ }
depth = diag_context_depth(env, ctx_kind);
opts = (struct bpf_diag_history_opts) {
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 7fbe32ce9449..d5a2ca9a24c2 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -11116,11 +11116,16 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
}
if (env->subprog_info[subprog].might_sleep && !in_sleepable_context(env)) {
+ const char *suggestion;
+
verbose(env, "sleepable global function %s() called in %s\n",
sub_name, non_sleepable_context_description(env));
+ if (in_sleepable(env))
+ suggestion = "Move the call outside the critical section, or use a non-sleepable function.";
+ else
+ suggestion = "Mark the program sleepable if the program type allows it, or use a non-sleepable function.";
operation = bpf_diag_fmt(env, "sleepable global function %s()", sub_name);
- bpf_diag_ctx_forbidden(env, *insn_idx, operation,
- "Move the call outside the critical section, or use a non-sleepable function.");
+ bpf_diag_ctx_forbidden(env, *insn_idx, operation, suggestion);
return -EINVAL;
}
@@ -12049,14 +12054,16 @@ static inline bool in_sleepable_context(struct bpf_verifier_env *env)
static const char *non_sleepable_context_description(struct bpf_verifier_env *env)
{
- if (env->cur_state->active_rcu_locks)
- return "rcu_read_lock region";
- if (env->cur_state->active_preempt_locks)
- return "non-preemptible region";
- if (env->cur_state->active_irq_id)
- return "IRQ-disabled region";
- if (env->cur_state->active_locks)
- return "lock region";
+ if (in_sleepable(env)) {
+ if (env->cur_state->active_rcu_locks)
+ return "rcu_read_lock region";
+ if (env->cur_state->active_preempt_locks)
+ return "non-preemptible region";
+ if (env->cur_state->active_irq_id)
+ return "IRQ-disabled region";
+ if (env->cur_state->active_locks)
+ return "lock region";
+ }
return "non-sleepable prog";
}
@@ -12148,12 +12155,17 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
}
if (fn->might_sleep && !in_sleepable_context(env)) {
+ const char *suggestion;
+
verbose(env, "sleepable helper %s#%d in %s\n", func_id_name(func_id), func_id,
non_sleepable_context_description(env));
+ if (in_sleepable(env))
+ suggestion = "Move the helper call outside the critical section, or use a non-sleepable helper.";
+ else
+ suggestion = "Mark the program sleepable if the program type allows it, or use a non-sleepable helper.";
operation = bpf_diag_fmt(env, "sleepable helper %s#%d",
func_id_name(func_id), func_id);
- bpf_diag_ctx_forbidden(env, insn_idx, operation,
- "Move the helper call outside the critical section, or use a non-sleepable helper.");
+ bpf_diag_ctx_forbidden(env, insn_idx, operation, suggestion);
return -EINVAL;
}
@@ -14787,11 +14799,20 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
}
sleepable = bpf_is_kfunc_sleepable(&meta);
- if (sleepable && !in_sleepable(env)) {
- verbose(env, "program must be sleepable to call sleepable kfunc %s\n", func_name);
+ if (sleepable && !in_sleepable_context(env)) {
+ const char *suggestion;
+
+ if (in_sleepable(env)) {
+ verbose(env, "kernel func %s is sleepable within %s\n",
+ func_name, non_sleepable_context_description(env));
+ suggestion = "Move the kfunc call outside the critical section, or use a non-sleepable kfunc.";
+ } else {
+ verbose(env, "program must be sleepable to call sleepable kfunc %s\n",
+ func_name);
+ suggestion = "Mark the program sleepable if the program type allows it, or use a non-sleepable kfunc.";
+ }
operation = bpf_diag_fmt(env, "sleepable kfunc %s", func_name);
- bpf_diag_ctx_forbidden(env, insn_idx, operation,
- "Mark the program sleepable if the program type allows it, or use a non-sleepable kfunc.");
+ bpf_diag_ctx_forbidden(env, insn_idx, operation, suggestion);
return -EACCES;
}
@@ -14905,15 +14926,6 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
invalidate_rcu_protected_refs(env);
}
- if (sleepable && !in_sleepable_context(env)) {
- verbose(env, "kernel func %s is sleepable within %s\n",
- func_name, non_sleepable_context_description(env));
- operation = bpf_diag_fmt(env, "sleepable kfunc %s", func_name);
- bpf_diag_ctx_forbidden(env, insn_idx, operation,
- "Move the kfunc call outside the critical section, or use a non-sleepable kfunc.");
- return -EACCES;
- }
-
if (in_rbtree_lock_required_cb(env) && (rcu_lock || rcu_unlock)) {
verbose(env, "Calling bpf_rcu_read_{lock,unlock} in unnecessary rbtree callback\n");
return -EACCES;
--
2.53.0
next prev parent reply other threads:[~2026-09-24 17:06 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-24 17:06 [PATCH bpf-next v3 0/7] Follow ups for verifier errors set Kumar Kartikeya Dwivedi
2026-09-24 17:06 ` [PATCH bpf-next v3 1/7] bpf: Correct verifier diagnostic attribution for stack reads Kumar Kartikeya Dwivedi
2026-09-24 17:06 ` [PATCH bpf-next v3 2/7] selftests/bpf: Test verifier stack-read diagnostic attribution Kumar Kartikeya Dwivedi
2026-09-24 17:06 ` [PATCH bpf-next v3 3/7] bpf: Drop dead spill diagnostic condition Kumar Kartikeya Dwivedi
2026-09-24 17:06 ` Kumar Kartikeya Dwivedi [this message]
2026-09-24 17:06 ` [PATCH bpf-next v3 5/7] selftests/bpf: Test non-sleepable kfunc context Kumar Kartikeya Dwivedi
2026-09-24 17:06 ` [PATCH bpf-next v3 6/7] bpf: Correct Program Structure diagnostic context Kumar Kartikeya Dwivedi
2026-09-24 17:06 ` [PATCH bpf-next v3 7/7] selftests/bpf: Test " Kumar Kartikeya Dwivedi
2026-09-24 21:10 ` [PATCH bpf-next v3 0/7] Follow ups for verifier errors set patchwork-bot+netdevbpf
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=20260924170646.2366016-5-memxor@gmail.com \
--to=memxor@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=emil@etsalapatis.com \
--cc=kernel-team@meta.com \
--cc=kkd@meta.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 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.