RusTEE:开发内存安全的ARM TrustZone应用程序
最近在上网的时候,无意中刷到了一篇2020的论文,于是这里来一起学习一下。
前言
1-作者们做了什么?
这里作者为我们介绍了为什么要做这样的一件事情:用Rust语言来实现TA?
近年来,TrustZone被广泛用于在ARM平台上提供安全保护。它通过为安全敏感代码和数据保护创建可信执行环境(TEE)来实现系统范围的隔离,从而保护TEE的软件免受不可信的富执行环境(REE)的影响。
隔离是通过处理器中内置的硬件功能以及系统总线互连来实现的。
由于硬件辅助隔离的保护,基于TrustZone的系统承担整个TEE的信任变得很常见,包括运行在TEE中的可信应用程序(TA)。此外,通过在可信隔离环境中安装各种TA,TEE系统的功能得到了显著扩展。
尽管TrustZone技术可以确保TEE和REE之间的隔离,但据报道,数十个基于软件的漏洞会危害整个TEE系统。在报告的漏洞中,大多数是由内存不安全TA的内存损坏引起的。TEE系统受损的风险将随着安装TA的数量而增加。
在最新的ARM TrustZone架构下,“受信任的应用程序”一词仅指应被信任在TEE中运行的应用程序,但并不意味着该应用程序没有错误。
由于TA的两个体系结构特征,即与REE进行跨世界通信和调用内核特权系统服务API,REE侧攻击者可能会操纵TA来危害整个TEE系统。研究人员建议将TA的执行从TEE转移到REE,从而防止一个易受攻击的TA破坏其他TA或可信操作系统。尽管这些解决方案可以有效地降低易受攻击的TA的风险,但它们将不可避免地在系统上引入不可忽略的开销。
最近,许多编程语言都致力于提高内存安全性,并提出了几种以内存安全为目标的新语言,如Rust和Go。
同时,研究人员已经将内存安全语言从上层应用层(例如,Intel SGX Enclave程序)应用到下层系统层(例如嵌入式系统操作系统)。
用这些内存安全语言重写代码库的工程工作的一个先决条件是相对较小,这样开发人员就可以负担得起将现有软件转换为内存安全风格的费用。
同时,由于ARM TrustZone是为了保护数量有限的小型安全任务而提出的,因此TA成为另一个理想的内存安全语言重写目标。
在本文中,我们提出了一种称为RustTEE的机制,以使用Rust作为编程语言,以内存安全风格构建TrustZone辅助应用程序。
其基本思想是利用新兴的内存安全语言,并提供一个基于Rust的软件开发工具包(SDK)来编译内存安全TA,以防止内存损坏漏洞。
具体来说,我们解决了使用Rust开发TA的几个挑战。
- 第一个挑战是,没有一个TrustZone辅助的TEE系统和相关的ARM平台被公认为Rust的官方支持目标。因此,我们需要将Rust的所有基本支持(如标准库)集成到TA开发中。
- 其次,TA需要调用不同系统服务的API,这些服务通常被实现为内核特权库。由于一些低级库需要Rust不支持的特定ARM汇编指令,因此重写Rust中的所有库是不切实际的。受Rust SGX最近一项工作的启发,我们通过在Rust应用程序和C系统之间提供绑定层来解决这一挑战。绑定为依赖TA的库提供了所有必要的接口,同时还在有界接口上强制执行Rust的内存安全标准。
- 第三,我们解决了TA特有的挑战,即为TEE世界中的TA提供一个安全的跨世界通信通道,以便与REE世界中的软件进行通信。跨世界通信的安全性是通过规范TA对两个世界之间任何共享参数的使用来确保的。
在系统研究了TrustZone辅助系统的体系结构规范后,我们成功地将Rust导入到TA开发环境中,并进一步应用多种安全增强功能,可靠地调用系统服务API,安全地进行跨世界通信。
我们在开源项目OP-TEE OS的基础上开发了RusTEE的原型,并提供了各种示例来展示RusTEE的功能和效率。
我们已经开源了RusTEE原型以及内存安全TA示例。系统评估已在多个ARM平台上进行,包括AArch64仿真和真实世界的开发板Juno r1。根据我们的实验结果,在评估的示例中,RusTEE平均只引入1%的性能开销。
此外,RusTEE使TA能够与数百万个现有的Rust库集成,显著扩展了TA在TEE中的功能。
2-这样做的意义?
前面我们知道了背景。
那这篇文章实现了什么?
- 我们提出了RusTEE,这是第一个内存安全的可信应用程序开发环境,具有TrustZone辅助系统的全面功能。通过利用Rust编程语言的内置安全属性和优势,我们的可信应用程序环境消除了可信应用程序中大多数已知的内存不安全实现错误,从而增强了TEE的安全性。
- 我们解决了TrustZone辅助TEE系统的两个安全问题,即广泛暴露的系统服务API和跨世界通信通道,以增强基于Rust的可信应用程序的安全性。
- 我们实现了RusTEE的原型,并在模拟环境和实际开发板中评估了其性能。我们的实验结果表明,我们的系统可以遵守严格安全的Rust,并且只会产生最小的开销。我们将开源系统原型。
背景知识
TrustZone Architecture
这个架构如果是老朋友了,看这两个图应该很熟悉了!
自适应可信执行环境(TEE)已成为系统开发人员保护其安全敏感软件的一种流行方法。为了提供可靠的硬件辅助TEE,ARM在其最新的应用处理器上部署了TrustZone技术。TrustZone将TEE创建为一个孤立的环境,与易受攻击和不受信任的富执行环境(REE)相对运行。从硬件角度来看,ARM依靠其AMBA总线功能将整个片上系统资源划分为两个世界,正常世界作为REE,安全世界作为TEE。
从软件的角度来看,ARM网站[2]认为GlobalPlatform TEE规范(又称GPD规范)是最新ARM处理器上广泛使用的TEE架构。GPD规范通过在REE和TEE之间提供一套完整的软件定义,为TrustZone辅助TEE系统定义了明确的安全边界。目前,多个真实世界的TEE系统,如Linaro OP-TEE[34]和Trustonic应用程序保护解决方案[45],将GPD规范的设计应用于其实现中。
根据GPD规范,REE托管与用户特权应用程序相关联的丰富操作系统(例如,Android、Linux)。虽然大多数应用程序作为普通应用程序完全在REE中部署和使用,但一些安全敏感的应用程序可以对其敏感操作启用TrustZone保护。
安全敏感的应用程序将自己分为两个组件,一个是REE端组件,称为客户端应用程序(CA),另一个是TEE端组件,名为可信应用程序(TA)。
CA支持大多数非敏感功能,如用户交互;然而,对方TA和TEE都不信任CA。同时,所有敏感操作都被隔离为TA,TA通常在TEE内部的Trusted OS上运行。通过利用TrustZone硬件辅助隔离,TA的机密性和完整性受到不可信REE的保护。TrustZone辅助设备的整个GlobalPlatform体系结构如下图所示
哈哈哈,想起了以前自己写论文的时候最头疼的就是写Introduction,如何把重复的事情用不重复的话语描述出来,是需要技巧。
为什么用Rust
Rust是一种旨在实现可靠性和效率的编程语言。为了在两个不同的方面实现可靠性,即内存安全和线程安全,Rust提供了以下机制:
- (1)声称每个数据对象的所有权;
- (2) 自动检查每个对象的读/写权限(可变性);
- (3) 对所有对象实施终身管理;
- (4) 禁止不安全的打字(类型安全);
- (5) 禁用危险的原始指针操作,如指针别名或悬挂指针。
在程序编译过程中,如果代码违反了Rust的任何安全标准,Rust编译器会引发错误并生成错误消息,以帮助开发人员相应地更正代码。除了提高代码安全性,Rust还带来了其他好处,如高效的并行化、开发人员友好的编译消息,以及数千个板条箱(类似于C语言中的库)来支持不同的开发需求。
尽管Rust在默认情况下被设计为实现严格的安全标准,以确保任何程序都可以用Rust编写,但它也为开发人员提供了关键字unsafe[44],以注入内存不安全的代码段。
为了拓展性,这里主要是介绍了一下关于Rust的特性,这个语言我是之前做云服务的时候,玩golang的时候有纠结过用哪个,后面与Rust擦身而过。
动力与挑战
第三部分介绍了做这个设计的动力和挑战,动力主要是因为即使是基于TrustZone这个框架下,也存在了很多的安全问题。而且大多数是软件问题,所以做这个事情很有意义。
挑战主要是三个点:
- 1、挑战1:解决TA中的内存损坏问题
- 2、挑战2:提供安全的系统服务API
- 3、挑战3:建立对跨世界通信的保护。
实际实现
下面也不多说,就来看看这个设计实现是怎么玩的。
假设和威胁模型
我们假设该设备配备了ARM TrustZone技术,该技术可以提供硬件强制隔离。我们假设所有TEE系统的软件组件,包括安全监视器、Trusted OS和所有TEE内核特权库,都是按照GlobalPlatform TEE规范实现的。在这种情况下,TA使用GlobalPlatform定义的(GPD定义的)API与系统服务和跨世界通信通道进行交互。我们还假设这些系统组件写得很好,因此Trusted OS或较低级别的软件中不存在不安全的缺陷。因此,我们专注于保护运行在Trusted OS之上的TA的内存安全。最后,我们假设TA开发人员是善意的,而他或她可能仍然以脆弱的方式对TA进行编程,这是最近CVE中公认的常见情况。
概述
我们在图中展示了RusTEE的总体架构。
RusTEE的主要思想是在TEE中充当基于Rust的TA SDK。
SDK通过向TA开发人员提供Rust标准库和相关的基本组件,以严格的Rust安全风格支持大多数通用开发需求,例如操作原始数据类型。
在Rust编译器内置安全检查的帮助下,RusTEE确保TA的源代码没有已知的内存损坏错误,从而缓解了Challenge-1。
本质是就是限制了TA的开发,来通过约束实现TA的安全性。
除了执行通用操作外,TA还需要调用特定TEE的系统服务的功能,这些功能不在Rust标准库的范围内。
因此,RusTEE将额外的库集成到SDK中以支持这些需求。
有两种设计选项可用于提供带有附加库的基于Rust的SDK。
- 第一个选项是重写Rust中所有请求的库。
- 另一种选择是基于成熟的基于C的库构建基于Rust的SDK,并进一步在Rust和C组件之间提供可靠的绑定。
尽管第一个选项提供了更好的独立性和内存安全性,但在ARM TrustZone辅助平台上实现时,它面临着两个不小的挑战。
- 第一个挑战是,一些TEE的系统服务涉及特定于TrustZone的操作(例如,读取安全计时器),而这些操作只能通过Rust标准支持中不可用的明确的基本ARM指令来实现。
- 另一个挑战是,对于一些TEE的系统服务(例如密码学),基于C的库比Rust库具有更好的性能。
考虑到这些挑战,我们建议提供SDK作为绑定解决方案。在系统化研究了这些额外涉及的库的所有关键数据结构和功能定义后,RusTEE将所有接口转换为Rust-safe风格,以解决Challenge-2。
同时,TA过去面临着处理通过跨世界通信信道传入的命令和参数的挑战,因为这些数据是由不可信的REE生成的。通过仔细审查现有跨世界通信的呼叫约定,我们重新设计了TEE的系统通信组件(TEE-Agent)与TA之间的连接接口。重新设计的通信接口保证所有参数都在安全标准下使用,因此可以处理Challenge-3。
最后,RusTEE提供了REE侧SDK,该SDK遵循了TEE侧SDK的类似方案,作为规范CA行为的补充组件。
请注意,TA的安全性并不取决于REE是否使用REE侧SDK,并且只有在善意的CA开发人员希望提高CA的内存安全性的情况下才提供REE侧的SDK。
小结
还是蛮有意思一个角度去关注安全。毕竟一个安全的架构,是一个设计到很多的方面,软件架构的选型、硬件逻辑的设计、内存安全语言等等很多个方面考量。
如果你玩过Rust,也在搞安全,对这方面感兴趣的可以去看一下这篇文章,链接放在文末了!!!
引用链接
[1] 【RusTEE: Developing Memory-Safe ARM TrustZone Applications】
作者:Hcoco
文章来源:TrustZone
推荐阅读
硬件安全机制
ATF(TF-A)通用威胁模型-安全检测与评估
从硬件架构与软件架构看TrustZone
特约专栏 | 软件分区设计,汽车功能安全可以从航空安全实践中得到哪些思考?
更多物联网安全,PSA等技术干货请关注平台安全架构(PSA)专栏。欢迎添加极术小姐姐微信(id:aijishu20)加入PSA技术交流群,请备注研究方向。