kernel/bpf/btf.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-)
I had an ebpf program which calls a kfunc defined and
implemented in one of my kernel modules, it was working
fine in 6.16, but was rejected to run by libbpf in 6.19,
the error message was:
libbpf: extern (func ksym) 'bpf_strstr': func_proto [5]
incompatible with vmlinux [94389]
The reason is there is a new added kfunc in kernel 6.19
which happens to be the same name with my kfunc. However the
error message is not obvious enough to address problem
immediately.
Therefore, this patches searches duplicated kfunc in
both btf_vmlinux and btf_modules list before a kernel module
attempts to register kfuncs through register_btf_kfunc_id_set,
it prints clear error message and returns error code if same name
kfunc has already implemented and registered, then developer
knows at the first place.
Suggested-by: Alexei Starovoitov <alexei.starovoitov@gmail.com>
Suggested-by: Kaitao Cheng <kaitao.cheng@linux.dev>
Suggested-by: Leon Hwang <leon.hwang@linux.dev>
Reviewed-by: Yonghong Song <yonghong.song@linux.dev>
Signed-off-by: Song Chen <chensong_2000@126.com>
---
changelog:
v1 --- v2:
libbpf has already specified which module this kfunc belongs to as
ebpf code onwer's expectation, then verifier uses
find_kallsyms_symbol_value to search kfunc's addr.
v2 --- v3:
After v2, I tried a new idea of introducing a namespace in libbpf
to specify kfunc owner in an ebpf program suggested by Kaitao Cheng,
please see [1]. Alex suggested to go back to report an error during
kmod load on conflicting kfunc name for now. What's more, v2 only
searched bpf_vmlinux, v3 also traverses btf_modules list.
v3 --- v4
Fixed some coding style problems suggested from Kaitao Cheng.
v4 --- v5
Use indentation plus space in multiple lines suggested from Yonghong Song.
Use guard(mutex) suggested from Leon Hwang.
---
kernel/bpf/btf.c | 36 +++++++++++++++++++++++++++++++++++-
1 file changed, 35 insertions(+), 1 deletion(-)
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 4872d2a6c42d..f34a210e03c0 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -8618,6 +8618,39 @@ static int btf_check_iter_kfuncs(struct btf *btf, const char *func_name,
return 0;
}
+static int btf_check_kfunc_name(struct btf *btf, const char *func_name, u32 kind)
+{
+#ifdef CONFIG_DEBUG_INFO_BTF_MODULES
+ struct btf_module *btf_mod, *tmp;
+#endif
+ s32 id;
+
+ if (!btf_is_module(btf))
+ return 0;
+
+ id = btf_find_by_name_kind(bpf_get_btf_vmlinux(), func_name, kind);
+ if (id >= 0) {
+ pr_err("kfunc %s (id: %d) is already present in vmlinux.\n",
+ func_name, id);
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_DEBUG_INFO_BTF_MODULES
+ guard(mutex)(&btf_module_mutex);
+ list_for_each_entry_safe(btf_mod, tmp, &btf_modules, list) {
+ if (btf_mod->btf == btf)
+ continue;
+ id = btf_find_by_name_kind(btf_mod->btf, func_name, kind);
+ if (id >= 0) {
+ pr_err("kfunc %s (id: %d) is already present in module %s.\n",
+ func_name, id, btf_mod->module->name);
+ return -EINVAL;
+ }
+ }
+#endif
+ return 0;
+}
+
static int btf_check_kfunc_protos(struct btf *btf, u32 func_id, u32 func_flags)
{
const struct btf_type *func;
@@ -8631,7 +8664,8 @@ static int btf_check_kfunc_protos(struct btf *btf, u32 func_id, u32 func_flags)
/* sanity check kfunc name */
func_name = btf_name_by_offset(btf, func->name_off);
- if (!func_name || !func_name[0])
+ if (!func_name || !func_name[0] ||
+ btf_check_kfunc_name(btf, func_name, BTF_INFO_KIND(func->info)))
return -EINVAL;
func = btf_type_by_id(btf, func->type);
--
2.43.0
> diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
> index 68921d9172b5..03fca4902cbd 100644
> --- a/kernel/bpf/btf.c
> +++ b/kernel/bpf/btf.c
> @@ -8757,6 +8757,39 @@ static int btf_check_iter_kfuncs(struct btf *btf, const char *func_name,
> return 0;
> }
>
> +static int btf_check_kfunc_name(struct btf *btf, const char *func_name, u32 kind)
> +{
> +#ifdef CONFIG_DEBUG_INFO_BTF_MODULES
> + struct btf_module *btf_mod, *tmp;
> +#endif
> + s32 id;
> +
> + if (!btf_is_module(btf))
> + return 0;
> +
> + id = btf_find_by_name_kind(bpf_get_btf_vmlinux(), func_name, kind);
> + if (id >= 0) {
> + pr_err("kfunc %s (id: %d) is already present in vmlinux.\n",
> + func_name, id);
> + return -EINVAL;
> + }
Since btf_find_by_name_kind() matches any BTF_KIND_FUNC entry, can this
falsely reject a kfunc registration whose name happens to match an
unrelated internal or static function in vmlinux rather than a function
that was actually registered as a kfunc?
With CONFIG_DEBUG_INFO_BTF, the vmlinux BTF contains all global and
static functions, not only registered kfuncs.
> +
> +#ifdef CONFIG_DEBUG_INFO_BTF_MODULES
> + guard(mutex)(&btf_module_mutex);
> + list_for_each_entry_safe(btf_mod, tmp, &btf_modules, list) {
> + if (btf_mod->btf == btf)
> + continue;
> + id = btf_find_by_name_kind(btf_mod->btf, func_name, kind);
> + if (id >= 0) {
> + pr_err("kfunc %s (id: %d) is already present in module %s.\n",
> + func_name, id, btf_mod->module->name);
> + return -EINVAL;
> + }
> + }
The same question applies to the per-module scan, which walks btf_modules
and matches against every function in each module's BTF.
Could this introduce a load-order dependency between unrelated modules?
For example, if module A has a static function 'foo' and module B
registers a kfunc named 'foo', module B's registration would fail when A
is loaded first, but succeed if B is loaded first.
A module's BTF is also added to btf_modules at MODULE_STATE_COMING,
before module init calls register_btf_kfunc_id_set, so could concurrent
module loading expose raw BTF early enough to cause spurious failures
here?
Would it be more robust to check against the actually registered kfunc
sets rather than against all BTF_KIND_FUNC entries in vmlinux and every
module?
This was raised by an automated review on both the v4 and v5 postings
but does not appear to have been responded to:
https://lore.kernel.org/bpf/20260603093823.B11CE1F00893@smtp.kernel.org/
> +#endif
> + return 0;
> +}
> +
---
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/26876238212
© 2016 - 2026 Red Hat, Inc.