与 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");
我正在尝试执行此 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");