首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用于C++代码的锈蚀当量,以演示对UAF的保护

用于C++代码的锈蚀当量,以演示对UAF的保护
EN

Stack Overflow用户
提问于 2020-07-26 20:22:30
回答 2查看 255关注 0票数 0

我试图了解Rust的终身注释是如何帮助捕获免费使用(UAF)问题的,而不会在功能上妥协。下面是我的代码:

代码语言:javascript
复制
use std::rc::Rc;

struct Foo {
    data: usize,
}

impl Foo {
    pub fn begin_foo(&self) {
        println!("Begin Foo");
    }

    pub fn end_foo(&self) {
        println!("End Foo");
    }
}

struct Bar {
    foo: Option<Foo>,
}

impl Bar {
    pub fn new(foo: Foo) -> Self {
        Bar {
            foo : Some(foo),
        }
    }

    pub fn get_foo(&self) -> Option<& Foo>
    {
        match &self.foo {
            Some(foo) => return Some(&foo),
            None => return None,
        }
    }
}

struct FooBar<'a> {
    bar : Option<Rc<Bar>>,
    foo : Option<&'a Foo>,
}

impl<'a> FooBar<'a> {
    pub fn new(bar : Option<Rc<Bar>>) -> Self {
        FooBar {
            bar : bar,
            foo : None,
        }
    }

    pub fn update_foo_1(&'a mut self)
    {
        if let Some(b) = &self.bar {
            self.foo = b.get_foo();
        }
    }

    // ERROR1
    /*
    pub fn update_foo_2(&mut self)
    {
        if let Some(b) = &self.bar {
            self.foo = b.get_foo();
        }
    }
    */

    pub fn invalidate_bar_1(&mut self) {
        self.bar.take();
    }

    // Inorder to drop the RC, we have to pass self and not &self, which consumes the object.
    pub fn invalidate_bar_2(self) {
        if let Some(bar) = &self.bar {
            println!("Strong ref count = {}", Rc::strong_count(bar));
            drop(self.bar.unwrap());
        }
    }

    pub fn use_foo(&self) {
        match self.foo {
            Some(foo) => println!("Foo.data = {}", foo.data),
            None => println!("Foo is None"),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn works()
    {
        println!("Works...");
        let foo = Foo {data : 42};
        let bar = Bar::new(foo);

        let bar_rc = Rc::new(bar);
        assert_eq!(1, Rc::strong_count(&bar_rc));

        let mut foo_bar: FooBar = FooBar::new(Some(bar_rc));
        
        foo_bar.update_foo_1();
        foo_bar.use_foo();
        foo_bar.invalidate_bar_1();
        println!("Exiting works()...");
    }

    #[test]
    fn fails()
    {
        println!("Fails...");
        let foo = Foo {data : 42};
        let bar = Bar::new(foo);

        let bar_rc = Rc::new(bar);
        assert_eq!(1, Rc::strong_count(&bar_rc));

        let mut foo_bar: FooBar = FooBar::new(Some(bar_rc));
        
        foo_bar.update_foo_1();
        foo_bar.invalidate_bar_1();
        foo_bar.use_foo();
        println!("Exiting fails()...");
    }
}

要求FooBar保存Bar,但也是对Foo的引用,以避免多次调用Bar::get_foo()FooBar::invalidate_bar_*()使Bar无效,使引用Foo悬空。

鉴于上述要求,下列调用顺序应有效:

代码语言:javascript
复制
foobar.update_foo();
foobar.use_foo();
foobar.invalidate_foo();

以下是无效的调用序列,必须在编译时捕获:

代码语言:javascript
复制
foobar.update_foo();
foobar.invalidate_foo();
foobar.use_foo();

但在我上面的代码中,这种情况并不完全发生。我所面临的挑战是:

  1. In FooBar::update_foo_1()我被迫用终身&'a注释self。否则,我将得到以下错误:

代码语言:javascript
复制
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> src/lib.rs:52:26
   |
52 |         if let Some(b) = &self.bar {
   |                          ^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 50:5...
  --> src/lib.rs:50:5
   |
50 | /     pub fn update_foo_1(& mut self)
51 | |     {
52 | |         if let Some(b) = &self.bar {
53 | |             self.foo = b.get_foo();
54 | |         }
55 | |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/lib.rs:52:26
   |
52 |         if let Some(b) = &self.bar {
   |                          ^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 42:6...
  --> src/lib.rs:42:6
   |
42 | impl<'a> FooBar<'a> {
   |      ^^
note: ...so that the expression is assignable
  --> src/lib.rs:53:24
   |
53 |             self.foo = b.get_foo();
   |                        ^^^^^^^^^^^
   = note: expected `std::option::Option<&'a Foo>`
              found `std::option::Option<&Foo>`

当我使用

  1. 来解决上述错误时,我不能进行任何其他需要在相同范围内对self进行独占引用的调用:

代码语言:javascript
复制
error[E0502]: cannot borrow `foo_bar` as immutable because it is also borrowed as mutable
   --> src/lib.rs:104:9
    |
103 |         foo_bar.update_foo_1();
    |         ------- mutable borrow occurs here
104 |         foo_bar.use_foo();
    |         ^^^^^^^
    |         |
    |         immutable borrow occurs here
    |         mutable borrow later used here
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-07-27 08:31:55

通过调用它,您将使FooBar成为一个在安全锈蚀中很难定义的自引用结构。

代码语言:javascript
复制
    pub fn update_foo_1(&'a mut self)
    {
        if let Some(b) = &self.bar {
            self.foo = b.get_foo();
        }
    }

编译器在这里正确地给出了错误:

代码语言:javascript
复制
error[E0502]: cannot borrow `foo_bar` as immutable because it is also borrowed as mutable
   --> src/lib.rs:104:9
    |
103 |         foo_bar.update_foo_1();
    |         ------- mutable borrow occurs here
104 |         foo_bar.use_foo();
    |         ^^^^^^^
    |         |
    |         immutable borrow occurs here
    |         mutable borrow later used here

因为如果在更新调用之后允许任何不可变的借款,那就意味着在这一点上没有可变的借款,这也意味着您可以在此之后进行可变的借款。

如果bar字段的强计数为1,然后执行以下操作,会发生什么情况:

代码语言:javascript
复制
drop(foo_bar.bar.take());

foo字段FooBar中将有一个悬空引用,这是Rust禁止的。

票数 2
EN

Stack Overflow用户

发布于 2020-07-27 08:35:50

Rust的生存期注释有助于捕捉免费使用(UAF)问题,而不影响功能。

铁锈的终身注解不会“捕捉”任何东西。他们所做的就是告诉编译器一些它可能无法推断的事情(即借用跨度多长)。

“捕捉”UAF问题的是仿射类型系统,即在移动之后(除非是Copy),源是不可访问的,并且您不能移动活动用户的结构(也就是有活动引用的结构,所有的借方都必须在移动结构之前结束)。

您没有在任何地方使用移动,因此您的FooBar对象始终是有效的。

至于update_foo_1问题,我认为这是你告诉铁锈的合乎逻辑的结果:

代码语言:javascript
复制
    pub fn update_foo_1(&'a mut self)

这意味着该方法正在创建一个可持续所有'a的借入。

'a是结构的一个参数,因此它需要“超过”结构本身,而且您是说在这个生命周期内只借用结构,这意味着'a与结构完全相同(这是合理的,因为您借用的是结构的一部分),您所做的唯一事情就是静态地将自己锁在使用该结构之外。

在Rust中,表示图形(/自引用结构)是很困难的,这正是你在这里试图做的,但更根本的是,你的整个努力似乎被误导了,而且是建立在误解的基础上。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63105314

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档