核心漏洞点

核心漏洞点

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

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

相关推荐
weixin_457885822 小时前
智能多媒体处理流水线——基于虎跃办公API的自动化解决方案
运维·数据库·人工智能·ai·自动化
雾月553 小时前
LeetCode 941 有效的山脉数组
java·开发语言·数据结构·算法·leetcode·职场和发展
狮歌~资深攻城狮4 小时前
ClickHouse进阶技巧:解锁数据处理的高级潜能
大数据·数据库
晨曦5432104 小时前
函数和模式化——python
开发语言·python
极限实验室5 小时前
Easysearch VS Opensearch 数据写入与存储性能对比
数据库
Verdure陌矣6 小时前
游戏开发中 C#、Python 和 C++ 的比较
c++·python·游戏·c#
丰锋ff6 小时前
借助 AI 工具使用 Python 实现北京市店铺分布地理信息可视化教程
人工智能·python·信息可视化
橘猫云计算机设计6 小时前
ASP.NET图书馆借阅系统(源码+lw+部署文档+讲解),源码可白嫖!
java·数据库·后端·爬虫·小程序·毕业设计·asp.net
java1234_小锋6 小时前
一周学会Pandas2 Python数据处理与分析-Pandas2二维数据结构-DataFrame
数据结构·python·pandas
王伯爵6 小时前
接入网和核心网之间的承载网详细介绍
服务器·网络·数据库