Cve-rs:用安全 Rust 编写的快速内存漏洞

一个 Rust 概念验证 crate、cve-rs,利用 Rust 生命周期和变异性系统中一个长期存在的编译器健全性 bug,在不含任何 `unsafe` 块的代码里制造内存安全违规。评论者剖析了隐含生命周期约束、函数指针变异性以及当前 trait solver 如何共同导致这一边缘情况,并指出即使 rustc 接受代码,Miri 也能检测到该问题。讨论也权衡了这类 bug 的罕见性和刻意构造性,与 Rust 作为“内存安全”语言的营销之间的关系,以及这些不健全的边角情况在实践中是否会实质性削弱这一保证。

Rust 生命周期语法与核心 bug

  • 讨论的重点在于 &'a &'b T 与添加显式 where 'b: 'a 约束之间的区别。
  • 多条评论解释说:嵌套引用会创建编译器应当遵守的 隐含 生命周期约束;外层生命周期不应长于内层。
  • 这个 bug 出现在这些隐含约束与函数指针协变/逆变以及高阶生命周期相互作用时:编译器在某些转换之后会错误地假定一个生命周期长于另一个,从而在“安全”代码中引发 use-after-free。
  • 也有人强调,这涉及后绑定与前绑定生命周期,以及函数类型的变异性(逆变/协变)如何处理。

Miri、Polonius 以及 trait solver 工作

  • Miri(解释器/消毒器)即使在 Rust 代码语法上是“安全”的情况下,也能在运行时检测到这种不健全性。
  • 关于新的 trait solver 及相关重构(隐含约束、共归纳)是否是正确修复的前置条件,存在争论;链接指出这个 bug 明确被该工作阻塞。
  • 有些人对“新 solver 会修好它”的说法持怀疑态度,但也有人指出技术路线很清晰,只是困难且进展缓慢。

安全保证、不健全性与营销

  • 一方认为:即便有 80+ 个未解决的“unsound”问题,Rust 也远比 C/C++ 安全得多,而这些通常是罕见、很难意外碰到的边缘情况。
  • 另一方反驳:任何不健全性都会削弱“内存安全”的宣称;在这些 bug 修复之前,Rust 应被描述为“更内存安全(memory safer)”。
  • 讨论还涉及这究竟是编译器 bug,还是更深层的语言/类型论缺陷;有人坚持设计本身可以是健全的,只是实现落后了。

易用性与可学习性

  • 一些读者觉得触发 bug 的代码可怕或难以阅读,并担心 Rust 符号过多、容易引发 RSI。
  • 也有人回应说,这些是为了最小复现而写的晦涩代码,并不代表典型 Rust;现实中的大多数代码并不会显式写很多生命周期。
  • 生命周期被非正式地解释为带标签的“内存池”,这让几位读者觉得更容易理解。
  • 讨论还延伸到对 Rust 语法选择的批评与辩护,有人建议某些 unsafe 相关语法和函数语法本可以设计得更好。

实际影响与可利用性

  • 很多人强调,要利用这个问题需要刻意构造代码和反优化技巧;几乎不可能在无意中写出来。
  • 但评论者也指出,即便只有这样一个漏洞,也与“安全 Rust 代码不会造成内存破坏”的预期相矛盾,应当认真对待。
  • 还有人将其与 /proc/self/mem 等其他途径作比较,并提醒 Rust 的保证只覆盖程序自身的行为,不包括外部进程或操作系统。

杂项

  • 有人提到项目的玩笑许可证(GLWTS)以及 download_more_ram() 函数,认为这些是幽默之处。
  • 有人询问 shell 提示符;其他人认出它是一款流行的提示符工具。