本系列主要是分析`RustSecurity` 安全数据库库[1]中记录的Rust
生态社区中发现的安全问题,从中总结一些教训,学习Rust
安全编程的经验。
前两篇:
Rust生态安全漏洞总结系列 | Part 1
Rust生态安全漏洞总结系列 | Part 2
本期分析了下面十一个安全问题:
- RUSTSEC-2021-0110: Vulnerability in wasmtime[2]
- RUSTSEC-2021-0098: Vulnerability in openssl-src[3]
- RUSTSEC-2021-0082: Unsoundness in vec-const[4]
- RUSTSEC-2021-0093: Vulnerability in crossbeam-deque[5]
- RUSTSEC-2021-0077: Vulnerability in better-macro[6]
- RUSTSEC-2021-0106: Vulnerability in bat[7]
- RUSTSEC-2021-0073: Vulnerability in prost-types[8]
- RUSTSEC-2021-0078: Vulnerability in hyper[9]
- RUSTSEC-2021-0072: Vulnerability in tokio[10]
- RUSTSEC-2021-0070: Vulnerability in nalgebra[11]
- CVE-2021-31162: Vulnerability in std[12]
看是否能给我们一些启示。
RUSTSEC-2021-0110: Vulnerability in wasmtime[13]
在 Wasmtime 中发现多个代码缺陷。包括 UAF(use-after-free)、越界读写等。
漏洞描述:
- 漏洞类型:Vulnerability
- 漏洞分类:memory-corruption/ memory-exposure
- CVE 编号:CVE-2021-39216[14]、CVE-2021-39219[15]、CVE-2021-39218[16]
- 详细:https://rustsec.org/advisories/RUSTSEC-2021-0110.html
- 补丁:
>=0.30.0
- 关键字:
use-after-free
/out-of-bounds read /out-of-bounds write / Wasm
/garbage collection
漏洞分析
“背景:
externref
是 WebAssembly 引用类型(Reference Types)中引入的概念,用于表示 Host 引用。
Use after free passing `externref`s to Wasm in Wasmtime[17]
当从 Host 传递给 Guest externrefs
时会引发 UAF 。满足下列条件之一可触发此 Bug :
- 同时明确地从Host传递多个
externrefs
给wasm
实例 - 通过将多个
externrefs
作为参数从 Host 代码传递给wasm
函数 - 从Host定义的多值返回函数中返回多个
externrefs
给wasm
如果 Wasmtime
的 VMExternRefActivationsTable
在传入第一个externref
后容量被填满,那么传入第二个externref
可能会触发垃圾回收。然而,在把控制权传给Wasm
之前,第一个externref
是没有根(root)的,因此,如果没有其他东西持有对它的引用或以其他方式保持它的live,就会被GC回收。然后,当控制权在垃圾收集后被传递给Wasm
时,Wasm
可以使用第一个externref
,但这时它已经被释放了。
Out-of-bounds read/write and invalid free with `externref`s and GC safepoints in Wasmtime[18]
在Wasmtime
运行使用externrefs
的Wasm
时,存在一个无效释放和越界读写的错误。
要触发这个错误,Wasmtime
需要运行使用externrefs
的Wasm
,Host 创建非空的externrefs
,Wasmtime
执行一个垃圾收集(GC),并且堆栈上必须有一个Wasm
帧,它处于GC Safepoint
(安全点就是指代码运行到这个地方,它的状态是确定的, GC就可以安全的进行一些操作),在这个安全点上没有 Live 的引用,这种情况下 Wasmtime
会错误地使用 GC Stack map
而非 安全点。这就会导致释放一些不应该释放的内存,以及潜在的越界读写。
Wrong type for `Linker`-define functions when used across two `Engine`s[19]
“Engine,是在 wasmtime 中被用于跨线程管理wasm模块的全局上下文。 Linker,是用于支持模块链接的结构。
在 Linker::func_*
安全函数中发现了一个问题。wasmtime 不支持函数的跨 engine 使用,这可能导致函数指针的类型混乱,导致能够安全地调用一个类型错误的函数。这种情况应该 panic!
RUSTSEC-2021-0098: Vulnerability in openssl-src[20]
openssl-src[21] 是用于构建 OpenSSL 给 openssl-sys
库使用的。OpenSSL 最近又发现了很多新的安全缺陷,也记录到这里了。
具体这个漏洞是指 处理ASN.1字符串时的读取缓冲区超限问题。
漏洞描述:
- 漏洞类型:Vulnerability
- 漏洞分类:denial-of-service / crypto-failure
- CVE 编号:CVE-2021-3712
- 详细:https://www.openssl.org/news/secadv/20210824.txt
- 补丁:
>=111.16
漏洞分析
ASN.1字符串在OpenSSL内部被表示为一个ASN1_STRING
结构,它包含一个容纳字符串数据的缓冲区和一个容纳缓冲区长度的字段。这与普通的C语言字符串不同,后者表示为一个字符串数据的缓冲区,以NUL(0)
字节结束。
虽然不是严格的要求,但使用OpenSSL自己的 "d2i "函数(和其他类似的解析函数)解析的ASN.1字符串,以及任何用ASN1_STRING_set()函数设置值的字符串,都会在ASN1_STRING结构中以NUL结束字节数。
然而,应用程序有可能直接构建有效的ASN1_STRING结构,通过直接设置ASN1_STRING数组中的 "data "和 "length "字段,不以NUL方式终止字节数组。这也可以通过使用ASN1_STRING_set0()函数来实现。
许多打印ASN.1数据的OpenSSL函数被认为ASN1_STRING字节数组将以NUL结尾,尽管这对直接构建的字符串来说是不保证的。如果应用程序要求打印一个ASN.1结构,而该ASN.1结构包含由应用程序直接构建的ASN1_STRING,而没有以NUL结束 "data "字段,那么就会发生读取缓冲区超限。
如果一个恶意行为者可以使一个应用程序直接构建一个ASN1_STRING,然后通过受影响的OpenSSL函数之一处理它,那么这个问题可能会被击中。这可能导致崩溃(造成拒绝服务攻击,DOS)。它还可能导致私人内存内容(如私人密钥或敏感明文)的泄露。
其他 OpenSSL 问题
OpenSSL 缺陷列表:https://rustsec.org/packages/openssl-src.html
RUSTSEC-2021-0082: Unsoundness in vec-const[22]
vec-const
试图从一个指向常量切片的指针构造一个Vec
。
漏洞描述:
- 漏洞类型:Unsound
- 漏洞分类:memory-corruption
- CVE 编号:CVE-2021-3711
- 详细:https://github.com/Eolu/vec-const/issues/1#issuecomment-898908241
- 补丁:暂无,不建议使用该 crate
- 关键字:memory-safety
漏洞分析
这个crate 违反了Rust的规则,使用起来会有危害。你不应该使用这个crate。这个crate不应该存在。它创建了不健全的抽象,允许不安全的代码伪装成安全代码。
这个crate声称要构造一个长度和容量都不为零的const Vec
,但这是做不到的,因为这样的Vec
需要一个来自分配器(allocator)的指针。参见:https://github.com/rust-lang/const-eval/issues/20。
RUSTSEC-2021-0093: Vulnerability in crossbeam-deque[23]
crossbeam-deque中发生了数据竞争。
漏洞描述:
- 漏洞类型:Vulnerability
- 漏洞分类:memory-corruption
- CVE 编号:GHSA-pqqp-xmhj-wgcw、 CVE-2021-32810[24]
- 详细:https://github.com/Eolu/vec-const/issues/1#issuecomment-898908241
- 补丁:
>=0.7.4, <0.8.0
/>=0.8.1
漏洞分析
在受影响的版本中,队列的一个或多个任务会被弹出两次,如果在堆上分配,会导致 dobule free 和 内存泄漏。如果不是堆上分配,则会引起逻辑错误。
修复PR :https://github.com/crossbeam-rs/crossbeam/pull/726
问题是因为任务窃取相关条件判断错误导致的,是逻辑 Bug。
RUSTSEC-2021-0077: Vulnerability in better-macro[25]
better-macro 是一个假的 crate,它在 "证明一个观点",即proc-macros
可以运行任意的代码。这是一个特别新颖或有趣的观察。
它目前打开的 https://github.com/raycar5/better-macro/blob/master/doc/hi.md,似乎没有任何恶意的内容,但不能保证会一直如此。
这个 crate 没有任何有用的功能,不应该被使用。
代码语言:javascript复制#[proc_macro]
pub fn println(input: TokenStream) -> TokenStream {
if let Ok(_) = Command::new("xdg-open").arg(URL).output() {
} else if let Ok(_) = Command::new("open").arg(URL).output() {
} else if let Ok(_) = Command::new("explorer.exe").arg(URL).output() {
}
let input: proc_macro2::TokenStream = input.into();
let out = quote! {::std::println!(#input)};
out.into()
}
RUSTSEC-2021-0106: Vulnerability in bat[26]
bat[27] 中存在不受控制的搜索路径元素,可能会导致非预期代码执行。
0.18.2
之前的windows系统中的bat会从当前工作目录中执行名为less.exe
的程序。
漏洞描述:
- 漏洞类型:Vulnerability
- 漏洞分类:code-execution
- CVE 编号:CVE-2021-36753[28] 、 GHSA-p24j-h477-76q3
- 详细:https://nvd.nist.gov/vuln/detail/CVE-2021-36753
- 补丁:
>=0.18.2
- 平台:Windows
漏洞分析
修复 PR:https://github.com/sharkdp/bat/pull/1724
对传入的 Path 进行了合法验证。使用的库是 grep_cli
。
RUSTSEC-2021-0073: Vulnerability in prost-types[29]
从prost_types::Timestamp
到SystemTime
的转换可能导致溢出和恐慌。
漏洞描述:
- 漏洞类型:Vulnerability
- 漏洞分类:denial-of-service
- CVE 编号:CVE-2021-36753[30] 、 GHSA-p24j-h477-76q3
- 详细:https://github.com/tokio-rs/prost/issues/438
- 补丁:
>=0.8.0
漏洞分析
在prost-types 0.7.0
中,从Timestamp
到SystemTime
的转换使用UNIX_EPOCH
上的
和-
运算符。如果输入的Timestamp
是不被信任的,这可能会溢出和恐慌,造成拒绝服务的漏洞。因为 SystimeTime 内部实现的
和 -
使用 checked_add/checked_sub
会发生 panic。
use prost_types::Timestamp;
use std::time::SystemTime;
SystemTime::from(Timestamp {
seconds: i64::MAX,
nanos: 0,
}); // panics on i686-unknown-linux-gnu (but not x86_64) with default compiler settings
SystemTime::from(Timestamp {
seconds: i64::MAX,
nanos: i32::MAX,
}); // panics on x86_64-unknown-linux-gnu with default compiler settings
另外,转换涉及到调用Timestamp::normalize
,它使用了
和-
运算符。这可能会引起恐慌或环绕(wrap around,取决于编译器设置),如果应用程序被编译为溢出时恐慌,也会产生拒绝服务的漏洞。
解决问题的思路是:
Timestamp::normalize
可能应该使用 `saturating_{add,sub}`[31] 方法,如果时间戳的nanos
字段超出了范围,这可能会默默地改变时间戳,最多3秒,但这样的时间戳可以说是无效的,所以这可能是好的。
SystemTime
没有Saturating_{add,sub}
方法,也没有MIN
和MAX
常数,应该再次使用 SystemTime::checked_{add,sub}
进行转换。
修复 PR:https://github.com/tokio-rs/prost/pull/439
RUSTSEC-2021-0078: Vulnerability in hyper[32]
对Content-Length进行宽松的 header 解析,可能会使请求被偷渡(走私,smuggling)。
“背景:请求偷渡 不合法的请求被夹杂在合法请求中被得到处理。需要通过
content-length
和Transfer-Encoding
两个header 来构造攻击。
漏洞描述:
- 漏洞类型:Vulnerability
- 漏洞分类:http、parsing
- CVE 编号:CVE-2021-32715
- 详细:https://github.com/hyperium/hyper/security/advisories/GHSA-f3pg-qwvg-p99c
- 补丁:
>=0.14.10
漏洞分析
hyper的HTTP/1服务器代码存在一个缺陷,即错误地解析和接受带有前缀加号的Content-Length头的请求,而这一请求本应作为非法请求被拒绝。这与上游HTTP代理不解析这种Content-Length头而转发的情况相结合,可能导致 "请求偷渡("request smuggling) "或 "去同步攻击(desync attacks)"。
修复代码:https://github.com/hyperium/hyper/commit/06335158ca48724db9bf074398067d2db08613e7
需要判断 content-lenght 是不是可以正常转换为有效数位。
RUSTSEC-2021-0072: Vulnerability in tokio[33]
当用JoinHandle::abort
中止一个任务时,对于 LocalSet
上生成的任务不正确, 容易导致竞态条件。
漏洞描述:
- 漏洞类型:Vulnerability
- 漏洞分类:memory-corruption
- CVE 编号:CVE-2021-32715
- 详细:https://github.com/tokio-rs/tokio/issues/3929
- 补丁:
>=1.5.1, <1.6.0
>=1.6.3, <1.7.0
>=1.7.2, <1.8.0
>=1.8.1
漏洞分析
当用JoinHandle::abort
中止一个任务时,如果该任务当前没有被执行,那么在调用abort
的线程中,Future
会被 Drop。这对于在LocalSet
上生成的任务是不正确的。
这很容易导致竞态条件,因为许多项目在它们的Tokio
任务中使用Rc
或RefCell
以获得更好的性能。
修复 PR:https://github.com/tokio-rs/tokio/pull/3934
RUSTSEC-2021-0070: Vulnerability in nalgebra[34]
nalgebra
库中VecStorage
的Deserialize
实现没有保持元素数量必须等于nrows * ncols
的不变性。对特制的输入进行反序列化时,可能会允许超出向量分配的内存访问。
漏洞描述:
- 漏洞类型:Vulnerability
- 漏洞分类:memory-corruption/ memory-exposure
- CVE 编号:CVE-2021-32715
- 详细:https://github.com/dimforge/nalgebra/issues/883
- 补丁:
>=0.27.1
漏洞分析
这个缺陷是在v0.11.0(086e6e)
中引入的,因为为MatrixVec
增加了一个自动派生(derive)的Deserialize
实现。MatrixVec
后来在v0.16.13(0f66403)
中被改名为VecStorage
,并继续使用自动派生的Deserialize
实现。
修复 PR :https://github.com/dimforge/nalgebra/pull/889
在反序列化的过程中,对 nrows.value() * ncols.value() == data.len()
进行校验。
CVE-2021-31162: Vulnerability in std[35]
在 Rust 1.52.0之前的Rust标准库中,如果释放元素时出现panic ,在Vec::from_iter
函数中会出现 double free。
漏洞描述:
- 漏洞类型:Vulnerability
- 漏洞分类:memory-corruption
- CVE 编号:CVE-2021-31162
- 详细:https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-31162
- 补丁:
>=1.52.0
漏洞分析
漏洞复现代码:
代码语言:javascript复制use std::iter::FromIterator;
#[derive(Debug)]
enum MyEnum {
DroppedTwice(Box<i32>),
PanicOnDrop,
}
impl Drop for MyEnum {
fn drop(&mut self) {
match self {
MyEnum::DroppedTwice(_) => println!("Dropping!"),
MyEnum::PanicOnDrop => {
if !std::thread::panicking() {
panic!();
}
}
}
}
}
fn main() {
let v = vec![MyEnum::DroppedTwice(Box::new(123)), MyEnum::PanicOnDrop];
Vec::from_iter(v.into_iter().take(0));
}
// Output : free(): double free detected in tcache 2
因为枚举MyEnum在 析构的时候panic,导致资源泄漏,而引发了双重 free 的问题。
修复 PR:https://github.com/rust-lang/rust/pull/84603
在 Vec::from_iter
中执行 forget_allocation_drop_remaining
,即,忘记已经被drop的src
的元素分配的内存,即便 drop 发生了 panic,也不会泄漏资源。
参考资料
[1]
RustSecurity
安全数据库库: https://rustsec.org/advisories/
[2]
RUSTSEC-2021-0110: Vulnerability in wasmtime: https://rustsec.org/advisories/RUSTSEC-2021-0110.html
[3]
RUSTSEC-2021-0098: Vulnerability in openssl-src: https://rustsec.org/advisories/RUSTSEC-2021-0098.html
[4]
RUSTSEC-2021-0082: Unsoundness in vec-const: https://rustsec.org/advisories/RUSTSEC-2021-0082.html
[5]
RUSTSEC-2021-0093: Vulnerability in crossbeam-deque: https://rustsec.org/advisories/RUSTSEC-2021-0093.html
[6]
RUSTSEC-2021-0077: Vulnerability in better-macro: https://rustsec.org/advisories/RUSTSEC-2021-0077.html
[7]
RUSTSEC-2021-0106: Vulnerability in bat: https://rustsec.org/advisories/RUSTSEC-2021-0106.html
[8]
RUSTSEC-2021-0073: Vulnerability in prost-types: https://rustsec.org/advisories/RUSTSEC-2021-0073.html
[9]
RUSTSEC-2021-0078: Vulnerability in hyper: https://rustsec.org/advisories/RUSTSEC-2021-0078.html
[10]
RUSTSEC-2021-0072: Vulnerability in tokio: https://rustsec.org/advisories/RUSTSEC-2021-0072.html
[11]
RUSTSEC-2021-0070: Vulnerability in nalgebra: https://rustsec.org/advisories/RUSTSEC-2021-0070.html
[12]
CVE-2021-31162: Vulnerability in std: https://rustsec.org/advisories/CVE-2021-31162.html
[13]
RUSTSEC-2021-0110: Vulnerability in wasmtime: https://rustsec.org/advisories/RUSTSEC-2021-0110.html
[14]
CVE-2021-39216: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-39216
[15]
CVE-2021-39219: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-39219
[16]
CVE-2021-39218: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-39218
[17]
Use after free passing externref
s to Wasm in Wasmtime: https://github.com/bytecodealliance/wasmtime/security/advisories/GHSA-v4cp-h94r-m7xf
[18]
Out-of-bounds read/write and invalid free with externref
s and GC safepoints in Wasmtime: https://github.com/bytecodealliance/wasmtime/security/advisories/GHSA-4873-36h9-wv49
[19]
Wrong type for Linker
-define functions when used across two Engine
s: https://github.com/bytecodealliance/wasmtime/security/advisories/GHSA-q879-9g95-56mx
[20]
RUSTSEC-2021-0098: Vulnerability in openssl-src: https://rustsec.org/advisories/RUSTSEC-2021-0098.html
[21]
openssl-src: https://crates.io/crates/openssl-src
[22]
RUSTSEC-2021-0082: Unsoundness in vec-const: https://rustsec.org/advisories/RUSTSEC-2021-0082.html
[23]
RUSTSEC-2021-0093: Vulnerability in crossbeam-deque: https://rustsec.org/advisories/RUSTSEC-2021-0093.html
[24]
CVE-2021-32810: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-32810
[25]
RUSTSEC-2021-0077: Vulnerability in better-macro: https://rustsec.org/advisories/RUSTSEC-2021-0077.html
[26]
RUSTSEC-2021-0106: Vulnerability in bat: https://rustsec.org/advisories/RUSTSEC-2021-0106.html
[27]
bat: https://rustsec.org/packages/bat.html
[28]
CVE-2021-36753: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-36753
[29]
RUSTSEC-2021-0073: Vulnerability in prost-types: https://rustsec.org/advisories/RUSTSEC-2021-0073.html
[30]
CVE-2021-36753: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-36753
[31]
saturating_{add,sub}
: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.saturating_add
[32]
RUSTSEC-2021-0078: Vulnerability in hyper: https://rustsec.org/advisories/RUSTSEC-2021-0078.html
[33]
RUSTSEC-2021-0072: Vulnerability in tokio: https://rustsec.org/advisories/RUSTSEC-2021-0072.html
[34]
RUSTSEC-2021-0070: Vulnerability in nalgebra: https://rustsec.org/advisories/RUSTSEC-2021-0070.html
[35]
CVE-2021-31162: Vulnerability in std: https://rustsec.org/advisories/CVE-2021-31162.html