lkml.org 
[lkml]   [2022]   [Jun]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.18 073/879] libbpf: Fix a bug with checking bpf_probe_read_kernel() support in old kernels
    Date
    From: Runqing Yang <rainkin1993@gmail.com>

    [ Upstream commit d252a4a499a07bec21c65873f605c3a1ef52ffed ]

    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/473

    Signed-off-by: Runqing Yang <rainkin1993@gmail.com>
    Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
    Link: https://lore.kernel.org/bpf/20220409144928.27499-1-rainkin1993@gmail.com
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    tools/lib/bpf/libbpf.c | 2 +-
    1 file changed, 1 insertion(+), 1 deletion(-)

    diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
    index 809fe209cdcc..dabf9a1451c3 100644
    --- a/tools/lib/bpf/libbpf.c
    +++ b/tools/lib/bpf/libbpf.c
    @@ -4587,7 +4587,7 @@ static int probe_kern_probe_read_kernel(void)
    };
    int fd, insn_cnt = ARRAY_SIZE(insns);

    - fd = bpf_prog_load(BPF_PROG_TYPE_KPROBE, NULL, "GPL", insns, insn_cnt, NULL);
    + fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", insns, insn_cnt, NULL);
    return probe_fd(fd);
    }

    --
    2.35.1


    \
     
     \ /
      Last update: 2022-06-08 00:12    [W:2.920 / U:0.444 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site