bpf: Consolidate sleepable checks in check_helper_call()

check_helper_call() prints the error message for every
env->cur_state->active* element when calling a sleepable helper.
Consolidate all of them into a single print statement.

The check for env->cur_state->active_locks was not part of the removed
print statements and will not be triggered with the consolidated print
as well because it is checked in do_check() before check_helper_call()
is even reached.

Acked-by: Mykyta Yatsenko <yatsenko@meta.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20260318174327.3151925-2-puranjay@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Puranjay Mohan 2026-03-18 10:43:24 -07:00 committed by Alexei Starovoitov
parent 4b21ea5024
commit a0d06cf102
3 changed files with 20 additions and 30 deletions

View File

@ -11678,6 +11678,19 @@ static inline bool in_sleepable_context(struct bpf_verifier_env *env)
in_sleepable(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";
return "non-sleepable prog";
}
static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
int *insn_idx_p)
{
@ -11717,11 +11730,6 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
return -EINVAL;
}
if (!in_sleepable(env) && fn->might_sleep) {
verbose(env, "helper call might sleep in a non-sleepable prog\n");
return -EINVAL;
}
/* With LD_ABS/IND some JITs save/restore skb from r1. */
changes_data = bpf_helper_changes_pkt_data(func_id);
if (changes_data && fn->arg1_type != ARG_PTR_TO_CTX) {
@ -11738,28 +11746,10 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
return err;
}
if (env->cur_state->active_rcu_locks) {
if (fn->might_sleep) {
verbose(env, "sleepable helper %s#%d in rcu_read_lock region\n",
func_id_name(func_id), func_id);
return -EINVAL;
}
}
if (env->cur_state->active_preempt_locks) {
if (fn->might_sleep) {
verbose(env, "sleepable helper %s#%d in non-preemptible region\n",
func_id_name(func_id), func_id);
return -EINVAL;
}
}
if (env->cur_state->active_irq_id) {
if (fn->might_sleep) {
verbose(env, "sleepable helper %s#%d in IRQ-disabled region\n",
func_id_name(func_id), func_id);
return -EINVAL;
}
if (fn->might_sleep && !in_sleepable_context(env)) {
verbose(env, "sleepable helper %s#%d in %s\n", func_id_name(func_id), func_id,
non_sleepable_context_description(env));
return -EINVAL;
}
/* Track non-sleepable context for helpers. */

View File

@ -58,7 +58,7 @@ static void test_aux(const char *main_prog_name,
* this particular combination can be enabled.
*/
if (!strcmp("might_sleep", replacement) && err) {
ASSERT_HAS_SUBSTR(log, "helper call might sleep in a non-sleepable prog", "error log");
ASSERT_HAS_SUBSTR(log, "sleepable helper bpf_copy_from_user#", "error log");
ASSERT_EQ(err, -EINVAL, "err");
test__skip();
goto out;

View File

@ -31,7 +31,7 @@ static int timer_cb(void *map, int *key, struct bpf_timer *timer)
}
SEC("fentry/bpf_fentry_test1")
__failure __msg("helper call might sleep in a non-sleepable prog")
__failure __msg("sleepable helper bpf_copy_from_user#{{[0-9]+}} in non-sleepable prog")
int timer_non_sleepable_prog(void *ctx)
{
struct timer_elem *val;
@ -47,7 +47,7 @@ int timer_non_sleepable_prog(void *ctx)
}
SEC("lsm.s/file_open")
__failure __msg("helper call might sleep in a non-sleepable prog")
__failure __msg("sleepable helper bpf_copy_from_user#{{[0-9]+}} in non-sleepable prog")
int timer_sleepable_prog(void *ctx)
{
struct timer_elem *val;