C 错误:无效的mem访问';inv&x27;使用bpf_探头_读取_*()
问题是: 我正在编写一个BPF程序,使用kprobe探测C 错误:无效的mem访问';inv&x27;使用bpf_探头_读取_*(),c,linux,bpf,ebpf,C,Linux,Bpf,Ebpf,问题是: 我正在编写一个BPF程序,使用kprobe探测vfs\u read()内核函数: ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) 使用类型为BPF\u map\u type\u HASH的映射收集相关信息(在*文件中)。BPF程序(kern.c)的代码如下: #define __KERNEL__ #define __TARGET_ARCH_x86 #include &
vfs\u read()
内核函数:
ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
使用类型为BPF\u map\u type\u HASH
的映射收集相关信息(在*文件中)。BPF程序(kern.c
)的代码如下:
#define __KERNEL__
#define __TARGET_ARCH_x86
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
struct data {
char filename[16];
u32 pid;
char comm[16];
};
struct bpf_map_def SEC("maps") my_map = {
.type = BPF_MAP_TYPE_HASH,
.key_size = sizeof(u64),
.value_size = sizeof(struct data),
.max_entries = 120
};
SEC("kprobe/vfs_read")
int vfs_read_probe(struct pt_regs *ctx)
{
struct data value = {};
struct file *f = (struct file *)PT_REGS_PARM1(ctx);
struct dentry *de = f->f_path.dentry;
struct qstr d_name = de->d_name;
bpf_probe_read_kernel_str(&value.filename, sizeof(value.filename), d_name.name);
u64 key = bpf_ktime_get_coarse_ns();
value.pid = (u32)bpf_get_current_pid_tgid();
bpf_get_current_comm(&value.comm, sizeof(value.comm));
bpf_map_update_elem(&my_map, &key, &value, BPF_ANY);
return 0;
}
char _license[] SEC("license") = "GPL";
该代码使用以下方法编译:
clang -O2 -target bpf -c kern.c -o kern.o
下面是用于加载kern.o
的用户空间程序(user.c
):
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/resource.h>
#include <bpf/libbpf.h>
#include <bpf/bpf.h>
struct data {
char filename[16];
unsigned int pid;
char comm[16];
};
static int fd;
static void handler(int sig)
{
unsigned long long key = 0, next_key;
struct data value;
while (bpf_map_get_next_key(fd, &key, &next_key) == 0) {
bpf_map_lookup_elem(fd, &next_key, &value);
printf("Key: %llx, Next Key: %llx, PID: %d, COMM: %s, file: %s\n", key, next_key, value.pid, value.comm, value.filename);
key = next_key;
}
exit(0);
}
int main()
{
struct bpf_object *obj;
struct bpf_program *prog;
struct bpf_link *link;
struct rlimit rlim = {
.rlim_cur = RLIM_INFINITY,
.rlim_max = RLIM_INFINITY
};
if(setrlimit(RLIMIT_MEMLOCK, &rlim)) {
fprintf(stderr, "ERROR adjusting memlock limit\n");
goto cleanup;
}
char path[] = "kern.o";
obj = bpf_object__open(path);
if (libbpf_get_error(obj)) {
fprintf(stderr, "ERROR: opening BPF object file failed\n");
obj = NULL;
goto cleanup;
}
prog = bpf_object__find_program_by_title(obj, "kprobe/vfs_read");
if (bpf_object__load(obj)) {
fprintf(stderr, "ERROR: loading BPF object file failed\n");
goto cleanup;
}
link = bpf_program__attach(prog);
fd = bpf_object__find_map_fd_by_name(obj, "my_map");
signal(SIGINT, handler);
printf("Press ^C to stop\n");
sleep(99999);
bpf_link__destroy(link);
bpf_object__close(obj);
return 0;
cleanup:
bpf_link__destroy(link);
bpf_object__close(obj);
return -1;
}
经过一些分析,我发现只要我不使用bpf\u probe\u read*()
和朋友,并将一个值硬编码到data.filename
,一切都很好
我使用的是Archlinux内核5.12.9-zen1-1-zen
如何正确获取文件名?谢谢你的帮助 您需要使用bpf\u probe\u read
来解除对内核指针的引用。
因此,要读取d_name
的代码应该如下所示:
struct dentry de;
struct qstr d_name;
bpf_probe_read_kernel_str(&de, sizeof(struct dentry), &f->f_path.dentry);
bpf_probe_read_kernel_str(&d_name, sizeof(struct qstr), &de->d_name);
解释。
此处需要使用bpf\u probe\u read
帮助程序,因为必须在运行时检查解除引用的内存地址,以避免由于无效内存访问而导致崩溃
或者,您可以使用BPF CO-RE依赖BTF在运行时之前使用BTF类型信息执行检查。有关更多信息,请参阅。谢谢!代码的另一个问题是我不确定vfs_read()是否真的与常规文件有关。。。
libbpf: load bpf program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r2 = 0
1: (63) *(u32 *)(r10 -8) = r2
last_idx 1 first_idx 0
regs=4 stack=0 before 0: (b7) r2 = 0
2: (7b) *(u64 *)(r10 -16) = r2
3: (7b) *(u64 *)(r10 -24) = r2
4: (7b) *(u64 *)(r10 -32) = r2
5: (7b) *(u64 *)(r10 -40) = r2
6: (79) r1 = *(u64 *)(r1 +112)
7: (79) r1 = *(u64 *)(r1 +24)
R1 invalid mem access 'inv'
processed 8 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 'vfs_read_probe'
libbpf: failed to load object 'kern.o'
ERROR: loading BPF object file failed
struct dentry de;
struct qstr d_name;
bpf_probe_read_kernel_str(&de, sizeof(struct dentry), &f->f_path.dentry);
bpf_probe_read_kernel_str(&d_name, sizeof(struct qstr), &de->d_name);