bpf_mem_cache_free_rcu() maybe called in preemptible context, this
will trigger the below warning message:
BUG: using smp_processor_id() in preemptible [00000000] code: syz.0.17/5820
caller is bpf_mem_cache_free_rcu+0x48/0xc0 kernel/bpf/memalloc.c:954
Call Trace:
check_preemption_disabled+0xd3/0xe0 lib/smp_processor_id.c:47
bpf_mem_cache_free_rcu+0x48/0xc0 kernel/bpf/memalloc.c:954
rhtab_delete_elem+0x185a/0x1b30 kernel/bpf/hashtab.c:2969
__rhtab_map_lookup_and_delete_batch+0x935/0xcb0 kernel/bpf/hashtab.c:3349
bpf_map_do_batch+0x445/0x630 kernel/bpf/syscall.c:-1
__sys_bpf+0x906/0xd90 kernel/bpf/syscall.c:-1
this_cpu_ptr() access needs to be guarded against migration.
Wrapping this batch operation in bpf_disable_instrumentation() risk
blinding BPF tracing globally on the CPU if preemption occurs.
bpf_disable_instrumentation() increments the per-CPU bpf_prog_active counter.
Because migrate_disable() and rcu_read_lock() do not disable preemption under
CONFIG_PREEMPT_RCU, the task can be preempted during this potentially long
loop.
If preempted, bpf_prog_active would remain elevated on that CPU, which could
cause subsequent tasks scheduled on the same CPU to silently drop BPF tracing
events (kprobes, tracepoints, perf).
Therefore, we fix this by disabling preemption rather than prohibiting
migration.
Fixes: 5af6807bdb10 ("bpf: Introduce bpf_mem_free_rcu() similar to kfree_rcu().")
Reported-by: syzbot+fd7e415d891073b83e1f@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=fd7e415d891073b83e1f
Signed-off-by: Edward Adam Davis <redacted>
---
v1 -> v2: using guard against preemption
v2 -> v3: replace get/put_cpu() to bpf_disable/enable_instrumentation()
v3 -> v4: disable preempt to make this_cpu_ptr() work
kernel/bpf/hashtab.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c
index 9f394e1aa2e8..7b98c2eea685 100644
--- a/kernel/bpf/hashtab.c
+++ b/kernel/bpf/hashtab.c
@@ -3345,8 +3345,10 @@ static int __rhtab_map_lookup_and_delete_batch(struct bpf_map *map,
}
if (do_delete) {
+ get_cpu();
for (i = 0; i < total; i++)
rhtab_delete_elem(rhtab, del_elems[i], NULL, 0);
+ put_cpu();
}
rcu_read_unlock();--
2.43.0