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: %s\n", 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 failed\n");
return 0;
}
bpf_object__load(obj);
if (libbpf_get_error(obj)) {
fprintf(stderr, "ERROR: opening BPF object file failed\n");
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 failed\n");
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 failed\n");
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 failed\n");
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;博士。您应该检查返回的指针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;
}
推荐阅读
- python - 比较文件名并将它们添加到 python 的列表中
- docker - windows 7 docker虚拟盒连接问题
- r - 如何在R中按多个时间范围过滤?
- c# - 将单个 .xaml 文件添加到解决方案时,VSTO 外接程序不再编译
- typescript - Typescript 中展开运算符的属性选择
- azure-devops - 根据计划将不同的参数值传递给 Azure DevOps Pipeline
- mysql - 按订单类型过滤产品
- postgresql - 每个语句插入前的 PostgreSQL 触发器
- date - 昨天的日期在颤抖
- javascript - 在 django 模板中的 js 的 Swiper 功能中创建了重复的元素(产品)