该篇文章是rbpf虚拟机验证器代码块功能的整理。
(学习该虚拟机的目的是为了搞懂solana合约的执行方式,solana使用的rbpf是在该虚拟机上进行扩展。)
这个 eBPF 验证器是在 eBPF 程序加载到虚拟机(VM)时执行的简单检查工具,与 Linux 内核中更复杂的验证器不同。它不涉及程序流控制(应为有向无环图)或寄存器使用一致性等深入检查。
什么是rbpf虚拟机?
RBPF虚拟机是一种基于Rust语言开发的轻量级虚拟机,用于执行BPF(Berkeley Packet Filter)程序。BPF是一种在内核中执行过滤和转发网络数据包的技术,RBPF虚拟机可以用来模拟和执行这些BPF程序,以实现网络数据包的快速过滤和处理。RBPF虚拟机通过提供一个安全的执行环境,可以在用户空间中运行BPF程序,而无需直接访问内核,从而提高了安全性和性能。RBPF虚拟机还支持在不同的操作系统和平台上运行,是一个功能强大的工具,被广泛应用于网络安全、性能优化等领域。
验证器主要执行以下检查:
check_prog_len
- 程序长度检查fn check_prog_len(prog: &[u8]) -> Result<(), Error> {
// 检查是否为8字节倍数
if prog.len() % ebpf::INSN_SIZE != 0 {
reject(...)?;
}
// 检查最大长度
if prog.len() > ebpf::PROG_MAX_SIZE {
reject(...)?;
}
// 检查非空
if prog.is_empty() {
reject(...)?;
}
// 检查必须以EXIT结束
let last_opc = ebpf::get_insn(prog, (prog.len() / ebpf::INSN_SIZE) - 1).opc;
if last_opc & ebpf::BPF_CLS_MASK != ebpf::BPF_JMP {
reject(...)?;
}
Ok(())
}
check_load_dw
- LD_DW指令检查fn check_load_dw(prog: &[u8], insn_ptr: usize) -> Result<(), Error> {
// 获取下一条指令
let next_insn = ebpf::get_insn(prog, insn_ptr + 1);
// 下一条指令的操作码必须不为0
if next_insn.opc != 0 {
reject(...)?;
}
Ok(())
}
check_jmp_offset
- 跳转指令检查fn check_jmp_offset(prog: &[u8], insn_ptr: usize) -> Result<(), Error> {
let insn = ebpf::get_insn(prog, insn_ptr);
// 检查死循环
if insn.off == -1 {
reject(...)?;
}
// 检查跳转目标是否在程序范围内
let dst_insn_ptr = insn_ptr as isize + 1 + insn.off as isize;
if dst_insn_ptr < 0 || dst_insn_ptr as usize >= (prog.len() / ebpf::INSN_SIZE) {
reject(...)?;
}
// 检查是否跳转到LD_DW指令的中间
let dst_insn = ebpf::get_insn(prog, dst_insn_ptr as usize);
if dst_insn.opc == 0 {
reject(...)?;
}
Ok(())
}
check_registers
- 寄存器访问检查fn check_registers(insn: &ebpf::Insn, store: bool, insn_ptr: usize) -> Result<(), Error> {
// 源寄存器检查
if insn.src > 10 {
reject(...)?;
}
// 目标寄存器检查
match (insn.dst, store) {
(0..=9, _) | (10, true) => Ok(()), // R0-R9总是可写,R10仅在store=true时可写
(10, false) => reject(...), // 不可写入R10
(_, _) => reject(...), // 无效寄存器
}
}
验证器支持的操作码分为以下几类:
这个 eBPF 验证器虽然比 Linux 内核中的验证器简单,但它提供了基本的程序完整性检查:
通过上述对源码进行解读,认识到验证器是虚拟机的门户,它保证了虚拟机的按照预定的规范的指令执行程序,保证了安全性和稳定性。
代码来源:rbpf虚拟机 鸣谢: qmonnet 提供的开源代码.
当然,我也会将带有中文注释和自己理解的一些代码上传的我的github页面,感兴趣的朋友可以进行clone查看.
我的GitHub:forked