RustGo: Fairly Directed Greybox Fuzzing for Enforcing Rust Memory Safety
RustGo 是一种新型的有向灰盒模糊测试器,它利用 Rust 特有的静态分析来自动识别潜在的内存错误目标并剪枝无关的执行路径,从而与现有方法相比,显著提高了模糊测试效率,并发现了 unsafe Rust 代码中未知的漏洞。
原始论文采用 CC BY 4.0 许可(http://creativecommons.org/licenses/by/4.0/)。 这是对下方论文的AI生成解释。它不是由作者撰写或认可的。如需技术准确性,请参阅原始论文。 阅读完整免责声明
想象一下你是一名侦探,试图在一座巨大且繁忙的城市中寻找一个微小的瑕疵。在计算机软件的世界里,这座城市就是一个程序,而这个瑕疵就是“内存漏洞(memory bug)”——即程序尝试获取、使用或丢弃它不该触碰的数据,从而导致崩溃或被黑客攻击。几十年来,寻找这些漏洞最流行的方法是“模糊测试(fuzzing)”。你可以把模糊测试想象成向城市围墙投掷数百万个随机且混乱的雪球,看看是否会有雪球砸碎窗户。通常情况下,这种方法对于旧语言非常有效,但它有一个致命缺陷:效率极低。你可能需要向坚固无比、无法攻破的正门投掷 99 个雪球,才能找到后巷里那个唯一的弱点窗口。
于是,Rust 登场了。这是一种现代编程语言,它扮演着一名极其严格的保安角色。Rust 的规则如此出色,以至于它构建的 90% 的城市几乎是防弹的;保安确保大多数“窗口”(内存区域)默认都是锁死的。然而,为了构建某些复杂的组件,Rust 允许开发者打开一个小型的特殊闸门,称为“不安全代码(unsafe code)”。这是唯一规则被放宽的地方,也是内存漏洞唯一可能藏身之处。问题在于,现有的“投掷雪球”工具并不知道这一点。它们仍然在向城市中那 90% 已经安全的区域投掷雪球,白白浪费时间和精力,而错过了那个特殊闸门后极少数危险的角落。这篇论文介绍了一种名为 RustGo 的新侦探工具,它改变了游戏规则,因为它知道该往哪里投掷雪球。
智能侦探:RustGo
这项研究背后的研究人员(来自高丽大学及其他机构的一个团队)意识到,向 Rust 程序随机投掷雪球就像是通过焚烧整个干草堆来寻找其中的一根针。由于 Rust 保证了其大部分代码的安全,他们提出了疑问:为什么还要测试那些安全的部分? 他们开发了 RustGo,一种“定向灰盒模糊测试工具(directed greybox fuzzer)”,它更像是一个拿着地图和放大镜的侦探,而不是一个蒙着眼睛扔石头的盲人。
RustGo 通过三个巧妙的步骤高效地追踪漏洞:
1. 寻找正确的目标(地图)
首先,RustGo 会扫描代码以寻找可能隐藏漏洞的“不安全(unsafe)”区域。但它并不只是瞎猜。它使用一种特殊的分析方法来观察数据如何在程序中流动。想象一下,城市有很多小巷,但有些小巷通向死胡同或者在现实中永远不会发生的循环。RustGo 会过滤掉这些路径。它识别出可能触发内存漏洞的具体位置,并将相似的位置合并在一起。如果代码中的两条不同路径会导致完全相同的危险结果,Rust-Go 会将它们视为同一个目标,这样它就不会在重复检查相同内容上浪费时间。在测试中,这一步帮助他们减少了约 84% 需要检查的目标数量,使其专注于真正可疑的区域。
2. 切断死路(放大镜)
一旦 RustGo 知道了该看哪里,它就需要忽略城市的其余部分。在旧的模糊测试工具中,城市的“地图”通常包含了标准库(Rust 使用的预建工具),这非常庞大且充满了看似可达实则无法到达的路径。这会让工具感到困惑,导致它们探索无用的区域。RustGo 引入了一种新技巧,称为“针对特定目标的路径剪枝(target-specific path pruning)”。这就像拥有一道神奇的栅栏,能瞬间让任何不通向当前正在调查目标的路径消失。如果侦探正在寻找面包店里的漏洞,那么这道栅栏就会阻断通往图书馆或公园的路径,即使这些路径在技术上确实存在于城市中。这使得 RustGo 能够切除掉其他工具会浪费时间去探索的 78.49% 的无关路径。
3. 公平竞争(轮询策略)
这是最后一个关键的转折。当侦探有多个嫌疑人(目标)需要检查时,旧的工具往往会对最容易到达的那一个产生痴迷,从而忽略了较难到达的那些。RustGo 使用了一个“动态公平切换(dynamic fair toggling)”系统。想象一位裁判,他在不同嫌疑人之间进行完美的轮换,切换侦探的注意力。如果侦探在嫌疑人 A 身上花费了太多时间,裁判会立即将注意力转向嫌人 B,确保每个嫌疑人都得到公平的关注。RustGo 通过为每个目标分配自己的“雪球队列”和用于跟踪进度的“记分卡”来实现这一点。这确保了没有任何危险点会因为稍微难以到达而被遗漏。
结果:更快、更聪明
该团队在 13 个真实的 Rust 应用上测试了 RustGo,范围涵盖从 Web 服务器到数据处理工具。他们将其与包括著名的 AFL++ 在内的多种现有顶级工具以及几种专门的“定向”模糊测试工具进行了对比。结果令人震惊。
由于 RustGo 不再在 90% 的安全代码上浪费时间,而是纯粹专注于那 10% 的危险区域,它发现漏洞的速度比其他工具快了 2.09 到 5.08 倍。在某些情况下,例如 gimli 应用,它的速度提高了 10 倍以上。为了直观理解,如果旧工具需要 10 小时才能找到一个漏洞,RustGo 用不到 1 小时就能找到。
但速度并非唯一的胜利。团队利用 RustGo 在野外(而非仅仅在实验室)寻找漏洞。他们发现了 13 个真实软件中此前未知的内存漏洞。其中,10 个得到了软件开发者的确认,且 8 个已经被修复。更令人印象深刻的是,其中 6 个漏洞被分配了官方安全 ID (RUSTSEC),并且 其中一个获得了 CVE ID(这是追踪严重安全缺陷的全球标准)。这证明了 RustGo 不仅仅是一个理论上的想法,它是一个已经在让软件变得更安全的实用工具。
为什么这很重要
这篇论文不仅仅是在建议 RustGo 是个好主意,它还通过测量、证明其有效性,并展示了它如何发现他人错过的真实漏洞。它明确反对了旧有的思维方式:即我们必须测试每一行代码才能确保安全。相反,它表明通过理解 Rust 的独特规则,我们可以变得更聪明、更快、更有效。
研究人员还解决了人们的一个普遍担忧:“如果我们忽略了安全部分,会不会错过漏洞?”他们解释说,Rust 的安全规则非常严格,以至于空间内存漏洞(如访问错误的内存地址)在代码的安全部分是绝不可能发生的。因此,忽略它们并不会产生盲点,而只是消除了噪音。对于时间漏洞(在使用完内存后继续使用),RustGo 非常谨慎,确保它不会意外剪掉可能导致漏洞的路径,它采用了一种“保守”的方法,使安全网足够宽,足以捕捉到所有东西。
最后,RustGo 是专业化力量的证明。正如顶级厨师不会用锤子去砸开坚果一样,现代模糊测试工具也不应该对像 Rust 这样先进的语言使用笨拙的工具。通过针对该语言独特的优势和弱点量身定制方法,作者创造了一个不仅更快、而且更公平的工具,确保代码中每一个潜在的危险都能得到应有的关注。
您所在领域的论文太多了?
获取与您研究关键词匹配的最新论文每日摘要——附技术摘要,使用您的语言。