Rust与C/C++的内存安全CVE有所不同
CVE是一个用于分类和报告软件安全漏洞的数据库。可以报告各种类型的漏洞。其中一些漏洞仅由程序逻辑中的错误引起(例如最近在Cargo中报告的CVE),但一些最严重的漏洞则由内存不安全引起,这可能很容易导致攻击。在这篇文章中,我想重点关注后一种类型的CVE,它们是如何报告的,特别是在库中,以及Rust与C或C++之间的差异。因为有时我在网上看到有人比较Rust和C/C++软件中的CVE数量,这通常伴随着关于Rust并不真正内存安全或在CVE仍然存在时不值得采用的说法。在我教授Rust给习惯于使用C或C++编程的程序员时,我也有时会观察到类似的观点。现在,当然,任何人都可以进行这样的比较,并根据此得出自己的结论。但我认为Rust和C/C++在处理与内存安全相关的潜在漏洞方面存在一个重要的差异,这一点可能在开始时并不明显,特别是如果你不知道Rust是如何工作的。我想在这篇文章中解释这一点。但首先,我应该澄清的是,在Rust中绝对有可能导致内存不安全的错误和未定义的行为。在绝大多数情况下,发生这种情况需要使用unsafe关键字,但任何声称Rust程序根本无法经历UB的人都是错误的。在Rust中也完全有可能导致一般性漏洞(意味着与内存不安全无关的漏洞)。毕竟,忘记检查管理仪表板仅对管理员可访问在任何语言中都可能发生。然而,Rust与C或C++之间的潜在漏洞存在一些非常不同之处,这与Rust在实践中比C或C++更内存安全的核心原因有关。我将尝试通过curl网络库来演示这一点,curl是用C编写的。curl中的潜在漏洞?(lib)curl是世界上使用最广泛、维护最好的开源库之一。其主要开发者Daniel Stenberg是我们这个时代最富有成效的开源维护者之一,过去30年来他与许多人一起勤奋地改进这个库。尽管需要处理最近LLMs发现的大量CVE,但他和他的合作者在保持curl免受潜在攻击和漏洞方面做得非常好,并且以curl是一款非常稳健的软件而自豪。那么,我们来测试一下吧?我打开了libcurl的文档,并找到了第一个我看到的接受参数的函数curl_getenv。这个函数应该是一个简单的函数,它提供了一个跨不同操作系统获取环境变量值的可移植抽象。curl应该是安全而稳健的,所以这个函数肯定不包含任何UB或内存不安全,对吧?那么下面这个C程序怎么样?#include <curl/curl.h> int main ( void ) { curl_getenv ( NULL ); } 这个5行的C程序是简单至极的,它只用NULL指针作为参数调用curl_getenv函数,并且编译时没有任何警告。然而,当你执行它时,你(可能)会得到一个段错误,从而导致内存安全错误,和潜在的漏洞/攻击:$ gcc test.c -otest -lcurl -Wall -Wextra $ ./test 段错误(核心已转储)当然,这个程序是人为简化的,但这正是要点。实际上,这种情况在较大的程序中经常意外发生。哈。那么curl果然不是那么安全吗?我应该去报告这个作为curl的漏洞吗?!不,当然不是。那样做很愚蠢。我知道,你也知道。但我们到底是如何知道的呢?这就是有趣的部分。考虑一个非常类似的程序,它这么调用函数:curl_getenv("FOO")。如果那个程序仍然段错误,从而包含潜在漏洞呢?我相信curl的维护者会想知道这种情况,并且会认为如果我报告这个的话会是一个相当大的问题!与此同时,我确信如果我把第一个程序报告为curl的漏洞,他们会(有理由地)训斥我。然而这两个程序仅有这么一点不同。那么,怎么回事呢?实际上,像我原始例子中的UB被认为是由于“错误使用”造成的,而它并不被认为是我使用的库或API中的问题,而是我(应用)代码中的问题。这主要是因以下两个原因:在C中,通常无法准确指定API的合同(不变性、前置条件、后置条件等),由于其有限的类型系统,库作者通常不愿意描述所有可能的错误使用,因为这不会具有实际意义。
本站免费、广告极少。如果觉得有帮助,可以请我们喝杯咖啡 —— 任何金额都对持续运营有实际帮助。
☕请我喝杯咖啡