Rust下的二进制漏洞 CVE-2024-27284 分析
字数 1880 2025-08-05 08:19:59
Rust下的二进制漏洞 CVE-2024-27284 深度分析
漏洞背景
CVE-2024-27284 是 Cassandra-rs 开源库中发现的一个 UAF (Use-After-Free) 漏洞。Cassandra 是一个开源的分布式数据库管理系统,由 Apache 软件基金会开发和维护。Cassandra-rs 是 Cassandra 的 Rust 绑定库。
尽管 Rust 语言以其内存安全性著称,但在实际开发中,由于需要对底层逻辑进行操作,开发者不得不使用 unsafe 关键字。一旦引入 unsafe,Rust 在编译期间的内存安全检查就会失效,从而导致潜在漏洞的出现。
漏洞概述
- 漏洞类型: Use-After-Free (UAF)
- 影响组件: Cassandra-rs 库中的迭代器实现
- 严重程度: 高危
- 触发条件: 在迭代器调用
next()方法后继续使用之前返回的项
Rust 相关概念解析
虚幻数据 (PhantomData)
PhantomData 是 Rust 中一种特殊的数据结构,它不占据实际内存空间,但可以用于标记生命周期关系。当结构体需要与某个外部对象保持生命周期一致,但没有直接包含该对象的引用时,可以使用 PhantomData。
pub struct Test2<'a> {
n1: u32,
_marker: PhantomData<&'a Test1>,
}
这种声明表示 Test2 的生命周期将与 Test1 保持一致(协变)。
Rust 迭代器 (Iterator)
Rust 中的迭代器有三种主要类型:
- iter(): 返回不可变迭代器,不转移所有权
- iter_mut(): 返回可变迭代器,不转移所有权
- into_iter(): 消费原对象,转移所有权
标准迭代器 trait 定义如下:
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
// 省略默认实现
}
借贷迭代器 (Lending Iterator)
Lending Iterator 是一种特殊迭代器,它确保在移动到下一个项之前必须停止使用当前项。Rust 1.65.0 引入了相关特性(GATs - Generic Associated Types)。
pub trait LendingIterator {
type Item<'a> where Self: 'a;
fn next(&mut self) -> Option<Self::Item<'_>>;
}
漏洞详细分析
漏洞根本原因
漏洞源于 Cassandra-rs 中迭代器的错误实现:
- 底层 C++ 的
ResultIterator包含一个Row对象 - 当调用
next()时,当前Row会被无效化 - 但 Rust 绑定未能正确反映这种关系,导致 Rust 编译器无法识别潜在的生命周期问题
问题代码结构
在修复前的实现中:
pub struct ResultIterator<'a>(pub *mut _CassIterator, usize, PhantomData<&'a CassResult>);
impl<'a> Iterator for ResultIterator<'a> {
type Item = Row<'a>;
fn next(&mut self) -> Option<Row<'a>> {
unsafe {
match cass_iterator_next(self.0) {
cass_false => None,
cass_true => Some(self.get_row()),
}
}
}
}
这里的问题在于:
Row的生命周期与CassResult绑定,而非与ResultIterator绑定- 但实际上
Row来自ResultIterator内部的内存 - 这种不一致导致 Rust 编译器无法正确识别生命周期关系
漏洞触发场景
let mut tmp_row = None;
let result = function.get_result();
{
for row in result.iter() { // 使用 Iterator trait
if condition.satisfied():
tmp_row = Some(row) // 保存 row 引用
break;
}
} // ResultIterator 在此被丢弃
// UAF: 访问已释放的内存
println!("Problem here: {:?}", tmp_row);
修复方案
修复主要包含以下几个方面:
1. 引入 Lending Iterator
将迭代器从 Iterator 改为 LendingIterator:
impl LendingIterator for ResultIterator<'_> {
type Item<'a> = Row<'a> where Self: 'a;
fn next(&mut self) -> Option<<Self as LendingIterator>::Item<'_>> {
unsafe {
match cass_iterator_next(self.0) {
cass_false => None,
cass_true => Some(self.get_row()),
}
}
}
}
2. 修正生命周期声明
修改 Row 结构的生命周期绑定:
// 修复前
pub struct Row<'a>(*const _Row, PhantomData<&'a CassResult>);
// 修复后
pub struct Row<'a>(*const _Row, PhantomData<&'a _Row>);
3. 更新使用模式
从 for-in 循环改为显式迭代:
// 修复前
for row in result.iter() { ... }
// 修复后
let mut iter = result.iter();
while let Some(row) = iter.next() { ... }
技术要点总结
- 安全边界:即使在使用 Rust 这样的内存安全语言时,
unsafe代码块仍可能引入漏洞 - FFI 交互:与 C/C++ 库交互时需要特别注意生命周期管理
- 迭代器设计:当迭代器内部状态影响返回项的有效性时,标准
Iteratortrait 可能不适用 - 生命周期标记:正确使用
PhantomData对跨语言交互至关重要 - 新特性应用:GATs 和 Lending Iterator 模式可以解决传统迭代器的局限性
防御建议
- 尽量减少
unsafe代码的使用 - 对 FFI 交互进行严格的生命周期管理
- 考虑使用像
LendingIterator这样的模式来处理有状态迭代 - 定期审计依赖库中的
unsafe代码块 - 及时更新到修复后的库版本(Cassandra-rs 3.0+)
参考资料
- Rust 官方文档: https://kaisery.github.io/trpl-zh-cn/title-page.html
- GATs 介绍: https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#generic-associated-types-gats
- Cassandra 官方文档: https://cassandra.apache.org/