[PATCH v3] kernel/bpf/btf.c: reject to register duplicated kfunc

Song Chen posted 1 patch 9 hours ago
kernel/bpf/btf.c | 44 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 43 insertions(+), 1 deletion(-)
[PATCH v3] kernel/bpf/btf.c: reject to register duplicated kfunc
Posted by Song Chen 9 hours ago
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>
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.

[1]:https://lore.kernel.org/all/CAADnVQ+jYGMjAC9aNygmhyppUO9foWN4z9cjSpwCEXAFHpRVJQ@mail.gmail.com/
---
 kernel/bpf/btf.c | 44 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 43 insertions(+), 1 deletion(-)

diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 4872d2a6c42d..a14ad3720872 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -8618,6 +8618,47 @@ 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;
+	int ret = 0;
+
+	if (!btf_is_module(btf))
+		goto out;
+
+	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);
+		ret = -EINVAL;
+		goto out;
+	}
+
+#ifdef CONFIG_DEBUG_INFO_BTF_MODULES
+	mutex_lock(&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);
+			ret = -EINVAL;
+			break;
+		}
+	}
+	mutex_unlock(&btf_module_mutex);
+#endif
+
+out:
+	return ret;
+}
+
 static int btf_check_kfunc_protos(struct btf *btf, u32 func_id, u32 func_flags)
 {
 	const struct btf_type *func;
@@ -8631,7 +8672,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
Re: [PATCH v3] kernel/bpf/btf.c: reject to register duplicated kfunc
Posted by bot+bpf-ci@kernel.org 8 hours ago
> diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
> index 17d4ab0a8206..425c9f5c64fa 100644
> --- a/kernel/bpf/btf.c
> +++ b/kernel/bpf/btf.c
> @@ -8673,6 +8673,47 @@ 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;
> +	int ret = 0;
> +
> +	if (!btf_is_module(btf))
> +		goto out;

During v2 review, Alexei Starovoitov suggested a different approach: instead
of rejecting duplicate kfunc registration, he proposed allowing module kfuncs
to override kernel kfuncs, similar to livepatching. He stated: "imo that's a
more interesting use case than helping out-of-tree module to produce nicier
error" and "I'm not convinced that we should be doing it... because ^^^ is
what I think we should be doing instead."

The author requested implementation guidance on how the override mechanism
would determine which kfunc to call, but received no maintainer response.

Should this implementation be reconsidered? The current approach rejects
duplicates, but the maintainer's feedback indicated preference for an
override/livepatching mechanism instead.

Reference: https://lore.kernel.org/bpf/CAADnVQJEjhJH6+2cLJ0jM_fZ366oU3yoK1b5aMk=VgksXhJtoQ@mail.gmail.com/

> +
> +	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);
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +#ifdef CONFIG_DEBUG_INFO_BTF_MODULES
> +	mutex_lock(&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);
> +			ret = -EINVAL;
> +			break;
> +		}
> +	}
> +	mutex_unlock(&btf_module_mutex);
> +#endif
> +
> +out:
> +	return ret;
> +}
> +
>  static int btf_check_kfunc_protos(struct btf *btf, u32 func_id, u32 func_flags)
>  {
>  	const struct btf_type *func;
> @@ -8686,7 +8727,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);

---
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/26356787905
Re: [PATCH v3] kernel/bpf/btf.c: reject to register duplicated kfunc
Posted by Alexei Starovoitov 8 hours ago
On Sun, May 24, 2026 at 11:15 AM <bot+bpf-ci@kernel.org> wrote:
>
> > diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
> > index 17d4ab0a8206..425c9f5c64fa 100644
> > --- a/kernel/bpf/btf.c
> > +++ b/kernel/bpf/btf.c
> > @@ -8673,6 +8673,47 @@ 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;
> > +     int ret = 0;
> > +
> > +     if (!btf_is_module(btf))
> > +             goto out;
>
> During v2 review, Alexei Starovoitov suggested a different approach: instead
> of rejecting duplicate kfunc registration, he proposed allowing module kfuncs
> to override kernel kfuncs, similar to livepatching. He stated: "imo that's a
> more interesting use case than helping out-of-tree module to produce nicier
> error" and "I'm not convinced that we should be doing it... because ^^^ is
> what I think we should be doing instead."
>
> The author requested implementation guidance on how the override mechanism
> would determine which kfunc to call, but received no maintainer response.
>
> Should this implementation be reconsidered?

It was considered and I said later to defer this idea for now.
AI should consider the whole discussion thread instead of immediate replies.
I guess in this case the threads were broken into multiple
due to different subjects.

Song,
in the future please try to use one subject.

Also "kernel/bpf/btf.c:" is not a valid prefix.
I will fix it up while applying when trees are ffwded after pending PR.