将 eBPF 附加到 KPROBE?
Attaching eBPF to KPROBE?
我写了一个简单的程序来附加到带有 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(用户 space 加载程序):
#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;
}
和生成文件:
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
。
在您的 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
,否则你的输出会很乱),但结果是none您包含的文件包含此助手的定义。
bpf_trace_printk()
被编译为内核的一部分,永远不会被编译到你的 BPF object 文件中。当尝试加载您的程序时,函数 load_bpf_file()
执行重定位步骤,它将 数字 关联到 bpf_trace_printk()
(在用户 API 中) eBPF字节码的相关指令。
但它需要在某处找到这个号码。它在 header linux/bpf.h
(从你的几个包含中拉出)中定义为 FN(trace_printk)
(一些宏魔术正在进行),导致 de facto一个#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;
- 或添加包含它的 header,例如tools/lib/bpf/bpf_helpers.h 在内核仓库中。在你的情况下:
#include <bpf/bpf_helpers.h>
(请注意,此 header 在编译 libbpf 时为 generated,默认情况下它不存在于存储库中。)
我写了一个简单的程序来附加到带有 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(用户 space 加载程序):
#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;
}
和生成文件:
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
。
在您的 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
,否则你的输出会很乱),但结果是none您包含的文件包含此助手的定义。
bpf_trace_printk()
被编译为内核的一部分,永远不会被编译到你的 BPF object 文件中。当尝试加载您的程序时,函数 load_bpf_file()
执行重定位步骤,它将 数字 关联到 bpf_trace_printk()
(在用户 API 中) eBPF字节码的相关指令。
但它需要在某处找到这个号码。它在 header linux/bpf.h
(从你的几个包含中拉出)中定义为 FN(trace_printk)
(一些宏魔术正在进行),导致 de facto一个#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;
- 或添加包含它的 header,例如tools/lib/bpf/bpf_helpers.h 在内核仓库中。在你的情况下:
(请注意,此 header 在编译 libbpf 时为 generated,默认情况下它不存在于存储库中。)#include <bpf/bpf_helpers.h>