核心漏洞点

核心漏洞点

那漏洞到底出现在哪儿呢?回到我们分析的第一个点以及维护者提到的next,这个漏洞应该是由于迭代器引发的,那么本质上应该是一个迭代器相关的点触发的问题。重新检查patch,会发现一个很容易忽略的点,在许多的example文件中,都出现了类似的修改

复制代码
-   for row in result.iter() {
+   let mut iter = result.iter();
+   while let Some(row) = iter.next() {

最初我以为这个修改无关痛痒,毕竟这个看起来只是用法不同。然而当我强行将其改成修改前的调用模式时,会提示如下的问题:

python 复制代码
error[E0277]: `cassandra_cpp::cassandra::result::ResultIterator<'_>` is not an iterator
  --> examples/simple2.rs:19:16
   |
19 |     for row in result.iter() {
   |                ^^^^^^^^^^^^^ `cassandra_cpp::cassandra::result::ResultIterator<'_>` is not an iterator
   |
   = help: the trait `Iterator` is not implemented for `cassandra_cpp::cassandra::result::ResultIterator<'_>`
   = note: required for `cassandra_cpp::cassandra::result::ResultIterator<'_>` to implement `IntoIterator`

换句话说,这个写法会直接导致错误,因为修正后的ResultIterator并没有去实现Iterator的特征。实际上作者也进行了相关提醒:

python 复制代码
/// An iterator over the results of a query. The result holds the data, so
/// the result must last for at least the lifetime of the iterator.
///
/// This is a lending iterator (you must stop using each item before you move to
/// the next), and so it does not implement `std::iter::Iterator`. The best way
/// to use it is as follows:

结合报错以及生命周期声明,这里会注意到几个特点

  • 修复后的漏洞并没有继承Iterator,而是使用了自行定义的迭代器特征,所以才没办法使用for-in-loop
  • ResultIterator是一个C++中的对象,其中包含了一个Row对象,而非指针
  • ResultIterator的生命周期和Row的生命周期在Rust中并非强绑定关系

修复公告中强调ResultIterator不在支持Iterator而是LendingIterator,观察其代码如下

复制代码
  impl<'a> Iterator for ResultIterator<'a> {
-       type Item = Row<'a>;
-       fn next(&mut self) -> Option<<Self as Iterator>::Item> {
+   impl LendingIterator for ResultIterator<'_> {
+       type Item<'a> = Row<'a> where Self: 'a;
+
+       fn next(&mut self) -> Option<<Self as LendingIterator>::Item<'_>> {

这个修改前 的代码具有一定的迷惑性,乍一看它和修改后一样,都保持了ResultIterator和Item指代的Row类型生命周期长度一致 ,只不过一个直接显示的指定生命周期,一个使用了Self;一个使用Item指定了带有生命周期的Row<'a>,另一个声明了有生命周期的Item<'a>。然而实际上,Row<'a>的生命周期并非就是真的是Row对象。这里可以检查定义

复制代码
/// A collection of column values. Read-only, so thread-safe.
-   pub struct Row<'a>(*const _Row, PhantomData<&'a CassResult>);
+   //
+   // Borrowed immutably.
+   pub struct Row<'a>(*const _Row, PhantomData<&'a _Row>);

如果结合这段代码看,我们就能发现,修改前的ResultIterator的生命周期,实际上和Row中指定的CassResult生命周期保持一致。CassResult这个对象提供了接口获取ResultIterator对象,他们之间的关系类似于

python 复制代码
CassResult --- Create --> ResultIterator 
                            |
                            +-- Create from self --> Row

从设计角度上看,也没太多问题,毕竟查询结果的每一行的生命周期与查询结果一致 是理所当然的。然而在实现过程中,Row自于ResultIterator,而这没有显示的指明Row与ResultIterator的关系 ,这就导致在修改前ResultIterator和Row在Rust中允许生命周期长度不同,而在C中这两个对象却来自于同一块内存 。这种场景中,一旦声明变量为Row类型,并且生命周期长度超过了ResultIterator,就会导致Row对象在ResultIterator被销毁后依然被使用。同时,由于生命周期声明错误,Rust编译器也会无法察觉当前问题,就会产生前文提到的UAF问题。

举个例子(这个代码只用于示范,无法运行)

复制代码
let mut tmp_row = None;
let result = function.get_result();
{
    for row in result.iter() {
        if condition.satisfied():
            tmp_row = Some(row)
            break;
    }
}

println!("here will cause problem {:?}", tmp_row);

实际上,这种代码在实际中很可能存在

相关推荐
fen_fen21 小时前
Oracle建表语句示例
数据库·oracle
好家伙VCC1 天前
### WebRTC技术:实时通信的革新与实现####webRTC(Web Real-TimeComm
java·前端·python·webrtc
砚边数影1 天前
数据可视化入门:Matplotlib 基础语法与折线图绘制
数据库·信息可视化·matplotlib·数据可视化·kingbase·数据库平替用金仓·金仓数据库
YYuCChi1 天前
代码随想录算法训练营第三十七天 | 52.携带研究材料(卡码网)、518.零钱兑换||、377.组合总和IV、57.爬楼梯(卡码网)
算法·动态规划
orange_tt1 天前
Djiango配置Celery
数据库·sqlite
前端玖耀里1 天前
如何使用python的boto库和SES发送电子邮件?
python
serve the people1 天前
python环境搭建 (十二) pydantic和pydantic-settings类型验证与解析
java·网络·python
小天源1 天前
Error 1053 Error 1067 服务“启动后立即停止” Java / Python 程序无法后台运行 windows nssm注册器下载与报错处理
开发语言·windows·python·nssm·error 1053·error 1067
云小逸1 天前
【nmap源码学习】 Nmap网络扫描工具深度解析:从基础参数到核心扫描逻辑
网络·数据库·学习
肉包_5111 天前
两个数据库互锁,用全局变量互锁会偶发软件卡死
开发语言·数据库·c++