-
内存损坏(Memory Corruption):由于堆内存被FFI传递到了外部函数,Rust无法保证其安全性,从而内存管理的责任又回到了程序员身上。这意味着C/C++中常见的内存安全错误(例如use-after-free,double-free,内存泄露等),理论上都有可能发生。 -
异常安全(Exception Safety):Rust不支持其他语言中常见的try-catch语法来处理异常。Rust所采用的方式是,对所有可恢复的错误(recoverable errors),编译器要求程序员必须处理这些错误,或者将错误返回给上层函数,由上层函数处理;对于所有不可恢复的错误(unrecoverable errors),程序将终止执行并做栈展开(stack unwinding)。所有栈中的对象的析构函数(destructors)将会被执行,以防止内存泄露。然而当需要将Rust中申请的内存传递给外部函数时,程序员往往需要暂时创建不健全的内存状态(例如使用未初始化的内存),当外部函数执行完后,程序员再去清理这个状态以消除不良影响。如果有异常在外部函数执行时产生,程序终止执行并做栈展开,从而导致后续的清理操作不会被执行。未被清理的不健全的内存状态得以长期存在并造成安全漏洞。 -
未定义行为(Undefined Behavior):C库经常提供函数来创建或销毁堆对象(通常使用malloc和free函数来实现)。为了使用这些已有的库,Rust开发者经常需要将这些C函数加以封装。一个常见的问题是,开发者往往错误地混合使用不同语言的内存申请/释放。例如在Rust中使用Box类型申请堆内存,但在C中使用free来释放它。这样混合使用不同语言的内存管理机制是一种未定义行为。因为(1)Rust和C/C++可以使用不同的内存分配器,例如在Linux下,Rust可以使用jemalloc,而C默认使用ptmalloc;(2)Rust在创建/释放对象时会运行其构造函数和析构函数,而C的内存管理没有类似的概念。
原文始发于微信公众号(安全研究GoSSIP):G.O.S.S.I.P 阅读推荐 2022-10-18 FFIChecker
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论