使用tracepoint/syscalls/sys_enter_execve获取argv时参数丢失求助
解决eBPF读取execve argv参数偶尔丢失的问题
问题原因
你当前的代码直接将用户空间的字符串指针传递给bpf_printk,但bpf_printk的%s格式要求指针指向内核空间内存。用户空间的内存可能因页置换、进程地址空间切换或权限限制,导致内核无法稳定读取到字符串内容,从而出现参数偶尔丢失的情况。
修复方案
需要先通过bpf_probe_read_user将用户空间的字符串拷贝到内核缓冲区,再打印缓冲区内容。同时优化循环逻辑,读到argv[i]为NULL时终止循环,避免无效读取。
修改后的task.c代码:
//go:build ignore #include "common.h" #include "bpf_helpers.h" char _license[] SEC("license") = "GPL"; struct execve { __u64 unused; __u32 nr; const char *filename; const char *const *argv; const char *const *envp; }; SEC("tracepoint/syscalls/sys_enter_execve") int sys_enter_execve(struct execve *ctx) { for (int i = 0; i < 10; i++) { const char *arg_ptr = NULL; // 读取argv数组中的第i个指针 if (bpf_probe_read_user(&arg_ptr, sizeof(arg_ptr), &ctx->argv[i])) break; if (!arg_ptr) break; // 遇到NULL终止符,停止循环 char buf[64] = {0}; // 将用户空间字符串拷贝到内核缓冲区 bpf_probe_read_user(buf, sizeof(buf)-1, arg_ptr); bpf_printk("arg%d: %s ", i, buf); } bpf_printk("\n"); return 0; }
关键改动说明
- 内核缓冲区拷贝:新增
char buf[64]作为内核本地缓冲区,先把用户空间的字符串内容拷贝到这里,再传递给bpf_printk,确保读取的是稳定的内核内存。 - 错误处理:检查
bpf_probe_read_user的返回值,读取失败时直接终止循环,避免无效操作。 - 终止条件优化:当
arg_ptr为NULL时(即argv数组的结束符),停止循环,减少不必要的系统开销。
这个方案也适用于kprobe/sys_execve的场景,原理完全一致——必须将用户空间数据拷贝到内核后再处理,不能直接引用用户空间指针。
内容的提问来源于stack exchange,提问作者HIHIA
相关产品推荐
相关产品推荐

