【问题标题】:Attaching eBPF to KPROBE?将 eBPF 附加到 KPROBE?
【发布时间】:2020-07-16 13:36:05
【问题描述】:

我编写了一个简单的程序来使用 kprobe 附加到 execve 系统调用,但我无法看到相关的输出。

这是我的 one.c(BPF 程序):

#include <errno.h>
#include <bpf/bpf.h>
#include <stdio.h>
#include <string.h>

#include "bpf_load.h"
#include "bpf_util.h"
#include "libbpf.h"

#define SEC(NAME) __attribute__((section(NAME), used))

SEC("kprobe/execve")
int bpf_prog1(struct pt_regs *ctx)
{
        char m[]="hello world";
        bpf_trace_printk(m,sizeof(m));
        
        return 0;
}

char _license[] SEC("license") = "GPL";

bpf_load.c(用户空间加载器):

#include "bpf_load.h"
#include <stdio.h>

#include <linux/bpf.h>
#include <sys/resource.h>

int main(int argc, char **argv) {
    if (load_bpf_file("one.o")) {
        printf("%s", bpf_log_buf);
        return 1;
    }
    return 0;
}

还有 Makefile:

CLANG = clang

EXECABLE = monitor-exec

BPFCODE = one

BPFTOOLS = /kernel-src/samples/bpf
BPFLOADER = $(BPFTOOLS)/bpf_load.c

INCLUDE += -I/kernel-src/samples/bpf
INCLUDE += -I/kernel-src/tools/lib

CCINCLUDE += -I/kernel-src/tools/testing/selftests/bpf
CCINCLUDE += -I/kernel-src/tools/lib/bpf
CCINCLUDE += ${INCLUDE}

LOADINCLUDE += -I/kernel-src/tools/include
LOADINCLUDE += -I/kernel-src/tools/perf
LOADINCLUDE += ${INCLUDE}
LIBRARY_PATH = -L/usr/local/lib64
BPFSO = -lbpf

.PHONY: clean bpfload build

clean:
    rm -f *.o *.so $(EXECABLE)

build: ${BPFCODE.c} ${BPFLOADER}
    $(CLANG) -O2 -DHAVE_ATTR_TEST=0 -target bpf -c $(BPFCODE:=.c) $(CCINCLUDE) -o ${BPFCODE:=.o}

bpfload: build
    clang -o $(EXECABLE) -DHAVE_ATTR_TEST=0  -lelf $(LOADINCLUDE) $(LIBRARY_PATH) $(BPFSO) \
        $(BPFLOADER) loader.c

$(EXECABLE): bpfload

.DEFAULT_GOAL := $(EXECABLE)

到目前为止,我没有从 Makefile 中得到任何错误。

当我执行./monitor-exec时得到以下输出

invalid relo for insn[6].code 0x85
bpf_load_program() err=22
last insn is not an exit or jmp
processed 0 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
last insn is not an exit or jmp
processed 0 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0

我无法理解我做错了什么。我只是附加了一个 kprobe,当该系统调用发生时,它应该打印 hello world

【问题讨论】:

  • 您的程序从哪里选择bpf_trace_printk() 的定义?当 libbpf 尝试对您的目标文件执行重定位时,它似乎不知道在哪里找到它。
  • 那我该怎么办?我是新手..所以据我了解bpf_trace_printk() 定义不在我的程序中,对吗?
  • 我不确定,因为它可能在您包含的文件之一中。但是您可以尝试在您的 BPF 程序文件中手动添加它:static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) = (void *) BPF_FUNC_trace_printk;(这将声明基于 linux/bpf.h 中定义的 BPF_FUNC_trace_printk 枚举成员的函数,我认为包含在 bpf/bpf.h 中)。
  • 好的,谢谢....我还有一个问题failed to create kprobe 'execve' error 'No such file or directory' ,如何知道在kprobe/ 或其他类似uprobe、tracepoint 之后支持的所有系统调用类型...
  • 几乎所有内核函数都可以被追踪(只要它们在编译时没有被内联)。您可能想检查sudo cat /proc/kallsyms|grep execve 之类的可用符号。尽管对于系统调用,我们通常建议使用跟踪点而不是 kprobes,因为它们更稳定(在内核版本之间)。在您的情况下,您可以使用一个名为 sys_enter_execve 的跟踪点。

标签: linux bpf ebpf


【解决方案1】:

在您的 eBPF 程序中:

#include <errno.h>
#include <bpf/bpf.h>
#include <stdio.h>
#include <string.h>

#include "bpf_load.h"
#include "bpf_util.h"
#include "libbpf.h"

#define SEC(NAME) __attribute__((section(NAME), used))

SEC("kprobe/execve")
int bpf_prog1(struct pt_regs *ctx)
{
        char m[]="hello world";
        bpf_trace_printk(m,sizeof(m));
        
        return 0;
}

您正确使用了bpf_trace_printk()(尽管您可能想在消息末尾添加\n,否则您的输出会很混乱),但事实证明您包含的所有文件都不包含此帮助程序的定义.

bpf_trace_printk() 被编译为内核的一部分,永远不会编译到你的 BPF 目标文件中。在尝试加载程序时,函数load_bpf_file() 执行重定位步骤,它将与bpf_trace_printk()(在用户API 中)关联的数字 放在eBPF 字节码的相关指令中。

但它需要在某个地方找到这个数字。它在标题linux/bpf.h(从您的几个包含中提取)中定义为FN(trace_printk)(一些宏魔术正在发生),导致#define BPF_FUNC_trace_prink 6 事实上。但是你需要告诉你的加载函数它对应于你正在调用的bpf_trace_prink()

两种解决方案:

  • 手动声明它:
    static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) =
            (void *) BPF_FUNC_trace_printk;
    
  • 或者添加一个包含它的标题,例如内核 repo 中的 tools/lib/bpf/bpf_helpers.h。在你的情况下:
    #include <bpf/bpf_helpers.h>
    
    (请注意,编译 libbpf 时此标头为 generated,默认情况下它不存在于存储库中。)

【讨论】:

    猜你喜欢
    • 2021-08-18
    • 1970-01-01
    • 2019-04-22
    • 2021-12-28
    • 1970-01-01
    • 2022-11-18
    • 2023-02-22
    • 2019-11-30
    • 1970-01-01
    相关资源
    最近更新 更多