libbpf: Store zero fd to fd_array for loader kfunc relocation
authorJiri Olsa <jolsa@kernel.org>
Mon, 15 May 2023 13:37:47 +0000 (15:37 +0200)
committerAlexei Starovoitov <ast@kernel.org>
Wed, 17 May 2023 05:09:23 +0000 (22:09 -0700)
When moving some of the test kfuncs to bpf_testmod I hit an issue
when some of the kfuncs that object uses are in module and some
in vmlinux.

The problem is that both vmlinux and module kfuncs get allocated
btf_fd_idx index into fd_array, but we store to it the BTF fd value
only for module's kfunc, not vmlinux's one because (it's zero).

Then after the program is loaded we check if fd_array[btf_fd_idx] != 0
and close the fd.

When the object has kfuncs from both vmlinux and module, the fd from
fd_array[btf_fd_idx] from previous load will be stored in there for
vmlinux's kfunc, so we close unrelated fd (of the program we just
loaded in my case).

Fixing this by storing zero to fd_array[btf_fd_idx] for vmlinux
kfuncs, so the we won't close stale fd.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Link: https://lore.kernel.org/r/20230515133756.1658301-2-jolsa@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
tools/lib/bpf/gen_loader.c

index 83e8e3bfd8ff3d14543613709933a7186f9ae71e..cf3323fd47b88630a375e79c64b46d77270f85a3 100644 (file)
@@ -703,17 +703,17 @@ static void emit_relo_kfunc_btf(struct bpf_gen *gen, struct ksym_relo_desc *relo
        /* obtain fd in BPF_REG_9 */
        emit(gen, BPF_MOV64_REG(BPF_REG_9, BPF_REG_7));
        emit(gen, BPF_ALU64_IMM(BPF_RSH, BPF_REG_9, 32));
-       /* jump to fd_array store if fd denotes module BTF */
-       emit(gen, BPF_JMP_IMM(BPF_JNE, BPF_REG_9, 0, 2));
-       /* set the default value for off */
-       emit(gen, BPF_ST_MEM(BPF_H, BPF_REG_8, offsetof(struct bpf_insn, off), 0));
-       /* skip BTF fd store for vmlinux BTF */
-       emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0, 4));
        /* load fd_array slot pointer */
        emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_0, BPF_PSEUDO_MAP_IDX_VALUE,
                                         0, 0, 0, blob_fd_array_off(gen, btf_fd_idx)));
-       /* store BTF fd in slot */
+       /* store BTF fd in slot, 0 for vmlinux */
        emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_9, 0));
+       /* jump to insn[insn_idx].off store if fd denotes module BTF */
+       emit(gen, BPF_JMP_IMM(BPF_JNE, BPF_REG_9, 0, 2));
+       /* set the default value for off */
+       emit(gen, BPF_ST_MEM(BPF_H, BPF_REG_8, offsetof(struct bpf_insn, off), 0));
+       /* skip BTF fd store for vmlinux BTF */
+       emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0, 1));
        /* store index into insn[insn_idx].off */
        emit(gen, BPF_ST_MEM(BPF_H, BPF_REG_8, offsetof(struct bpf_insn, off), btf_fd_idx));
 log: