rbpf虚拟机-验证器(verifier)

本文涉及的产品
可观测可视化 Grafana 版,10个用户账号 1个月
任务调度 XXL-JOB 版免费试用,400 元额度,开发版规格
MSE Nacos/ZooKeeper 企业版试用,1600元额度,限量50份
简介: 该篇文章是rbpf虚拟机验证器代码块功能的整理。(学习该虚拟机的目的是为了搞懂solana合约的执行方式,solana使用的rbpf是在该虚拟机上进行扩展。)

Welcome to Code Block's blog

本篇文章主要介绍了
[rbpf虚拟机-验证器(verifier)]
❤博主广交技术好友,喜欢我的文章的可以关注一下❤

一、概述

该篇文章是rbpf虚拟机验证器代码块功能的整理。

(学习该虚拟机的目的是为了搞懂solana合约的执行方式,solana使用的rbpf是在该虚拟机上进行扩展。)

这个 eBPF 验证器是在 eBPF 程序加载到虚拟机(VM)时执行的简单检查工具,与 Linux 内核中更复杂的验证器不同。它不涉及程序流控制(应为有向无环图)或寄存器使用一致性等深入检查。

什么是rbpf虚拟机?

RBPF虚拟机是一种基于Rust语言开发的轻量级虚拟机,用于执行BPF(Berkeley Packet Filter)程序。BPF是一种在内核中执行过滤和转发网络数据包的技术,RBPF虚拟机可以用来模拟和执行这些BPF程序,以实现网络数据包的快速过滤和处理。RBPF虚拟机通过提供一个安全的执行环境,可以在用户空间中运行BPF程序,而无需直接访问内核,从而提高了安全性和性能。RBPF虚拟机还支持在不同的操作系统和平台上运行,是一个功能强大的工具,被广泛应用于网络安全、性能优化等领域。


二、主要功能

验证器主要执行以下检查:

  1. 程序长度检查

    • 指令必须是 8 字节的倍数
    • 最大指令数限制为 1,000,000 字节
    • 程序不能为空
    • 程序必须以 "EXIT" 指令结束
  2. 指令格式检查

    • 检查 LD_DW(64位加载)指令是否完整(由两条连续指令组成)
    • 检查跳转指令的目标是否有效
    • 检查寄存器访问是否合法
  3. 操作码验证

    • 验证所有操作码是否属于已知类型

三、关键函数解析

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(...),               // 无效寄存器
    }
}

四、操作码分类

验证器支持的操作码分为以下几类:

  1. 加载类 (BPF_LD)

    • LD_ABS_B/H/W/DW - 固定偏移加载
    • LD_IND_B/H/W/DW - 间接偏移加载
    • LD_DW_IMM - 64位立即数加载(特殊处理)
  2. 存储类 (BPF_ST/BPF_STX)

    • ST_B/H/W/DW_IMM - 立即数存储
    • ST_B/H/W/DW_REG - 寄存器存储
  3. 算术逻辑运算类 (BPF_ALU/BPF_ALU64)

    • 32位和64位的加减乘除、位操作等
  4. 跳转类 (BPF_JMP/BPF_JMP32)

    • 条件跳转(等于、大于、小于等)
    • 无条件跳转 (JA)
    • 32位和64位版本
  5. 调用类 (BPF_CALL)

    • 普通调用 (CALL)
    • 尾调用 (TAIL_CALL)

五、总结

这个 eBPF 验证器虽然比 Linux 内核中的验证器简单,但它提供了基本的程序完整性检查:

  1. 确保程序格式正确
  2. 防止明显的安全风险(如无效内存访问)
  3. 验证指令序列的合法性

通过上述对源码进行解读,认识到验证器是虚拟机的门户,它保证了虚拟机的按照预定的规范的指令执行程序,保证了安全性和稳定性。

代码来源:rbpf虚拟机
鸣谢: qmonnet 提供的开源代码.

当然,我也会将带有中文注释和自己理解的一些代码上传的我的github页面,感兴趣的朋友可以进行clone查看.

我的GitHub:forked


感谢您的点赞、关注、收藏!

目录
相关文章
|
5月前
|
人工智能 运维 监控
基于MCP的一体化AI管线:从模型训练到部署监控的全链路解析
本文介绍基于MCP(模型控制流水线)的一体化AI部署架构,涵盖从模型训练、自动部署、实时推理到性能监控的完整闭环系统设计,并结合工业制造、能源、IoT等场景,提供代码实现与落地案例,助力企业实现AI自动化运维与智能化升级。
基于MCP的一体化AI管线:从模型训练到部署监控的全链路解析
|
5月前
|
存储 Java API
小试牛刀-SpringBoot集成SOL链
java工程师:如何在java/springboot中使用solana区块链呢?不用担心,现在solanaj来了!
168 0
|
5月前
|
编解码 vr&ar 芯片
详解工业AR眼镜关键技术之光学篇
AR眼镜的光学技术是影响显示效果与佩戴体验的核心,主要包括微显示与光波导技术。微显示决定分辨率、亮度与色彩表现,主流方案有LCOS、Micro-OLED与Micro-LED;光波导则实现轻薄化设计,分为几何波导与衍射波导,分别侧重亮度与厚度控制。未来发展方向为更轻薄、大视场角与低成本。
|
5月前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习模型、算法与应用的全方位解析
深度学习,作为人工智能(AI)的一个重要分支,已经在多个领域产生了革命性的影响。从图像识别到自然语言处理,从语音识别到自动驾驶,深度学习无处不在。本篇博客将深入探讨深度学习的模型、算法及其在各个领域的应用。
936 3
|
5月前
|
传感器 定位技术 数据格式
常用通信协议及数据格式
常用通信协议和格式总结
447 2
|
5月前
|
存储 JavaScript 区块链
小试牛刀-walletconnect二维码及交互
最近在使用walletconnect协议和typescript语言实现相关交互功能,在此对从walletconnet协议二维码生成、连接后发送交易事务、签名事务、签名任意信息的处理进行记录,加深对walletconnect的理解,熟悉对其组件的使用,同时希望帮助到有实现相关功能的朋友。
185 1
|
5月前
|
存储 算法 区块链
从零实现Python扫雷游戏:完整开发指南与深度解析
扫雷作为Windows经典游戏,承载了许多人的童年回忆。本文将详细介绍如何使用Python和Tkinter库从零开始构建一个功能完整的扫雷游戏,涵盖游戏设计、算法实现和界面开发的全过程。
394 0
|
5月前
|
jenkins Java 持续交付
使用Jenkins完成springboot项目快速更新
本文介绍了使用Jenkins和WinSW实现SpringBoot项目自动化部署的完整流程。首先讲解了Jenkins作为持续集成工具的作用,然后详细说明了环境准备步骤:包括JDK版本管理、WinSW服务配置(含XML文件修改)以及bat启动脚本编写。重点演示了Jenkins的项目配置方法,包括源码管理设置和构建步骤中的Windows批处理命令调用。通过这套方案,开发者只需推送代码到Git仓库,即可触发Jenkins自动完成项目构建、服务重启等全流程,显著提升部署效率。文章还提到IDEA的Jenkins插件可进
200 1
|
5月前
|
存储 Rust IDE
小试牛刀-Solana合约账户详解
开发语言上,Solana合约使用Rust为主要开发语言,其次是Solana合约并不像其它链那样将数据直接存到合约里,而是使用了更加独立的账户来代币转移和存储数据。按功能可以分为以下账户
188 1
|
11月前
|
机器学习/深度学习 自然语言处理 搜索推荐
自注意力机制全解析:从原理到计算细节,一文尽览!
自注意力机制(Self-Attention)最早可追溯至20世纪70年代的神经网络研究,但直到2017年Google Brain团队提出Transformer架构后才广泛应用于深度学习。它通过计算序列内部元素间的相关性,捕捉复杂依赖关系,并支持并行化训练,显著提升了处理长文本和序列数据的能力。相比传统的RNN、LSTM和GRU,自注意力机制在自然语言处理(NLP)、计算机视觉、语音识别及推荐系统等领域展现出卓越性能。其核心步骤包括生成查询(Q)、键(K)和值(V)向量,计算缩放点积注意力得分,应用Softmax归一化,以及加权求和生成输出。自注意力机制提高了模型的表达能力,带来了更精准的服务。
12296 46