Re: [PATCH bpf-next v2 33/43] bpf: Keep the symbols of a program until it has ended
flat view
From: bot+bpf-ci@kernel.org
Date: 2026-10-17 17:17:24
Also in:
bpf
bpf: Keep the symbols of a program until it has ended
TL;DR: Design question: kallsyms removal now happens after the RCU callback frees btf and linfo, so a symbol lookup in that window might touch freed memory. The review found no such reader.
quoted hunk ↗ jump to hunk
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index e1216927373a..6e32db9777c2 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c@@ -3085,12 +3085,40 @@ static void bpf_free_used_btfs(struct bpf_prog_aux *aux)
[ ... ]
quoted hunk ↗ jump to hunk
+static void bpf_prog_free_deferred(struct work_struct *work) +{ + struct bpf_prog_aux *aux; + bool ksyms; + aux = container_of(work, struct bpf_prog_aux, work); + /* + * A prog that still runs when its last reference goes needs its symbols, + * by which its exception table is found. It has ended by now. + */ + ksyms = aux->real_func_cnt || !list_empty(&aux->ksym.lnode); + bpf_prog_kallsyms_del_all(aux->prog); #ifdef CONFIG_BPF_SYSCALL bpf_free_kfunc_btf_tab(aux->kfunc_btf_tab); #endif
[ ... ]
quoted hunk ↗ jump to hunk
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index c412bcd1903f..ddb986324f2f 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c@@ -2461,6 +2461,8 @@ static void __bpf_prog_put_rcu(struct rcu_head *rcu) struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu); btf_put(aux->btf); + kvfree(aux->jited_linfo); + kvfree(aux->linfo); kvfree(aux->func_info); kfree(aux->func_info_aux); free_uid(aux->user);@@ -2485,10 +2487,7 @@ static void __bpf_prog_put_rcu_tasks(struct rcu_head *rcu) static void __bpf_prog_put_noref(struct bpf_prog *prog, bool deferred) { - bpf_prog_kallsyms_del_all(prog); module_put(prog->aux->mod); - kvfree(prog->aux->jited_linfo); - kvfree(prog->aux->linfo); kfree(prog->aux->kfunc_tab); kfree(prog->aux->ctx_arg_info); if (prog->aux->attach_btf)
A subsystem pattern flags the ordering here as potentially concerning, so
this is a question rather than a confirmed bug.
__bpf_prog_put_noref() still issues call_rcu() (or call_rcu_tasks() or
call_rcu_tasks_trace()) on &prog->aux->rcu:
if (deferred) {
if (IS_ENABLED(CONFIG_TASKS_RCU) && prog->aux->tramp_linked)
call_rcu_tasks(&prog->aux->rcu, __bpf_prog_put_rcu_tasks);
else if (bpf_prog_runs_sleepable(prog))
call_rcu_tasks_trace(&prog->aux->rcu, __bpf_prog_put_rcu);
else
call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
}
but with bpf_prog_kallsyms_del_all() gone from this function, aux->ksym is
still linked in the RCU-protected bpf_tree latch tree and the bpf_kallsyms
list when the callback is queued.
The removal now happens in bpf_prog_free_deferred(), which is a work item
scheduled from inside the callback chain:
__bpf_prog_put_rcu()
bpf_prog_free()
schedule_work()
bpf_prog_free_deferred()
bpf_prog_kallsyms_del_all()
In between, __bpf_prog_put_rcu() has already done:
btf_put(aux->btf);
kvfree(aux->jited_linfo);
kvfree(aux->linfo);
kvfree(aux->func_info);
kfree(aux->func_info_aux);
and bpf_prog_free() has dropped aux->dst_prog and aux->token.
Can a tree reader that runs after the grace period but before
bpf_prog_free_deferred() still get the prog from bpf_prog_ksym_find() and
then dereference those fields? For example:
dump_stack_cb()
bpf_prog_get_file_line()
prog->aux->btf, prog->aux->linfo, prog->aux->jited_linfo
The final free of aux and of the JIT images does look to be behind the
second grace period from queue_rcu_work(), so the exposure would only cover
the fields freed in __bpf_prog_put_rcu().
Looking at the callers of bpf_prog_ksym_find() that go past the ksym
fields (search_bpf_extables(), dump_stack_cb(), find_from_stack_cb(),
bpf_stack_walker(), bpf_prog_report_arena_violation()), they resolve
either the IP of a frame on the current stack through arch_bpf_stack_walk()
or the faulting IP. In both cases the program is still running, so the
grace period chosen in __bpf_prog_put_noref() should not have finished.
The name-only readers (bpf_address_lookup(), bpf_get_kallsym(),
is_bpf_text_address(), bpf_has_frame_pointer()) read only aux->ksym, which
stays valid until the extra grace period. I did not find a reader that
reaches the freed linfo or btf for a program that is not running.
Is the ordering of call_rcu() before the ksym removal intended, given that
the pattern of queueing an RCU callback on an object that is still
reachable through an RCU-protected structure is normally treated as a bug?
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/39051545464