c-将数据从用户空间发送到带有映射的bpf程序时出现问题



我的bpf程序有问题。加载此程序时出错。我的bpf程序是:

#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <uapi/linux/bpf.h>
#include <linux/version.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <linux/fs.h>
#include <uapi/asm-generic/errno-base.h>
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key,   int);
__type(value, ino_t);
__uint(max_entries, 256);
} qu SEC(".maps");

SEC("lsm/task_kill")
BPF_PROG(
lsm__task_kill,
struct task_struct* p, 
struct kernel_siginfo* info,
int sig,
const struct cred* cred
) {
int key = 0;
int* my_pid = bpf_map_lookup_elem(&qu, &key);
if (*my_pid == 3935991) {
return -EPERM;
}

bpf_ringbuf_output(&rb, &data, sizeof(data), 0);
return 0;
}

这是我的用户程序:

#include <bpf/bpf.h>
#include <unistd.h>
#include <string.h>
#include <sys/syscall.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/version.h>
#include <linux/perf_event.h>
#include <linux/hw_breakpoint.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <bpf/libbpf.h>
#include <time.h>

int main(
int         argc, 
const char* argv[]
) {
if (argc <= 1) {
return -1;
}

struct stat stat_buf = {0};
int ret = stat(argv[1], &stat_buf);
if (ret == -1) {
printf("ERROR: resolving pathname failed: %sn", strerror(errno));
return -1;
}
struct bpf_object *obj = bpf_object__open("./my_prog.o");
if (libbpf_get_error(obj)) {
fprintf(stderr, "ERROR: opening BPF object file failedn");
return 0;
}
bpf_object__load(obj);
if (libbpf_get_error(obj)) {
fprintf(stderr, "ERROR: opening BPF object file failedn");
return 0;
}
int qfd = bpf_object__find_map_fd_by_name(obj, "qu");
if (qfd < 0) {
fprintf(stderr, "ERROR: finding a queue in obj file failedn");
return -1;
}
int val = stat_buf.st_ino;
int key = 0;
ret = bpf_map_update_elem(qfd, &key, &val, BPF_ANY);
if (ret < 0) {
printf("ERROR: updating map failedn");
return -1;
}


struct bpf_link*    links[1];
struct bpf_program* prog;
int j = 0;
bpf_object__for_each_program(prog, obj) {
links[j] = bpf_program__attach_lsm(prog);
if (libbpf_get_error(links[j])) {
fprintf(stderr, "ERROR: bpf_program__attach failedn");
links[j] = NULL;
return -1;
}
j++;
}

}

制作bpf对象文件和编译用户程序时没有错误,但当我运行用户程序时,我在加载bpf程序时遇到了这个错误:

user@host:~$ sudo ./my_prog_loader ./some_file
libbpf: elf: skipping unrecognized data section(22) .eh_frame
libbpf: elf: skipping relo section(23) .rel.eh_frame for section(22) .eh_frame
libbpf: load bpf program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf: 
R1 type=ctx expected=fp
; BPF_PROG(
0: (b7) r6 = 0
; Data data = {0};
1: (7b) *(u64 *)(r10 -8) = r6
last_idx 1 first_idx 0
regs=40 stack=0 before 0: (b7) r6 = 0
2: (7b) *(u64 *)(r10 -16) = r6
3: (7b) *(u64 *)(r10 -24) = r6
4: (7b) *(u64 *)(r10 -32) = r6
5: (bf) r1 = r10
6: (07) r1 += -16
; bpf_get_current_comm(data.str, 16);
7: (b7) r2 = 16
8: (85) call bpf_get_current_comm#16
last_idx 8 first_idx 0
regs=4 stack=0 before 7: (b7) r2 = 16
; data.pid  = 000000;
9: (63) *(u32 *)(r10 -32) = r6
; int key = 0;
10: (63) *(u32 *)(r10 -36) = r6
11: (bf) r2 = r10
; 
12: (07) r2 += -36
; ino_t* my_pid = bpf_map_lookup_elem(&qu, &key);
13: (18) r1 = 0xffff8fa64edafc00
15: (85) call bpf_map_lookup_elem#1
; if (*my_pid == 3935991) {
16: (79) r1 = *(u64 *)(r0 +0)
R0 invalid mem access 'map_value_or_null'
processed 16 insns (limit 1000000) max_states_per_insn 0 total_states 1 peak_states 1 mark_read 1
libbpf: -- END LOG --
libbpf: failed to load program 'lsm__task_kill'
libbpf: failed to load object './my_prog.o'
ERROR: finding a map in obj file failed
user@host:~$_

为什么我会出现这个错误,我该怎么办??谢谢你的帮助!

TL;DR。您应该检查bpf_map_lookup_elem返回的指针是否为NULL。


使用以下日志,BPF验证器会告诉您,当它到达my_pid的解引用时,指针可能仍然具有NULL值。因此,它包含映射值或NULL值,即map_value_or_null

; ino_t* my_pid = bpf_map_lookup_elem(&qu, &key);
13: (18) r1 = 0xffff8fa64edafc00
15: (85) call bpf_map_lookup_elem#1
; if (*my_pid == 3935991) {
16: (79) r1 = *(u64 *)(r0 +0)
R0 invalid mem access 'map_value_or_null'

每当找不到查找到的密钥时,bpf_map_lookup_elem都会返回一个NULL值。

你可以简单地做这样的事情:

if (my_pid && *my_pid == 3935991) {
return -EPERM;
}

最新更新