与 usespace 或至少访问参数共享 ebpf 函数参数

sharing ebpf function parameters with usespace or atleast accessing parameters

我正在尝试执行此 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 程序和用户空间应用程序之间共享信息。共享参数是一个基本的东西,但我不知道为什么我在互联网上没有看到它

您可以使用 PT_REGS_PARM macros, in this case PT_REGS_PARM2(ctx). This is an example from the tracex4 示例读取 recvfrom 的参数:

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");