[PATCH v5] bpf: Fix smp_processor_id() call trace for preemptible kernels

From: Edward Adam Davis

Date: Tue Jun 30 2026 - 20:27:43 EST


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() requires the caller to prevent task migration.
These helpers currently do not enforce that requirement and may
be invoked from preemptible contexts, leading to accesses to another
CPU's per-CPU cache after migration. Use get_cpu_ptr()/put_cpu_ptr()
to pin the task while accessing the per-CPU allocator state.

Fixes: 5af6807bdb10 ("bpf: Introduce bpf_mem_free_rcu() similar to kfree_rcu().")
Fixes: 7c8199e24fa0 ("bpf: Introduce any context BPF specific memory allocator.")
Reported-by: syzbot+fd7e415d891073b83e1f@xxxxxxxxxxxxxxxxxxxxxxxxx
Closes: https://syzkaller.appspot.com/bug?extid=fd7e415d891073b83e1f
Signed-off-by: Edward Adam Davis <eadavis@xxxxxx>
---
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
v4 -> v5: in mem free disable preemption

kernel/bpf/memalloc.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/kernel/bpf/memalloc.c b/kernel/bpf/memalloc.c
index e9662db7198f..2118fe725ed4 100644
--- a/kernel/bpf/memalloc.c
+++ b/kernel/bpf/memalloc.c
@@ -911,7 +911,8 @@ void notrace bpf_mem_free(struct bpf_mem_alloc *ma, void *ptr)
if (WARN_ON_ONCE(idx < 0))
return;

- unit_free(this_cpu_ptr(ma->caches)->cache + idx, ptr);
+ unit_free(get_cpu_ptr(ma->caches)->cache + idx, ptr);
+ put_cpu_ptr(ma->caches);
}

void notrace bpf_mem_free_rcu(struct bpf_mem_alloc *ma, void *ptr)
@@ -927,7 +928,8 @@ void notrace bpf_mem_free_rcu(struct bpf_mem_alloc *ma, void *ptr)
if (WARN_ON_ONCE(idx < 0))
return;

- unit_free_rcu(this_cpu_ptr(ma->caches)->cache + idx, ptr);
+ unit_free_rcu(get_cpu_ptr(ma->caches)->cache + idx, ptr);
+ put_cpu_ptr(ma->caches);
}

void notrace *bpf_mem_cache_alloc(struct bpf_mem_alloc *ma)
@@ -951,7 +953,8 @@ void notrace bpf_mem_cache_free_rcu(struct bpf_mem_alloc *ma, void *ptr)
if (!ptr)
return;

- unit_free_rcu(this_cpu_ptr(ma->cache), ptr);
+ unit_free_rcu(get_cpu_ptr(ma->cache), ptr);
+ put_cpu_ptr(ma->cache);
}

/* Directly does a kfree() without putting 'ptr' back to the free_llist
--
2.43.0