与使用空间共享 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 函数参数或至少访问参数的主要内容,如果未能解决你的问题,请参考以下文章

匿名函数内置函数与模块

C++入门基础

C++命名空间与缺省参数

C++命名空间与缺省参数

C++命名空间与缺省参数

匿名函数及其使用