FEATURED · 精选文章

Aptos MonoMove VM 安全与正确性设计指南:漏洞分类、关键不变量与工程落地

发布时间 / 2026/9/18 3:06:56
来源 / 创域科博编辑部
栏目 / 资讯中心
Aptos MonoMove VM 安全与正确性设计指南:漏洞分类、关键不变量与工程落地 Aptos MonoMove VM 安全与正确性设计指南漏洞分类、关键不变量与工程落地【免费下载链接】aptos-coreAptos is a layer 1 blockchain built to support the widespread use of blockchain through better technology and user experience.项目地址: https://gitcode.com/GitHub_Trending/ap/aptos-coreMonoMove 是 Aptos 仓库third_party/move/mono-move中新一代 Move VM 的实现代号本文围绕其安全设计文档 vm_security_and_correctness.md 展开系统梳理 VM 层必须坚守的漏洞分类体系与关键不变量。读完本文你将掌握 MonoMove 在算术安全、内存安全、气体计量、确定性、缓存一致性等维度上的硬性约束以及这些约束如何在 global-context、runtime、alloc 等模块中落地实现。文档定位一份给 VM 实现的安全宪法该文档是 MonoMove 设计与实现系列文档之一与 closure_design.md、gas_design.md、heap_and_gc.md、value_representation.md 等并列共同定义新一代 VM 的运行时语义。它的作用不是描述某个具体算法而是列出 VM 实现任何阶段都不得违反的安全与正确性契约——从漏洞分类、关键不变量到实现层面的强制规则是代码审查、模糊测试和形式化验证的对照基准。核心设计原则文档开篇给出两条奠基性设计原则假定所有漏洞终将被发现Assume all vulnerabilities will be discovered。任何可被利用的缺陷最终都会被攻击者发现并利用或者被安全研究者报告——在 AI 辅助审计工具日益普及的背景下这种趋势只会加速。因此不能寄希望于没人发现而必须默认漏洞会被曝光并提前防御。安全必须内建于核心设计Security must be integral to the core design。事后向已有实现打补丁式地追加安全保证远比从第一天起就把安全设计进去困难得多、也更容易出错。这也解释了为什么该文档先于实现、或与实现同步地规定不变量——例如 global-context/src/context.rs 开篇就声明了两阶段状态机的安全契约。常见漏洞分类文档将 VM 漏洞归纳为五大类按严重程度排列类别危害描述严重性铸造 / 数据变造 / 资金损失Minting / Data Transmutation / Loss of Funds未经授权地创建、销毁或篡改链上资产最严重的一类非确定性Non-determinism导致链停止出块chain halt高崩溃Crashing未处理的错误使节点进程终止高重入Reentrancy意外的重入调用导致合约级绕过或失败高慢化Slow-down恶意输入使执行性能劣化DoS中其中铸造/数据变造/资金损失之所以被列为最严重类别是因为 Move 的全局存储模型下资源resource即资产任何绕过类型系统的字节级操作见下文类型与内存安全都可能直接改变资产的创建与归属。而非确定性之所以会造成链停是因为所有验证节点必须对同一输入产生完全一致的结果一旦分歧出现共识即失效——文档在严格确定性一节对这一点给出了更细的约束。关键不变量Key Invariants以下不变量贯穿 VM 实现全程是本文档的核心章节。算术安全所有算术运算与数值类型转换必须经过检查。除非能证明正确性例如输入已因先前的边界检查或不变量而确定在合法范围内否则不允许未经检查的算术wrapping/overflow。这意味着 u64/u128 加减乘除、整数移位、整数类型之间的收窄转换等都必须显式处理溢出与截断不能依赖 Rust 在 release 模式下的默认 wrapping 行为。类型与内存安全MonoMove 中值以无类型的原始字节存储VM 必须时刻防止类型混淆type confusion与数据变造data transmutation。这一点与 value_representation.md 中的扁平内存布局设计直接呼应——原始字节没有自描述的类型信息安全性完全依赖 VM 的布局计算与描述符表正确。指针有效性Pointer validity。每次指针解引用都必须满足指针必须指向该交易被授权访问的内存区域——即交易自身的内存区域或由先前已提交交易共享的冻结全局状态禁止 use-after-free不得解引用已释放或被回收的内存指针禁止 off-by-one 或其他错误的偏移计算禁止越界访问容器vector、struct 等内部。分配失败处理。栈溢出stack overflow与堆分配失败必须被当作错误并优雅处理——即中止交易abort the transaction绝不能忽略。这与 heap_and_gc.md 中关于 per-block 内存上限的讨论互为表里分配失败是内存受限下的预期事件而不是崩溃条件。集中式内存管理。所有重要的内存分配都必须经由 VM 的内存管理器完成。原生函数native functions尤其不应维护独立的影子内存空间否则难以强制全局内存上限并为不受追踪的资源消耗敞开大门。从源码结构看MonoMove 将分配器独立成 cratealloc内含GlobalArenaPool、global_arena.rs等global-context 与 runtime 均依赖它这正是集中式约束的体现。气体计量Gas MeteringVM 执行的每一单位工作都必须计费。文档给出两条核心要求渐近安全Asymptotic safety执行过程中任意时刻的累计 gas 消耗必须与累计工作量成正比。这是不可谈判的底线——如果某个操作复杂度是 O(n) 但只收常量费用攻击者就能以极低成本放大工作量形成 DoS。先计费后工作Charge-before-work一般原则是 gas 应在对应工作执行之前收取。该规则并非总能满足必要时可被短暂违反但任何违反都必须由一个小的常数界住——即欠账量必须有上界。MonoMove 的气体设计在 gas_design.md 中有详细展开计量被放在stackless execution IR 层面做基本块basic block粒度计费每个块的成本在 lowering 期间静态计算控制流转入某块时由转移指令jump顺带收取该块成本entry_gas、gas_taken、gas_fallthrough字段从而在热路径上省去独立的计费指令。这正体现了先计费后工作与渐近安全两条不变量在实现层的落地策略。有界性BoundednessVM 内部所有数据结构、算法与资源消耗都必须显式有界。任何维度空间或时间上的无界都是潜在的拒绝服务向量。数据与存储上界。以下各项都必须有强制上限Loader 数据包括代码大小需计入单态化/泛型展开的膨胀内存消耗栈、堆、代码区类型名长度与数据布局大小缓存大小全局上下文与每交易上下文中的所有缓存二进制格式中的所有条目注意现有上限由反序列化器执行但必须审查其完备性写集write set大小。递归上界。递归是最重要也最难防御的方向文档明确列出三个不同的无界递归来源Move 层递归栈内存耗尽时必须中止交易Rust 层递归任何遍历深度嵌套数据的 Rust 算法都易栈溢出。其中尤须警惕递归类型上的Drop实现——因为程序员对它的调用时机与控制能力有限递归类型上派生的 traitClone、Hash、Eq、PartialEq、Display、Debug——它们生成递归实现在深度嵌套数据上可溢出栈且极易在看似无害的代码路径中悄然发生目标是彻底消除递归算法至少在上生产前要有清晰、文档化的缓解方案。递归库调用任何内部递归的库函数调用例如拓扑排序、强连通分量分析也必须遵守深度限制。算法运行时间。loader、单态化器monomorphizer、字节码验证器及其他所有算法相对于输入规模必须有界运行时间。值上界。当前倾向是只要没有递归遍历作用于值之上即不存在递归的 display、drop 或其他遍历值结构的递归算法值包括闭包就不需要显式的深度或大小上界。若某类遍历不可避免则该遍历自身必须做深度限制而不是依赖值级上界。该决策待值上的操作集合完全确定后最终拍板。禁止未记录的 PanicVM 代码中的 panic 等价于崩溃而崩溃即漏洞。文档给出两条硬性规则裸unwrap()被禁止任何可能 panic 的 API 必须使用expect()、unreachable!()或等价形式并附带一条说明为何该 panic 条件被相信为不可达的消息。从源码看这一要求在 runtime/src/verifier.rs 等模块的错误处理风格中有所体现静态检查器以返回VecVerificationError而非 panic的方式报告函数体不合法问题错误消息包含函数名与可选的 pc 位置便于定位。严格确定性Strict DeterminismVM 必须在所有节点、所有平台、所有运行中对相同输入产生相同结果。三条禁令禁止浮点运算IEEE 754跨平台浮点行为无法保证一致禁止操作系统或线程局部随机源唯一允许的随机性来源是区块上下文如区块级随机种子禁止无序枚举哈希表等迭代顺序不确定的数据结构除非显式保证确定性顺序否则绝不枚举。文档给出的可能缓解方案是为 VM 提供经过审查的安全数据结构 crate例如对HashMap的包装——完全禁止迭代或要求unsafe才能枚举。缓存一致性Cache Consistency所有缓存必须时刻保持一致静默地对外提供过期缓存条目是正确性 bug最坏情况下是安全漏洞。VM 维护多层缓存状态——已验证模块、结构体布局、interned 类型、类型标签等文档点名以下常见风险区代码升级Code upgrades发布或升级模块会使所有派生自它的缓存数据失效模块本身、其定义、类型布局以及任何跨模块依赖方块内可见性Intra-block visibility在 Block-STM 下某交易发布模块时仍必须对所有投机执行speculatively executed、读取了该模块的交易保证正确性。全局缓存、每块缓存与每交易读集三者的交互是当前 VM 复杂性的主要来源之一跨块缓存生命周期Cross-block cache lifecycle跨块存活的缓存必须在条件变化时保持有效非连续交易切片、VM 配置变更、大小上限被突破。每一项被遗漏都是一致性隐患。MonoMove 的MaintenanceGuard见下为这一场景提供了单一的强制点派生数据一致性Derived data coherence缓存常存储由其他缓存数据派生而来的数据结构体布局依赖类型定义类型定义依赖已加载模块。只失效某一层而不传播到依赖方将导致不一致枚举布局Enum layouts枚举需要特别关注——增加一个变体是合法的模块升级但它改变了类型的布局。因此即使升级本身合法布局缓存也必须失效。当前 VM 的做法是任何模块发布时整体刷新布局缓存读集追踪Read-set tracking执行期间读取的每个模块或代码工件都必须记录到交易的读集中即使由缓存提供以保证 Block-STM 正确性。缓存命中在这一点上必须与存储读取不可区分。文档提到的MaintenanceGuard在代码中确实存在global-context/src/context.rs 定义了该结构第 360-392 行 显示它通过mut GlobalContext独占获取与执行期可并发的ExecutionGuard互斥从而保证维护阶段没有任何执行上下文存活、不存在悬垂指针使缓存的 reset 与去分配安全——这正是跨块缓存生命周期一致性问题的工程解法。维护行为由 maintenance_config.rs 中的MaintenanceConfig配置当前仍为占位实现。引用别名Reference AliasingMove 的线性类型系统禁止可变引用的别名aliasing。这一不变量必须在运行时得到维持否则违反可直接导致资金损失——例如通过对同一 coin 资源的别名可变访问实现双重花费。这意味着即使字节码验证器在发布时已保证借用安全运行时仍不能假设这一点可以放松。安全格式化与显示Safe Formatting and Display格式化值或内部数据结构例如用于错误消息或日志是危险操作值可能非常大甚至深度嵌套导致过度内存分配、栈溢出或执行停滞。文档要求错误消息不应包含值的完整转储或复杂的内部状态对值执行Clone具有相同风险须同等谨慎对待考虑禁止在特定 VM 内部类型上使用#[derive(...)]以免意外引入递归或高开销的 trait 实现。交易参数校验Transaction Argument Validation交易参数不得豁免于校验。所有输入——包括交易 payload 中提供的参数——都必须与进入 VM 的任何其他数据一样通过相同的安全检查。换句话说参数解析路径不能成为绕过验证器的旁路。文档结尾以TBA: Closure-specific things标注了待定项——闭包相关的安全事项尚未完全敲定。MonoMove 已支持闭包字节码指令PackClosure/CallClosure其语义约束捕获即 move、调用即消费、禁止捕获引用等详见 closure_design.md而闭包相关的安全与正确性不变量仍在设计中。从文档到实现不变量如何在代码中落地安全文档的价值最终体现在实现上。结合仓库源码可以看到上述不变量与 MonoMove 各组件的对应关系不变量对应实现/文档证据集中式内存管理、分配失败处理alloc、heap_and_gc.mdbump 分配 Cheney 复制式 GC、per-block 内存上限缓存一致性、跨块生命周期global-context/src/context.rs 的两阶段状态机ExecutionGuard / MaintenanceGuard禁止未记录 panic、运行时健全性runtime/src/verifier.rs 的静态 well-formedness 检查帧边界、指针槽有效性、非法跳转目标等气体计量gas_design.mdstackless IR 基本块计费、静态成本类型与内存安全value_representation.md统一 8 字节堆对象头[desc_id, size]、描述符表驱动 GC 追踪以类型与内存安全为例MonoMove 的所有堆对象共享统一头部[desc_id: u32 | size: u32]desc_id索引描述符表GC 借此获知内部指针的偏移struct 字段、enum 按 tag 索引的变体指针表、vector 长度与元素区从而在复制式 GC 中只追踪真正的堆内指针——这正是指针有效性约束得以机械执行的基础设施。再以缓存一致性为例GlobalContext内部用DashMap维护 identifiers、module_ids、types、type_lists、function_refs 等 intern 缓存外加 module_cache 与 script_cachecontext.rs 第 116-141 行。文档要求的读集追踪则由 loader 模块中的 read_set.rs 等承担——缓存命中与存储读取在执行结果上不可区分正是 Block-STM 正确性的前提。总结与阅读建议MonoMove 的这份安全与正确性文档是一份设计期安全规格它不追求覆盖每个 API 的用法而是锚定 VM 最致命的五类漏洞铸造/变造、非确定性、崩溃、重入、慢化并把防御责任分解为一条条可审计、可测试、可形式化验证的不变量。对 VM 开发者而言它是实现时的红线清单对审计者而言它是漏洞排查的检查表对研究者而言它展示了把安全内建于核心设计在区块链 VM 中的具体含义。建议按以下顺序继续深入仓库先读 vm_security_and_correctness.md 本文档建立不变量框架再读 heap_and_gc.md 与 value_representation.md理解内存安全不变量赖以执行的布局与 GC 设计读 gas_design.md对照气体计量不变量看基本块计费方案最后对照 global-context/src/context.rs 与 runtime/src/verifier.rs 的源码注释体会两阶段状态机与静态健全性检查如何在代码层面兑现文档承诺。【免费下载链接】aptos-coreAptos is a layer 1 blockchain built to support the widespread use of blockchain through better technology and user experience.项目地址: https://gitcode.com/GitHub_Trending/ap/aptos-core创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻