软件防护方案存在的一个通病是只考虑“防”,不考虑“防”带来的副作用。一旦系统受到攻击,进入到防护状态,很多正常功能就大受影响。我们今天介绍的这篇论文——Unlimited Lives: Secure In-Process Rollback with Isolated Domains,它的作者显然希望能够在防护和正常运转中找到平衡。因此,作者设计了一套增强运行时异常处理弹性的方案,让我们一起看看这套技术方案的细节。
作者指出,现在的防护方案动辄采取“硬隔离”、“熔断”等手段,不利于软件的持续运行。为了在保证安全的同时增加软件运行的稳定性(想象一下生产环境分分秒秒不能停),作者提出了针对被保护区域(isolated domain)的安全回滚(secure rollback),主要应用在最近越来越流行的进程内隔离(in-process isolation)防护中。我们都知道,进程内隔离防护会把进程中的代码(通过各种软硬件策略)隔离而成不同的域(domain),不同的domain有不同的安全级别,这种设计虽然提供了很好的“分而治之”策略,但是对那些受到攻击的domain而言,隔离机制并不等同于错误处理,遇到问题往往就只能瘫痪掉。作者的安全回滚策略则是仔细考虑了受攻击的domain的”善后“,让出问题的执行状态回到最近一个稳定状态,保证整个进程能够持续不断前行。
来看看具体的代码实例。在下图这个有漏洞的程序中,第二行中(在stack上)分配的固定大小的buf很容易就会被攻击者overflow。尽管现代编译器提供的防护机制可以对抗大部分的stack overflow,但是带来的副作用是会让程序直接crash:
我们当然不希望一个很重要的生产环境中的应用程序在遇到攻击后无法正常工作(还记得之前的新闻吗 “4月28日,北京市新冠肺炎疫情防控新闻发布会透露, ‘北京健康宝’在当天上午使用高峰期遭受来自境外的网络攻击,经及时有效应对,相关服务未受影响。”),如果上面存在漏洞的代码能像下面这样改写,稳定性能够得到改善:
注意到上面的例子中,核心的函数是get_domain
,这个函数为可能存在问题的代码(即get_number
)执行进行了封装,如果执行过程产生异常,作者希望自己提出的安全回滚机制满足如下四条性质:
-
性质1:The mechanism must allow the application to continue operation after system defenses (A2) detect an attack.
-
性质2:The mechanism must ensure that the integrity of memory after recovering from the detected attack is maintained.
-
性质3:Run-time attacks that affect one domain must not affect the integrity of memory in other domains
-
性质4:The attacker must not be able to tamper with components responsible for maintaining isolation between domains, transitions between domains, or data used as part of the rollback process.
提出这些性质容易,要在工程上实现起来,有很多细节需要考虑(我们自己也做过fine-grained domain isolation,深知其中之艰辛)。和我们之前的CryptoMPK类似,本文作者也基于MPK硬件隔离机制,为开发者提供了名为SDRoB
的一套代码库,提供了一组API,帮助使用者在不知道细节的情况下,就可以实现自动化的domain创建和销毁,同时保证运行时domain出现问题可以回滚,听上去是不是很fancy!
如果大家关心SDRoB
的使用者在调用了get_domain
之后发生的事情,下面这幅图就展示了其中的完整逻辑:
注意到domain的进入和退出,有点像《盗梦空间》的逻辑(或者说《盗梦空间》那种从深层梦境里面逐个醒来、而遇到危险直接退出到最外层的逻辑本来就是从程序的异常处理逻辑里面抄过去的),既可以逐步退出,也可以强行退出到root domain这一外层。在异常回滚的设计实现上,SDRoB
也利用了比较标准的做法,使用C标准库里面的setjmp
和longjmp
来辅助实现,如果读者对此不熟悉,可以去了解一下C语言层面上这两个函数的用法。
另一个很麻烦的地方是针对domain中的内存的管理,一般我们都会主要考虑全局变量、stack和heap的管理,而作者基本上也是从这三类型内存对象来考虑,把内存分配重新定位到一个新的区域去单独处理。不过在实现过程中,为了性能的优化,有很多细节处理方法,建议大家去读论文的Section 4.3仔细了解一下。
作者选择了知名的内存数据库Memcached
作为实验对象,在其中重新“实现”了CVE-2011-4971,让程序在收到畸形数据包的时候会产生拒绝服务的效果,然后部署SDRoB
进行测试。
实验结果表明,SDRoB
在最坏情况下(单线程)也就增加了7.3%的开销,平均额外内存需求只增加了原来的0.4%,对于作者提出的4个安全回滚需要满足的性能,也都能满足(嗯论文里面当然都是这样^_^)
小编在读这篇论文的时候就想到,SDRoB
这个不是很适合给Rust这样需要引入一些unsafe code的语言使用吗?果然,作者在论文的讨论部分也说到了这个想法,接下来就看是我们的读者手速快,还是论文作者再接再厉,发表一篇Rust+SDRoB
的论文了!
论文PDF:
https://arxiv.org/pdf/2205.03205.pdf
原文始发于微信公众号(安全研究GoSSIP):G.O.S.S.I.P 阅读推荐 2022-06-21
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论