与使用空间共享 ebpf 函数参数或至少访问参数
Posted
技术标签:
【中文标题】与使用空间共享 ebpf 函数参数或至少访问参数【英文标题】:sharing ebpf function parameters with usespace or atleast accessing parameters 【发布时间】:2022-01-20 23:01:07 【问题描述】:我有这个我正在尝试做的 ebpf 程序。基本上,我正在捕获recvfrom
函数调用并尝试将我的recvfrom
缓冲区共享给我的用户空间应用程序。这是代码:
SEC("kprobe/__x64_sys_recvfrom")
int bpf_prog1(struct pt_regs *ctx,int fd, const char *buf, size_t count)
struct S
int pid;
char cookie[90];
data=1,"";
//data.pid =count;// bpf_get_current_pid_tgid();
//if(buf==NULL)
// memcpy(data.cookie,buf,20);
// data.cookie[0]=buf[0];
bpf_get_current_comm(&data.cookie, sizeof(data.cookie));
int i=0;
bpf_perf_event_output(ctx, &my_map, 1, &data, sizeof(data));
return 0;
所以,我似乎有bpf_prog function
的签名,其中我有来自recvfrom
函数的缓冲区,但是当我尝试访问它时,我根本无法访问它,因为我的程序正在加载抱怨。
root@this:/home/ubuntu/Desktop/ebpf/Linux-exFilter-main/pkg/probe/bpf# ./trace
libbpf: load bpf program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
R1 type=ctx expected=fp
; int bpf_prog1(struct pt_regs *ctx,int fd, const char *buf, size_t count)
0: (bf) r6 = r1
1: (b7) r1 = 0
; data=1,"";
2: (7b) *(u64 *)(r10 -8) = r1
last_idx 2 first_idx 0
regs=2 stack=0 before 1: (b7) r1 = 0
3: (7b) *(u64 *)(r10 -16) = r1
4: (7b) *(u64 *)(r10 -24) = r1
5: (7b) *(u64 *)(r10 -32) = r1
6: (7b) *(u64 *)(r10 -40) = r1
7: (7b) *(u64 *)(r10 -48) = r1
8: (7b) *(u64 *)(r10 -56) = r1
9: (7b) *(u64 *)(r10 -64) = r1
10: (7b) *(u64 *)(r10 -72) = r1
11: (b7) r1 = 1
12: (63) *(u32 *)(r10 -96) = r1
; memcpy(data.cookie,buf,20);
13: (71) r4 = *(u8 *)(r3 +1)
R3 !read_ok
processed 14 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
libbpf: -- END LOG --
libbpf: failed to load program 'bpf_prog1'
libbpf: failed to load object './kprobe_send.o'
ERROR: loading BPF object file failed
还有一个像bpf_get_current_comm(&data.cookie, sizeof(data.cookie));
和bpf_perf_event_output(ctx, &my_map, 1, &data, sizeof(data));
这样的函数,使用这些函数会给我垃圾数据。所以我想知道如何读取 ebpf 程序中的函数参数。有没有传统的方法呢
我知道 ebpf 有地图,地图用于在 ebpf 程序和用户空间应用程序之间共享信息。共享参数是一个基本的东西,但我不知道为什么我在网上没有看到它
【问题讨论】:
And there is a function like bpf_get_current_comm(&data.cookie, sizeof(data.cookie)); and bpf_perf_event_output(ctx, &my_map, 1, &data, sizeof(data)); and use of these functions giving me garbage data
访问 buf 失败,因为访问 buf 代码 .o 未加载
【参考方案1】:
您可以使用PT_REGS_PARM macros 读取recvfrom
的参数,在本例中为PT_REGS_PARM2(ctx)
。这是来自tracex4 示例的示例:
SEC("kprobe/kmem_cache_free")
int bpf_prog1(struct pt_regs *ctx)
long ptr = PT_REGS_PARM2(ctx);
bpf_map_delete_elem(&my_map, &ptr);
return 0;
对于recvfrom
,第二个参数应该是指向缓冲区的指针:
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
要从内核到用户空间进行通信,您确实需要一个映射。您会注意到您对bpf_perf_event_output
的调用也需要一个指向地图的指针:&my_map
。
bpf_perf_event_output
辅助函数需要BPF_MAP_TYPE_PERF_EVENT_ARRAY
类型的映射才能运行。但与大多数地图类型不同,这种地图类型的工作方式类似于从 eBPF 程序到用户空间的单向数据流。
我相信您的代码松散地基于内核中的trace_output_kern 示例。你会注意到他们在这里也定义了一个地图:
struct
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
__uint(key_size, sizeof(int));
__uint(value_size, sizeof(u32));
__uint(max_entries, 2);
my_map SEC(".maps");
【讨论】:
在recvfrom函数的情况下是否应该将此行long ptr = PT_REGS_PARM2(ctx);
更改为char *ptr = PT_REGS_PARM2(ctx);
。因为 recvfrom 的第二个参数是 char *buf。而且时间不长。你能告诉我吗
libbpf: failed to find BTF for extern 'PT_REGS_PARM2': -2
我出错了
libbpf: failed to find BTF for extern 'PT_REGS_PARM2': -2
这个函数存在于我的系统 /usr/include/bpf/tracing.h` 文件中。但是运行我的用户空间程序会抛出这个错误,它失败了 2 找到 PT_REGS_PARM2 函数。为什么会这样。在这个链接上,它说它与一些 ubuntu 符号链接和 trace
有问题,Missing header error while trying to run...
github.com/iovisor/kubectl-trace/issues/76 .. 任何想法,自从我开始研究 ebpf 以来,这些错误越来越多地出现我从内核源代码编译样本
ever since I started looking into ebpf these error are appearing more and more as I compile samples from..
我有 libbpf 并且我有内核头文件,但是为什么我的 clang -target -bpf
命令没有将这些 libbpf 函数链接到我编译并使用命令 clang -O2 -Wall -g -target bpf -c kprobe_send.c -o kprobe_send.o
链接的程序我知道我遗漏了一些东西大到阻止我用 libbpf 函数编译和运行 ebpf 程序。我确保我确实有 libbpf。那么在编译和链接clang -target bpf
程序时,我需要注意clang 使用的一些符号链接吗?
编译时可以在clang命令中添加-D__TARGET_ARCH_x86
来指定以上是关于与使用空间共享 ebpf 函数参数或至少访问参数的主要内容,如果未能解决你的问题,请参考以下文章