☰
rust-review 对抗性 Trait 实现审计指南:如何发现 `unsafe` 代码信任用户 Trait 返回值导致的越界写漏洞(TRAITADV)
2026/10/10 2:14:06 网站建设 项目流程
  • AI 技能
  • AI 插件
  • 应用安全
  • 网络安全
  • AI 评测

【免费下载链接】skills

Trail of Bits Claude Code skills for security research, vulnerability detection, and audit workflows

项目地址:https://gitcode.com/gh_mirrors/skills8/skills
点击查看免费下载

导读

本文讲解 Trail of Bitsskills8仓库中rust-review插件的adversarial-trait-finder检测器(Finding ID 前缀TRAITADV):当 Rust 库公开一个以 trait 为泛型边界的 API,并在unsafe操作中信任 trait 方法(如Read::read、Iterator::next、Hasher、ExactSizeIterator::len)返回的“长度/数量/索引/哈希”时,恶意实现方如何把这种信任变成堆越界写(OOB write)。读完本文,你将掌握该漏洞的完整 bug shape、三条判定 Gates、两类误报排除规则,以及把 trait 输出视为不可信输入的标准修补方案;同时会看到这一 bug class 在rust-review编排管线中的实际接入方式(manifest 声明、has_unsafe门控、worker 执行与发现文件格式)。

漏洞形态(Bug Shape):库信任 trait 返回值,unsafe越界写

adversarial-trait-finder的核心研究模型非常具体:

Bug shape(研究):库接受T: Read,基于T::read()报告的字节数分配缓冲区,并通过未检查的unsafe写操作写入。敌对的impl Read for HostileType返回一个大于实际缓冲区的尺寸 → 越界写(OOB write)。

这与经典 Rust 安全审计中的“调用者即敌人”视角一脉相承:一旦一个 generic API 暴露给外部,T的具体实现就不受库作者控制。凡是把 trait 方法输出当作权威事实、再喂给unsafe长度信任汇点(length-trusting sink)的代码,都可能被一个合法但恶意的impl攻破。

在rust-review的编排体系中,这一 bug class 位于logic-correctness集群,编号为adversarial-trait,前缀TRAITADV。见 prompts/clusters/manifest.json 中logic-correctness集群的 passes 列表:

{ "bug_class": "adversarial-trait", "prefix": "TRAITADV", "prompt": "prompts/general/adversarial-trait-finder.md", "requires": ["has_unsafe"] }

requires: ["has_unsafe"]意味着该 pass 仅在目标代码库包含unsafe(由 Phase 1 的能力探测决定)时才会被计划选中——因为这里的可利用后果正是unsafe代码中的内存破坏,纯 safe-Rust crate 不存在该 sink。plugins/rust-review/README.md 中也将“hostile generic trait impls”列为logic-correctness集群覆盖的逻辑正确性问题之一,并明确“The hostile-trait (TRAITADV) and closure-panic (CLOSUREPANIC) passes requirehas_unsafe”。

Gates:三条判定标准缺一不可

adversarial-trait-finder定义了三个必须同时满足的门槛(Gates),用于把真实的 TRAITADV 从“泛型库常见写法”中筛出来。

Gate 1:公开的泛型 API + trait 边界参数

代码必须是一个公开的(public)泛型 API,其参数带 trait 边界,例如T: Read、T: Iterator、T: Hasher、T: ExactSizeIterator,或自定义 trait。

对应到集群探测层面,prompts/clusters/logic-correctness.md 的 Phase A 提供了如下的rg种子,供 worker 先建立库存再逐项审查:

rg seed: "<\s*\w+\s*:\s*[A-Z]" # generic trait bounds

rust-reviewworker 在执行这些种子搜索时要求使用rg(ripgrep 语法\s/\d/\b),若rg不可用则必须用 POSIX 类回退(\s→[[:space:]]、\d→[[:digit:]]、去掉\b),详见 agents/rust-review-worker.md 的搜索纪律。

Gate 2:trait 方法返回值流入 unsafe 或长度信任汇点

实现必须把 trait 方法的返回值(尺寸、数量、索引、哈希)喂进以下任一unsafe操作或长度信任汇点:

  • Vec::set_len—— 直接声明缓冲区长度为“敌报值”;
  • get_unchecked/get_unchecked_mut—— 用敌报索引越界访问;
  • ptr::write/copy_nonoverlapping在计算偏移处写入 —— 经典 OOB 写路径;
  • from_raw_parts—— 用敌报长度构造切片/裸指针。

关键澄清(文档明确标注的陷阱):

Vec::with_capacity/reserve不是OOB 写汇点——它只预留容量,len仍为0,敌对的尺寸无法借此越界写。但攻击者控制的容量是独立的分配/内存耗尽 DoS,应作为单独问题记录,而不是当作内存破坏上报。

Gate 3:缺乏防御性校验

没有防御性检查确保报告值与实际一致。文档特别强调:

ExactSizeIterator::len()是提示(hint),不是保证(guarantee)——unsafe代码绝不能信任它。

同理,Read::read返回的“读取字节数”在Read契约中也不是权威保证(read本就可以返回比请求更少的字节,而一个恶意 impl 甚至可以谎报)。只要上游没有对 trait 输出做边界校验,Gate 3 即成立。

FPs:两种明确不算数的情况

检测器同时给出了两条“非漏洞”排除规则(False Positives),供 worker 在核查候选时直接放行:

  1. Trait 是密封的(sealed):pub trait T: sealed::Sealed。由于实现被限定在库内部,外部无法提供恶意 impl,信任假设成立。
  2. 返回值仅作启发式且下游会校验:报告值只用于启发式判断(如粗略估算),并且在真正进入unsafe汇点之前会被验证。此时信任链被下游校验切断,不构成漏洞。

这两条 FP 规则与rust-reviewworker 的核查纪律一致:先查现有校验与缓解(“Check for existing validation or mitigations before reporting”),再决定是否上报。

Patch:把 trait 方法输出当作不可信输入

文档给出的修补原则十分简洁:

Patch:将 trait 方法输出视为不可信(untrusted);对它们做边界约束(bound them);绝不直接喂给set_len或get_unchecked。

具体落地通常包含三件事:

  1. 在进入unsafe前校验:用真实可观测信息(如已读取字节数、切片真实长度、len <= cap断言)交叉核对 trait 返回值;
  2. 改用安全 API:把get_unchecked换成slice::get(..n).ok_or(...)?、把ptr::copy_nonoverlapping换成copy_from_slice,让越界变成显式Err而非 UB;
  3. 在// SAFETY:注释中指名上游校验者:文档化“谁保证了这个不变量成立”,而不是写一句无法验证的“caller ensures len <= 64”。

这与 agents/rust-review-worker.md 中 Finding File Format 的Recommendation字段模板完全同构——worker 上报时需给出可替换的安全代码写法并命名真实的校验来源。

在 rust-review 管线中的落地方式

触发条件与计划过滤

TRAITADV pass 是否进入某次审计,由 scripts/build_run_plan.py 的pass_filtered_out()决定。该函数遍历 pass 的requires列表,任何一个 capability flag 为假则硬性剔除该 pass:

for req in requires: if req not in KNOWN_REQUIRES: fail(...) if not flags[req]: return True

也就是说,has_unsafe=false时 TRAITADV 会在计划阶段被直接丢弃,根本不会出现在 worker 的 spawn prompt 中(因此 worker 侧不存在“跳过该 pass”的选择——见 worker 协议中Skip subclasses: (none)的说明)。

执行顺序与冲突消解

在 prompts/clusters/logic-correctness.md 中,TRAITADV 是 Phase B 的第 2 个 pass。该集群用 Phase A 的一次性种子搜索建立共享库存(generic trait bounds、HashMap/HashSet、RefCell等),随后各 pass 复用同一库存,避免重复扫描。集群还给出了相邻 bug class 的去冲突规则,确保同一个根因不被重复贴上多个标签:

  • ORDEQHASHvsKEYMUT:手写Ord/Hash实现本身破坏契约是ORDEQHASH;对一个本已正确的 key 在集合内原地修改才是KEYMUT。
  • CLOSUREPANIC(本集群)vsPANICUNWIND(memory-safety 集群):用户闭包在两个指针操作之间 panic 使unsafe脚手架不一致 →CLOSUREPANIC;容器元数据在 unwind 后残留陈旧 →PANICUNWIND。

TRAITADV 与ORDEQHASH同属“trait 实现危险”,但视角不同:前者是恶意实现者主动利用(外部impl谎报长度攻击库),后者是库自身实现违反契约(a == b ⟹ hash(a) == hash(b)等不变量被破坏导致 HashMap/BTreeMap 崩溃),见 prompts/general/ord-eq-hash-finder.md。

发现文件与后续判定

worker 确认的每个 TRAITADV 发现会以TRAITADV-NNN.md写入$(pwd)/.rust-review-results/<iso-timestamp>/findings/,frontmatter 包含id、bug_class: adversarial-trait、location(单条path:line)、function、confidence、worker,正文按七段结构撰写(Description / Code / Data flow / Reachability trace / Impact / Mitigations checked / Recommendation)。随后 dedup-judge 按(path, line, bug_class)等 Tier 合并重复项,fp-judge 给每个 primary 打fp_verdict与severity;severity_filter只影响最终REPORT.md的渲染,不决定 worker 是否上报。完整协议见 agents/rust-review-worker.md 与 skills/rust-review/SKILL.md。

实战核查清单(可直接复制使用)

对照 prompts/general/adversarial-trait-finder.md 原文,可把审计流程固化为以下清单:

  1. 找边界:rg "<\s*\w+\s*:\s*[A-Z]"列出所有公开泛型 API 与 trait 边界。
  2. 找汇点:对每个边界候选,搜索set_len、get_unchecked、ptr::write、copy_nonoverlapping、from_raw_parts的调用,判断其索引/长度来源是否为 trait 方法返回值。
  3. 找校验:确认汇点上游没有把报告值与真实长度交叉核对;确认 trait 未密封、返回值不是“仅启发式+下游校验”。
  4. 区分 DoS:若攻击面只落在with_capacity/reserve,按“分配/内存耗尽 DoS”单独记录,不要混入内存破坏类。
  5. 写修复建议:给出带边界约束或安全 API 的替换代码,并在// SAFETY:中指名真正的校验方。

按此清单,审计者可以稳定复现 TRAITADV 的完整判定路径:从 generic trait bound 到 unsafe 长度信任汇点,再到恶意 impl 的越界写后果。

小结

adversarial-trait-finder(TRAITADV)把“公开泛型 API + unsafe 长度信任”这一组合精确建模为可利用漏洞:T::read()/ExactSizeIterator::len()等 trait 输出只是提示而非保证,恶意实现可以谎报尺寸,使库在set_len、get_unchecked、copy_nonoverlapping上越界写。三条 Gates(泛型公开 API、unsafe 汇点、缺校验)与两条 FP 规则(密封 trait、下游校验)让检测器既能命中真漏洞又不至于把普通泛型库误报成高危;其requires: has_unsafe门控、硬过滤式计划选择、七段式 finding 文件与后续 dedup/fp 判定,展示了这类“基于研究 bug shape”的检测器在rust-review并行审计管线中从探测到报告的完整落地方式。

  • AI 技能
  • AI 插件
  • 应用安全
  • 网络安全
  • AI 评测

【免费下载链接】skills

Trail of Bits Claude Code skills for security research, vulnerability detection, and audit workflows

项目地址:https://gitcode.com/gh_mirrors/skills8/skills
点击查看免费下载

相关推荐

上一篇:XNBCLI终极指南:让星露谷物语模组开发变得像搭积木一样简单
下一篇:百度网盘解析工具:三步获取真实下载地址的完整指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询