android ebpf中CO-RE的学习

发布时间 2023-10-31 14:23:34作者: 怎么可以吃突突

CO-RE原理

因为不同的内核版本的系统内部结构体会有差异,例如struct user_arg_ptr,当内核编译配置中存在CONFIG_COMPAT=y的时候,会在native成员之前增加一个布尔变量is_compat,这样native的偏移就发生的变化。

如果编写的ebpf内核程序需要访问struct user_arg_ptr类型的变量就需要考虑在不同内核版本上的兼容问题,即一次编译到处运行(CO-RE)。libbpf提供CO-RE的支持,libbpf程序编译的时候依赖特定内核的vmlinux.h头文件(通过bpftool btf dump file /sys/kernel/btf/vmlinux format c生成),这个头文件中包含了内核中所有结构体信息,这些结构体的成员偏移都是固定的。

当编译ebpf程序生成字节码的时候,libbpfCO-RE接口函数借助clang通过__builtin_preserve_access_index记录成员的偏移量。

ebpf字节码加载到内存之前,libbpf会从运行系统的btf文件/sys/kernel/btf/vmlinux中获取实际的内核结构体信息并进行解析,之后对ebpf字节码中的结构体引用进行重定位,这样ebpf就可以获取内核结构体正确的偏移。只有系统内核编译的时候打开CONFIG_DEBUG_INFO_BTF=y才会生成对应的btf文件,否则就需要通过其他方法提取btf文件并重编译libbpf增加对自提取btf文件的加载。

CO-RE使用

这里以bcc中提供的libbpf-tools为例,libbpf-toolsbcc为了支持CO-RE依赖与libbpf编写的一些和bcc tool功能类似的小工具。其中execsnoop通过SEC("tracepoint/syscalls/sys_entry_execve")SEC("tracepoint/syscalls/sys_entry_execveat")execve/execveat系统调用进行hook,因为大多数android设备都没有打开CONFIG_FTRACE_SYSCALLS=y配置,所以并不支持syscalls类型的tracepoint

这里利用kprobe/kretprobe对原程序进行改写,从而能在未开启CONFIG_FTRACE_SYSCALLS=y的设备上运行。这里hook的是do_execveat_common,因为execve/execveat系统调用最后都会调用此函数,并且此函数是导出的。这里注意是struct user_arg_ptrnative成员保存了argv命令行参数指针,struct user_arg_ptr类型变量作为参数传递给do_execveat_common函数。

这里需要注意gcc/clang编译器在编译时,如果函数调用传递的参数是一个结构体,其会将此结构体所有的成员作为单个的参数进行传递,而windows平台的MSVC编译器则是将结构体先拷贝到目标函数栈空间中,然后将对应栈空间中结构体的地址作为参数进行传递。

因为我这里内核配置有CONFIG_COMPAT=y,所以struct user_arg_ptr类型的native成员前有个布尔类型的成员is_compat,那么对应的is_compat就是do_execveat_common函数的第三个参数,native就是第四个参数(没配置CONFIG_COMPAT=y就是第三个参数)。利用libbpf的CO-RE支持函数bpf_core_field_exists可以判断某个成员是否存在,从而判断是取第三个参数还是第四个参数。

最后通过bpf_prob_read_user读取对应的命令行参数

do_execveat_common函数的第二个参数是filename类型的指针,其成员name指向对应可执行文件的全路径。虽然filename在各个linux内核中的结构差异不大,但是为了安全最好所有的内核结构访问都使用libbpfCO-RE支持函数。

如果访问filename类型的name成员不适用CO-RE支持函数,那么就使用bpf_probe_read_kernel,默认为namefilename结构中的偏移为0

如果使用libbpfCO-RE支持函数bpf_core_read访问

这里name就是一个指针,所以可以直接使用bpf_core_read,对于结构体多层嵌套的情况可以使用BPF_CORE_READ访问

最后通过bpf_probe_read_kernel_strname内核指针中读取可执行文件全路径

android平台运行的效果如下

代码已上传github:https://github.com/revercc/libbpf-bootstrap-for-android.git

参考:
https://mp.weixin.qq.com/s/zOgwwvVSMlEQzRXse3SBhw
https://github.com/iovisor/bcc.git