• Runqing Yang's avatar
    libbpf: Fix a bug with checking bpf_probe_read_kernel() support in old kernels · d252a4a4
    Runqing Yang authored
    Background:
    Libbpf automatically replaces calls to BPF bpf_probe_read_{kernel,user}
    [_str]() helpers with bpf_probe_read[_str](), if libbpf detects that
    kernel doesn't support new APIs. Specifically, libbpf invokes the
    probe_kern_probe_read_kernel function to load a small eBPF program into
    the kernel in which bpf_probe_read_kernel API is invoked and lets the
    kernel checks whether the new API is valid. If the loading fails, libbpf
    considers the new API invalid and replaces it with the old API.
    
    static int probe_kern_probe_read_kernel(void)
    {
    	struct bpf_insn insns[] = {
    		BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),	/* r1 = r10 (fp) */
    		BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8),	/* r1 += -8 */
    		BPF_MOV64_IMM(BPF_REG_2, 8),		/* r2 = 8 */
    		BPF_MOV64_IMM(BPF_REG_3, 0),		/* r3 = 0 */
    		BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_probe_read_kernel),
    		BPF_EXIT_INSN(),
    	};
    	int fd, insn_cnt = ARRAY_SIZE(insns);
    
    	fd = bpf_prog_load(BPF_PROG_TYPE_KPROBE, NULL,
                               "GPL", insns, insn_cnt, NULL);
    	return probe_fd(fd);
    }
    
    Bug:
    On older kernel versions [0], the kernel checks whether the version
    number provided in the bpf syscall, matches the LINUX_VERSION_CODE.
    If not matched, the bpf syscall fails. eBPF However, the
    probe_kern_probe_read_kernel code does not set the kernel version
    number provided to the bpf syscall, which causes the loading process
    alwasys fails for old versions. It means that libbpf will replace the
    new API with the old one even the kernel supports the new one.
    
    Solution:
    After a discussion in [1], the solution is using BPF_PROG_TYPE_TRACEPOINT
    program type instead of BPF_PROG_TYPE_KPROBE because kernel does not
    enfoce version check for tracepoint programs. I test the patch in old
    kernels (4.18 and 4.19) and it works well.
    
      [0] https://elixir.bootlin.com/linux/v4.19/source/kernel/bpf/syscall.c#L1360
      [1] Closes: https://github.com/libbpf/libbpf/issues/473Signed-off-by: default avatarRunqing Yang <rainkin1993@gmail.com>
    Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
    Link: https://lore.kernel.org/bpf/20220409144928.27499-1-rainkin1993@gmail.com
    d252a4a4
libbpf.c 332 KB