Re: [PATCH v2] libbpf: poison unresolved weak kfuncs in light skeletons

From: Andrii Nakryiko

Date: Mon Jul 27 2026 - 19:27:41 EST


On Wed, Jul 22, 2026 at 4:41 AM Siddharth Nayyar <sidnayyar@xxxxxxxxxx> 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

panics? as in can crash the kernel? overstatement or it's actually that bad?

> fails the load (e.g. bpf_unspec#0 or -EINVAL). This entirely breaks

also, I think we intentionally do not fail for kfunc with btf ID zero
eagerly, so if subsequent dead code elimination logic proves this
instruction is unreachable, it should be ignored anyways.

can you please double check, this sounds suspicious. invalid helper vs
invalid kfunc call shouldn't matter much (and if it does, we should
fix *that*)

pw-bot: cr


> 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.
>
> Fixes: 18f4fccbf314 ("libbpf: Update gen_loader to emit BTF_KIND_FUNC relocations")
> Signed-off-by: Siddharth Nayyar <sidnayyar@xxxxxxxxxx>
> Acked-by: Yonghong Song <yonghong.song@xxxxxxxxx>
> ---
> Changes in v2:
> - Rebased and added Fixes and Acked-by tags
> - Link to v1: https://lore.kernel.org/r/20260622-bpf-lskel-fixes-2-v1-1-004d72cba5c2@xxxxxxxxxx
> ---
> 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: 248951ddc14de84de3910f9b13f51491a8cd91df
> change-id: 20260622-bpf-lskel-fixes-2-758036ae9911
>
> Best regards,
> --
> Siddharth Nayyar <sidnayyar@xxxxxxxxxx>
>