核心漏洞点

核心漏洞点

那漏洞到底出现在哪儿呢?回到我们分析的第一个点以及维护者提到的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);

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

相关推荐
加勒比之杰克6 分钟前
【数据库初阶】MySQL中表的约束(上)
android·数据库·mysql
庞传奇7 分钟前
【LC】191. 位1的个数
java·数据结构·算法·leetcode
胜天半月子8 分钟前
Python | 学习type()方法动态创建类
开发语言·python·学习
鳄鱼的眼药水1 小时前
TT100K数据集, YOLO格式, COCO格式
人工智能·python·yolo·yolov5·yolov8
Tomorrow'sThinker1 小时前
25年1月更新。Windows 上搭建 Python 开发环境:Python + PyCharm 安装全攻略(文中有安装包不用官网下载)
开发语言·python·pycharm
健康平安的活着2 小时前
redis7基础篇2 redis的主从模式1
数据库·redis·缓存
白宇横流学长2 小时前
基于Java的银行排号系统的设计与实现【源码+文档+部署讲解】
java·开发语言·数据库
C++忠实粉丝2 小时前
Redis List列表
数据库·redis·缓存
123yhy传奇2 小时前
【学习总结|DAY027】JAVA操作数据库
java·数据库·spring boot·学习·mybatis
Evaporator Core2 小时前
SQLite简介:轻量级数据库入门
数据库·sqlite