非Root用户运行eBPF Hello World时.rodata map冻结失败求助
问题解决与非Root用户eBPF Hello World实现
问题根源分析
你遇到的hello.rodata map创建失败问题,本质是非特权用户默认缺少创建只读数据段map的权限,即便启用了非特权eBPF功能,内核仍会对部分map操作做权限限制。以下是具体解决步骤:
解决步骤
1. 配置内核参数(必须)
确保系统已启用非特权eBPF支持,并放开相关限制:
# 启用非特权eBPF sudo sysctl -w kernel.unprivileged_bpf_disabled=0 # 允许非特权用户访问系统BTF信息(加载带CO-RE的程序需要) sudo sysctl -w kernel.bpf_unprivileged_override_btf=1 # 可选:启用eBPF JIT编译提升性能 sudo sysctl -w net.core.bpf_jit_enable=1
2. 调整用户权限
将当前用户加入bpf和tracing组,获得BPF资源访问和trace文件系统权限:
sudo usermod -aG bpf $USER sudo usermod -aG tracing $USER
执行后重新登录使组权限生效。
3. 修改用户态加载代码
在bpf_object__load前,遍历并调整hello.rodata map的标志位,去掉非特权用户不允许的只读限制:
// 在bpf_object__open_file之后添加 struct bpf_map *map; bpf_object__for_each_map(map, obj) { if (strcmp(bpf_map__name(map), "hello.rodata") == 0) { // 移除特权级只读/只写标志 map->def.map_flags &= ~(BPF_F_RDONLY_PROG | BPF_F_WRONLY_PROG); // 添加可mmap标志(非特权用户创建map的必要条件) map->def.map_flags |= BPF_F_MMAPABLE; } }
完整非Root用户eBPF Hello World实现
1. 环境准备(内核5.10+)
安装编译依赖:
sudo apt install clang libbpf-dev linux-tools-common linux-headers-$(uname -r)
2. eBPF程序(hello.bpf.c)
#include "vmlinux.h" #include <bpf_helpers.h> SEC("tracepoint/syscalls/sys_enter_execve") int tracepoint__syscalls__sys_enter_execve(struct trace_event_raw_sys_enter *ctx) { bpf_printk("Hello from unprivileged eBPF!\n"); return 0; } char LICENSE[] SEC("license") = "GPL";
3. 用户态加载程序(hello.c)
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/resource.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <bpf/libbpf.h> #include <bpf/bpf.h> void read_trace_pipe(void) { int trace_fd = open("/sys/kernel/debug/tracing/trace_pipe", O_RDONLY); if (trace_fd < 0) { fprintf(stderr, "Failed to open trace_pipe\n"); return; } char buf[4096]; while (1) { ssize_t sz = read(trace_fd, buf, sizeof(buf)-1); if (sz > 0) { buf[sz] = '\0'; puts(buf); } } } int main(void) { struct rlimit rlim = { .rlim_cur = 512UL << 20, .rlim_max = 512UL << 20, }; if (setrlimit(RLIMIT_MEMLOCK, &rlim) != 0) { perror("setrlimit"); return 1; } struct bpf_object *obj = bpf_object__open_file("hello.bpf.o", NULL); if (!obj) { fprintf(stderr, "Failed to open BPF object\n"); return 1; } // 调整rodata map权限 struct bpf_map *map; bpf_object__for_each_map(map, obj) { if (strcmp(bpf_map__name(map), "hello.rodata") == 0) { map->def.map_flags &= ~(BPF_F_RDONLY_PROG | BPF_F_WRONLY_PROG); map->def.map_flags |= BPF_F_MMAPABLE; } } if (bpf_object__load(obj) != 0) { perror("bpf_object__load"); bpf_object__close(obj); return 1; } struct bpf_program *prog = bpf_object__find_program_by_name(obj, "tracepoint__syscalls__sys_enter_execve"); if (!prog) { fprintf(stderr, "Failed to find program\n"); bpf_object__close(obj); return 1; } if (bpf_program__attach(prog) != 0) { perror("bpf_program__attach"); bpf_object__close(obj); return 1; } read_trace_pipe(); bpf_object__close(obj); return 0; }
4. 编译运行
# 编译eBPF程序 clang -target bpf -D__TARGET_ARCH_x86_64 -I/usr/include/x86_64-linux-gnu -I. -O2 -c hello.bpf.c -o hello.bpf.o # 编译用户态程序 gcc hello.c -o hello -lbpf -lelf -lz # 普通用户直接运行 ./hello
打开新终端执行ls等命令,即可看到trace_pipe输出的eBPF日志。
内容的提问来源于stack exchange,提问作者urd00m
相关产品推荐
相关产品推荐

