0x1:技术背景
bpf:
BPF 的全称是 Berkeley Packet Filter,是一个用于过滤(filter)网络报文(packet)的架构。(例如tcpdump),目前称为Cbpf(Classical bpf)
Ebpf:
eBPF全称 extended BPF,Linux Kernel 3.15 中引入的全新设计, 是对既有BPF架构进行了全面扩展,一方面,支持了更多领域的应用,比如:内核追踪(Kernel Tracing)、应用性能调优/监控、流控(Traffic Control)等;另一方面,在接口的设计以及易用性上,也有了较大的改进。
eBPF 支持在用户态将 C 语言编写的一小段“内核代码”注入到内核中运行,注入时要先用 llvm 编译得到使用 BPF 指令集的 ELF 文件,然后从 ELF 文件中解析出可以注入内核的部分,最后用 bpf_load_program() 方法完成注入。 用户态程序和注入到内核中的程序通过共用一个位于内核的 eBPF MAP 实现通信。为了防止注入的代码导致内核崩溃,eBPF 会对注入的代码进行严格检查,拒绝不合格的代码的注入。
- eBPF prog load的严格的verify机制
- eBPF访问内核资源需借助各种eBPF 的helper func,helper func函数能在最坏的情况下保证安全
- 现在,Linux 内核只运行 eBPF,内核会将加载的 cBPF 字节码 透明地转换成 eBPF 再执行
0x2:技术对比
优劣 | eBPF | 源码开发 | 热补丁 |
---|---|---|---|
优势 | 1.安全,不会引起宕机 2.自主,可控 2.热加载(良好的加载/卸载流程) 3.开启CO-RE后,移植性高,适配量小 4.可以在注入的代码中写入业务逻辑,优化hids性能 5.开发难度低,上手快 |
1.体积小 2.*度高 3.性能高 4.功能强大 |
1.体积小 2.*度高 3.性能高 4.热加载,不需要重启 |
缺点 | 1.功能受限(验证器) 2.强依赖于内核版本 3.不支持内核函数调用 4.单函数最大512byte栈空间,通过尾调用扩展到8K 5.性能不如其他两者 |
1.需要重新编译内核 2.需要重启业务主机 3.需要开发者熟悉内核 4.适配工作量巨大 上发数据有性能瓶颈 |
1.需要开发者熟悉内核 2.适配工作量大 |
0x3:运行流程
用 C 编写 BPF 程序
用 LLVM 将 C 程序编译成对象文件(ELF)
用户空间 BPF ELF 加载器(例如 libbpf)解析对象文件
加载器通过 bpf() 系统调用将解析后的对象文件注入内核
内核验证 BPF 指令,然后对其执行即时编译(JIT),返回程序的一个新文件描述符
利用文件描述符 attach 到内核