* [PATCH] libbpf: poison unresolved weak kfuncs in light skeletons
@ 2026-06-22 23:04 Siddharth Nayyar
2026-06-22 23:48 ` bot+bpf-ci
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Siddharth Nayyar @ 2026-06-22 23:04 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis
Cc: bpf, linux-kernel, Giuliano Procida, Matthias Maennich,
Tiffany Yang, Neill Kapron, Siddharth Nayyar
When the light skeleton generator (gen_loader) fails to find a BTF ID
for a weak kfunc, it correctly clears the immediate value (imm = 0) to
convert the pseudo kfunc call into an invalid instruction.
However, the generator fails to clear src_reg (which is set to
BPF_PSEUDO_KFUNC_CALL). This leaves the instruction looking like a valid
pseudo kfunc call with a zero BTF ID. When the target verifier's
add_subprog_and_kfunc encounters this, it unconditionally scans all
BPF_PSEUDO_KFUNC_CALL instructions, sees imm == 0, and panics or
fails the load (e.g. bpf_unspec#0 or -EINVAL). This entirely breaks
the verifier's dead-code elimination logic which expects to cleanly prune
branches protected by bpf_ksym_exists().
Furthermore, when the generator processes subsequent references to the
same unresolved weak kfunc, it copies the imm and off fields from
the first occurrence but skips the src_reg field, meaning subsequent
calls also retain the poisonous BPF_PSEUDO_KFUNC_CALL flag.
This patch fixes the issue by explicitly clearing src_reg for both the
initial occurrence and all subsequent occurrences of unresolved weak
kfuncs, converting them into standard invalid helper calls that the
verifier's dead-code eliminator can safely recognize and discard.
Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
---
tools/lib/bpf/gen_loader.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/tools/lib/bpf/gen_loader.c b/tools/lib/bpf/gen_loader.c
index d79695f01c87..a08071114347 100644
--- a/tools/lib/bpf/gen_loader.c
+++ b/tools/lib/bpf/gen_loader.c
@@ -783,10 +783,17 @@ static void emit_relo_kfunc_btf(struct bpf_gen *gen, struct ksym_relo_desc *relo
return;
/* try to copy from existing bpf_insn */
if (kdesc->ref > 1) {
- move_blob2blob(gen, insn + offsetof(struct bpf_insn, imm), 4,
- kdesc->insn + offsetof(struct bpf_insn, imm));
move_blob2blob(gen, insn + offsetof(struct bpf_insn, off), 2,
kdesc->insn + offsetof(struct bpf_insn, off));
+ move_blob2blob(gen, insn + offsetof(struct bpf_insn, imm), 4,
+ kdesc->insn + offsetof(struct bpf_insn, imm));
+ /*
+ * jump over src_reg adjustment if imm (btf_id) is not 0, reuse BPF_REG_0 from
+ * move_blob2blob. If btf_id is zero, clear BPF_PSEUDO_KFUNC_CALL flag in src_reg
+ * of call insn.
+ */
+ emit(gen, BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1));
+ emit(gen, BPF_ST_MEM(BPF_B, BPF_REG_8, 1, 0));
goto log;
}
/* remember insn offset, so we can copy BTF ID and FD later */
@@ -804,10 +811,12 @@ static void emit_relo_kfunc_btf(struct bpf_gen *gen, struct ksym_relo_desc *relo
}
kdesc->off = btf_fd_idx;
/* jump to success case */
- emit(gen, BPF_JMP_IMM(BPF_JSGE, BPF_REG_7, 0, 3));
+ emit(gen, BPF_JMP_IMM(BPF_JSGE, BPF_REG_7, 0, 4));
/* set value for imm, off as 0 */
emit(gen, BPF_ST_MEM(BPF_W, BPF_REG_8, offsetof(struct bpf_insn, imm), 0));
emit(gen, BPF_ST_MEM(BPF_H, BPF_REG_8, offsetof(struct bpf_insn, off), 0));
+ /* clear src_reg (and dst_reg) to convert pseudo kfunc call into invalid helper call */
+ emit(gen, BPF_ST_MEM(BPF_B, BPF_REG_8, 1, 0));
/* skip success case for ret < 0 */
emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0, 10));
/* store btf_id into insn[insn_idx].imm */
---
base-commit: e771677c937da5808f7b6c1f0e4a97ec1a84f8a8
change-id: 20260622-bpf-lskel-fixes-2-758036ae9911
Best regards,
--
Siddharth Nayyar <sidnayyar@google.com>
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH] libbpf: poison unresolved weak kfuncs in light skeletons
2026-06-22 23:04 [PATCH] libbpf: poison unresolved weak kfuncs in light skeletons Siddharth Nayyar
@ 2026-06-22 23:48 ` bot+bpf-ci
2026-06-25 18:36 ` Yonghong Song
2026-06-26 0:45 ` Alexei Starovoitov
2 siblings, 0 replies; 5+ messages in thread
From: bot+bpf-ci @ 2026-06-22 23:48 UTC (permalink / raw)
To: sidnayyar, ast, daniel, andrii, eddyz87, memxor, martin.lau, song,
yonghong.song, jolsa, emil
Cc: bpf, linux-kernel, gprocida, maennich, ynaffit, nkapron,
sidnayyar, ast, andrii, daniel, martin.lau, eddyz87,
yonghong.song, clm, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 1831 bytes --]
> libbpf: poison unresolved weak kfuncs in light skeletons
>
> When the light skeleton generator (gen_loader) fails to find a BTF ID
> for a weak kfunc, it correctly clears the immediate value (imm = 0) to
> convert the pseudo kfunc call into an invalid instruction.
>
> However, the generator fails to clear src_reg (which is set to
> BPF_PSEUDO_KFUNC_CALL). This leaves the instruction looking like a valid
> pseudo kfunc call with a zero BTF ID. When the target verifier's
> add_subprog_and_kfunc encounters this, it unconditionally scans all
> BPF_PSEUDO_KFUNC_CALL instructions, sees imm == 0, and panics or
> fails the load (e.g. bpf_unspec#0 or -EINVAL). This entirely breaks
> the verifier's dead-code elimination logic which expects to cleanly prune
> branches protected by bpf_ksym_exists().
>
> Furthermore, when the generator processes subsequent references to the
> same unresolved weak kfunc, it copies the imm and off fields from
> the first occurrence but skips the src_reg field, meaning subsequent
> calls also retain the poisonous BPF_PSEUDO_KFUNC_CALL flag.
>
> This patch fixes the issue by explicitly clearing src_reg for both the
> initial occurrence and all subsequent occurrences of unresolved weak
> kfuncs, converting them into standard invalid helper calls that the
> verifier's dead-code eliminator can safely recognize and discard.
>
> Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
This looks like a bug fix for the light skeleton generator. Should this
include:
Fixes: 18f4fccbf314 ("libbpf: Update gen_loader to emit BTF_KIND_FUNC relocations")
---
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/27990767350
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] libbpf: poison unresolved weak kfuncs in light skeletons
2026-06-22 23:04 [PATCH] libbpf: poison unresolved weak kfuncs in light skeletons Siddharth Nayyar
2026-06-22 23:48 ` bot+bpf-ci
@ 2026-06-25 18:36 ` Yonghong Song
2026-06-26 0:45 ` Alexei Starovoitov
2 siblings, 0 replies; 5+ messages in thread
From: Yonghong Song @ 2026-06-25 18:36 UTC (permalink / raw)
To: Siddharth Nayyar, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
Martin KaFai Lau, Song Liu, Jiri Olsa, Emil Tsalapatis
Cc: bpf, linux-kernel, Giuliano Procida, Matthias Maennich,
Tiffany Yang, Neill Kapron
On 6/22/26 4:04 PM, Siddharth Nayyar wrote:
> When the light skeleton generator (gen_loader) fails to find a BTF ID
> for a weak kfunc, it correctly clears the immediate value (imm = 0) to
> convert the pseudo kfunc call into an invalid instruction.
>
> However, the generator fails to clear src_reg (which is set to
> BPF_PSEUDO_KFUNC_CALL). This leaves the instruction looking like a valid
> pseudo kfunc call with a zero BTF ID. When the target verifier's
> add_subprog_and_kfunc encounters this, it unconditionally scans all
> BPF_PSEUDO_KFUNC_CALL instructions, sees imm == 0, and panics or
> fails the load (e.g. bpf_unspec#0 or -EINVAL). This entirely breaks
> the verifier's dead-code elimination logic which expects to cleanly prune
> branches protected by bpf_ksym_exists().
>
> Furthermore, when the generator processes subsequent references to the
> same unresolved weak kfunc, it copies the imm and off fields from
> the first occurrence but skips the src_reg field, meaning subsequent
> calls also retain the poisonous BPF_PSEUDO_KFUNC_CALL flag.
>
> This patch fixes the issue by explicitly clearing src_reg for both the
> initial occurrence and all subsequent occurrences of unresolved weak
> kfuncs, converting them into standard invalid helper calls that the
> verifier's dead-code eliminator can safely recognize and discard.
>
> Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
Acked-by: Yonghong Song <yonghong.song@linux.dev>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] libbpf: poison unresolved weak kfuncs in light skeletons
2026-06-22 23:04 [PATCH] libbpf: poison unresolved weak kfuncs in light skeletons Siddharth Nayyar
2026-06-22 23:48 ` bot+bpf-ci
2026-06-25 18:36 ` Yonghong Song
@ 2026-06-26 0:45 ` Alexei Starovoitov
2026-06-26 16:29 ` Sid Nayyar
2 siblings, 1 reply; 5+ messages in thread
From: Alexei Starovoitov @ 2026-06-26 0:45 UTC (permalink / raw)
To: Siddharth Nayyar
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, bpf, LKML,
Giuliano Procida, Matthias Maennich, Tiffany Yang, Neill Kapron
On Mon, Jun 22, 2026 at 4:04 PM Siddharth Nayyar <sidnayyar@google.com> wrote:
>
> When the light skeleton generator (gen_loader) fails to find a BTF ID
> for a weak kfunc, it correctly clears the immediate value (imm = 0) to
> convert the pseudo kfunc call into an invalid instruction.
>
> However, the generator fails to clear src_reg (which is set to
> BPF_PSEUDO_KFUNC_CALL). This leaves the instruction looking like a valid
> pseudo kfunc call with a zero BTF ID. When the target verifier's
> add_subprog_and_kfunc encounters this, it unconditionally scans all
> BPF_PSEUDO_KFUNC_CALL instructions, sees imm == 0, and panics or
> fails the load (e.g. bpf_unspec#0 or -EINVAL). This entirely breaks
> the verifier's dead-code elimination logic which expects to cleanly prune
> branches protected by bpf_ksym_exists().
>
> Furthermore, when the generator processes subsequent references to the
> same unresolved weak kfunc, it copies the imm and off fields from
> the first occurrence but skips the src_reg field, meaning subsequent
> calls also retain the poisonous BPF_PSEUDO_KFUNC_CALL flag.
>
> This patch fixes the issue by explicitly clearing src_reg for both the
> initial occurrence and all subsequent occurrences of unresolved weak
> kfuncs, converting them into standard invalid helper calls that the
> verifier's dead-code eliminator can safely recognize and discard.
>
> Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
> ---
> tools/lib/bpf/gen_loader.c | 15 ++++++++++++---
> 1 file changed, 12 insertions(+), 3 deletions(-)
>
> diff --git a/tools/lib/bpf/gen_loader.c b/tools/lib/bpf/gen_loader.c
> index d79695f01c87..a08071114347 100644
> --- a/tools/lib/bpf/gen_loader.c
> +++ b/tools/lib/bpf/gen_loader.c
> @@ -783,10 +783,17 @@ static void emit_relo_kfunc_btf(struct bpf_gen *gen, struct ksym_relo_desc *relo
> return;
> /* try to copy from existing bpf_insn */
> if (kdesc->ref > 1) {
> - move_blob2blob(gen, insn + offsetof(struct bpf_insn, imm), 4,
> - kdesc->insn + offsetof(struct bpf_insn, imm));
> move_blob2blob(gen, insn + offsetof(struct bpf_insn, off), 2,
> kdesc->insn + offsetof(struct bpf_insn, off));
> + move_blob2blob(gen, insn + offsetof(struct bpf_insn, imm), 4,
> + kdesc->insn + offsetof(struct bpf_insn, imm));
why did you change the order?
Looks like an unrelated change.
pw-bot: cr
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] libbpf: poison unresolved weak kfuncs in light skeletons
2026-06-26 0:45 ` Alexei Starovoitov
@ 2026-06-26 16:29 ` Sid Nayyar
0 siblings, 0 replies; 5+ messages in thread
From: Sid Nayyar @ 2026-06-26 16:29 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, bpf, LKML,
Giuliano Procida, Matthias Maennich, Tiffany Yang, Neill Kapron
On Fri, Jun 26, 2026 at 1:46 AM Alexei Starovoitov
<alexei.starovoitov@gmail.com> wrote:
>
> On Mon, Jun 22, 2026 at 4:04 PM Siddharth Nayyar <sidnayyar@google.com> wrote:
> >
> > --- a/tools/lib/bpf/gen_loader.c
> > +++ b/tools/lib/bpf/gen_loader.c
> > @@ -783,10 +783,17 @@ static void emit_relo_kfunc_btf(struct bpf_gen *gen, struct ksym_relo_desc *relo
> > return;
> > /* try to copy from existing bpf_insn */
> > if (kdesc->ref > 1) {
> > - move_blob2blob(gen, insn + offsetof(struct bpf_insn, imm), 4,
> > - kdesc->insn + offsetof(struct bpf_insn, imm));
> > move_blob2blob(gen, insn + offsetof(struct bpf_insn, off), 2,
> > kdesc->insn + offsetof(struct bpf_insn, off));
> > + move_blob2blob(gen, insn + offsetof(struct bpf_insn, imm), 4,
> > + kdesc->insn + offsetof(struct bpf_insn, imm));
>
> why did you change the order?
> Looks like an unrelated change.
Changing the order leaves the value of imm (rather than off) in
BPF_REG_0, which the next instruction consumes when checking if this
value is zero. If I don't do this we will need extra instructions to
load the value of imm before we can check if it is zero.
I hinted this in the comment just after the move_blob2blob() calls by
stating "reuse BPF_REG_0 from move_blob2blob". Please let me know if
this is unclear, I will expand the commentary if necessary.
Regards,
Siddharth Nayyar
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-06-26 16:29 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-22 23:04 [PATCH] libbpf: poison unresolved weak kfuncs in light skeletons Siddharth Nayyar
2026-06-22 23:48 ` bot+bpf-ci
2026-06-25 18:36 ` Yonghong Song
2026-06-26 0:45 ` Alexei Starovoitov
2026-06-26 16:29 ` Sid Nayyar
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.