There are three situations when a program logically exits and transfers
control to the kernel or another program: bpf_throw, BPF_EXIT, and tail
calls. The former two check for any lingering locks and references, but
tail calls currently do not. Expand the checks to check for spin locks,
RCU read sections and preempt disabled sections.
Spin locks are indirectly preventing tail calls as function calls are
disallowed, but the checks for preemption and RCU are more relaxed,
hence ensure tail calls are prevented in their presence.
Fixes: 9bb00b2895cb ("bpf: Add kfunc bpf_rcu_read_lock/unlock()")
Fixes: fc7566ad0a82 ("bpf: Introduce bpf_preempt_[disable,enable] kfuncs")
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20241103225940.1408302-2-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
switch (func_id) {
case BPF_FUNC_tail_call:
+ if (env->cur_state->active_lock.ptr) {
+ verbose(env, "tail_call cannot be used inside bpf_spin_lock-ed region\n");
+ return -EINVAL;
+ }
+
err = check_reference_leak(env, false);
if (err) {
verbose(env, "tail_call would lead to reference leak\n");
return err;
}
+
+ if (env->cur_state->active_rcu_lock) {
+ verbose(env, "tail_call cannot be used inside bpf_rcu_read_lock-ed region\n");
+ return -EINVAL;
+ }
+
+ if (env->cur_state->active_preempt_lock) {
+ verbose(env, "tail_call cannot be used inside bpf_preempt_disable-ed region\n");
+ return -EINVAL;
+ }
break;
case BPF_FUNC_get_local_storage:
/* check that flags argument in get_local_storage(map, flags) is 0,