[PATCH bpf-next v1 1/2] bpf: Fix sleepable context checks and remove in_sleepable helper
Kumar Kartikeya Dwivedi <[email protected]>
| Newsgroups | org.kernel.vger.bpf |
|---|---|
| Message-ID | <[email protected]> |
The verifier has two helpers to determine if the current program can
sleep:
- in_sleepable() checks only env->cur_state->in_sleepable
- in_sleepable_context() checks active RCU, preempt, lock and IRQ
state in addition to in_sleepable
Several call sites incorrectly used in_sleepable() where
in_sleepable_context() is required. This allowed sleepable programs
in non-sleepable contexts (e.g., inside bpf_rcu_read_lock()) to
incorrectly use sleepable iterators and kfuncs:
- check_css_task_iter_allowlist() returned in_sleepable() and
therefore allowed css_task iterator in any sleepable program,
even inside RCU/preempt/lock/IRQ-disabled regions. Fix it to
use in_sleepable_context().
- The first sleepable check in check_kfunc_call() used
in_sleepable() and only verified the program flag, not the
current context. Replace it with in_sleepable_context() so
sleepable kfuncs are rejected when called from any
non-sleepable context, consistent with the second check in the
same function.
To prevent future misuse, remove the in_sleepable() helper
completely and replace its legitimate uses with a direct check of
env->cur_state->in_sleepable. We do not want anyone to test this
bit directly and in isolation; all sleepable-context decisions must
go through in_sleepable_context(), which accounts for locks and
preemption. The remaining direct checks are in in_rcu_cs() and
in_sleepable_context() itself, where testing the bit in isolation
is intentional.
Signed-off-by: Kumar Kartikeya Dwivedi <[email protected]>
---
kernel/bpf/verifier.c | 13 ++++---------
1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index e6233c0081d1..3dadf2b33a36 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -4441,11 +4441,6 @@ static int map_kptr_match_type(struct bpf_verifier_env *env,
return -EINVAL;
}
-static bool in_sleepable(struct bpf_verifier_env *env)
-{
- return env->cur_state->in_sleepable;
-}
-
/* The non-sleepable programs and sleepable programs with explicit bpf_rcu_read_lock()
* can dereference RCU protected pointers and result is PTR_TRUSTED.
*/
@@ -4455,7 +4450,7 @@ static bool in_rcu_cs(struct bpf_verifier_env *env)
env->cur_state->active_preempt_locks ||
env->cur_state->active_locks ||
env->cur_state->active_irq_id ||
- !in_sleepable(env);
+ !env->cur_state->in_sleepable;
}
/* Once GCC supports btf_type_tag the following mechanism will be replaced with tag check */
@@ -10258,7 +10253,7 @@ static inline bool in_sleepable_context(struct bpf_verifier_env *env)
!env->cur_state->active_preempt_locks &&
!env->cur_state->active_locks &&
!env->cur_state->active_irq_id &&
- in_sleepable(env);
+ env->cur_state->in_sleepable;
}
static const char *non_sleepable_context_description(struct bpf_verifier_env *env)
@@ -12083,7 +12078,7 @@ static bool check_css_task_iter_allowlist(struct bpf_verifier_env *env)
return true;
fallthrough;
default:
- return in_sleepable(env);
+ return in_sleepable_context(env);
}
}
@@ -13090,7 +13085,7 @@ 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)) {
+ if (sleepable && !in_sleepable_context(env)) {
verbose(env, "program must be sleepable to call sleepable kfunc %s\n", func_name);
return -EACCES;
}
--
2.53.0-Meta