记一次bpf_probe_read_user_str
和bpf_probe_read_str
的区别。
bpf_probe_read_user_str
用于从用户空间地址读取字符串,会自动处理用户空间和内核空间的地址隔离问题;而 bpf_probe_read_str
用于从内核空间地址读取字符串,适合处理内核数据结构中的字段或 eBPF map 中的内存。简单来说,_user_str
是专为用户空间数据设计的,而 _str
适用于内核空间数据。
代码:https://github.com/CeerDecy/study-ebpf/tree/main/03-trace-open-exit
优先发布:https://etov.cloud/index.php/2025/01/bpf_probe_read_str/
具体可以参考如下例子:
bpf_probe_read_user_str
我们可以用这个函数来读取tracepoint中函数的参数。其中ctx上下文就是来自于用户空间的数据,args[1]
代表的是sys_enter_openat
函数中第二个参数(即文件名称),使用bpf_probe_read_user_str
即可读取到OpenFile结构体变量中。
SEC("tracepoint/syscalls/sys_enter_openat")
int tracepoint__syscalls__sys_enter_openat(struct trace_event_raw_sys_enter *ctx) {
struct OpenFile of = {};
if (bpf_probe_read_user_str(of.filename, sizeof(of.filename), (const char *)ctx->args[1]) < 0) {
return 0;
}
...
}
bpf_probe_read_str
这个函数可以用来读取eBPF map中的数据,因为eBPF map是处于内核空间的,所以这里就需要使用第二个函数。
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1024);
__type(key, u32);
__type(value, struct OpenFile);
} dict SEC(".maps");
SEC("tracepoint/syscalls/sys_exit_openat")
int tracepoint__syscalls__sys_exit_openat(struct trace_event_raw_sys_exit *ctx) {
...
struct OpenFile *of;
struct Event *e;
of = bpf_map_lookup_elem(&dict, &pid);
if (bpf_probe_read_str(&e->filename, sizeof(e->filename), of->filename) < 0) {
return 0;
}
...
}