可信执行环境(TEE)是一种环境,其中执行的代码和访问的数据在机密性(没有人可以访问数据)和完整性(没有人可以更改代码及其行为)方面被隔离和保护。
TEE的必要性
软件越来越复杂,像Linux内核和Android开源项目(AOSP)这样的大型项目有数百万行代码,这意味着会有很多bugs。在修复某个漏洞时,有时还会造成新的bug,虽然我们可以防止某些类型的错误,但软件中总是会有错误。其中一些漏洞可能会暴露安全漏洞,更糟糕的是,如果bug在内核中,整个系统就会受到损害。
那么如何解决这个问题呢?如果软件遭到破坏,如何保护您在系统中的资产?
解决这个问题的一种方法是创建一个隔离的环境,在这个环境中,即使操作系统受到破坏,您的数据也会受到保护。这就是我们所说的可信执行环境(TEE)。
TEE用例
TEE术语和操作
在具有TEE的系统中,我们有运行在富执行环境(REE)上的不可信应用程序或者叫客户端y和运行在可信执行环境(TEE)上的可信应用程序(TAs)。
只有运行在TEE(安全世界)上的受信任应用程序才能完全访问主处理器、外围设备和内存,而硬件隔离保护这些应用程序不受主操作系统(非安全世界)上运行的不可信应用程序的影响。
尽管上面的图表举例说明了一个带有操作系统(可信操作系统)的TEE,但是我们可以使用一个裸机固件来暴露一个接口,该接口可以独占访问某些硬件资源。
在TEE中,所有受信任的应用程序(TAs)和相关数据都与正常(不可信)操作系统及其应用程序完全隔离。另外,受信任的应用程序必须与其他受信任的应用程序以及TEE本身隔离运行。
另外,TEE只接受经过适当授权并由其他授权代码检查的代码来执行。因此,在TEE中,我们需要一个安全引导特性来检查所有操作系统组件(引导加载程序、内核、文件系统、可信应用程序等)的完整性和真实性。这样可以确保在设备关机时没有人篡改操作系统的代码。
TEE实际上是一个执行环境(有或没有操作系统),可以独占访问某些硬件资源。但它是如何实施的呢?如何防止不受信任的应用程序从受信任的应用程序访问资源?
如何实现TEE?
我们可以在“沙箱”中隔离应用程序,例如使用容器。这将阻止应用程序查看和访问来自其他应用程序的数据。
但是内核呢?如何防止在内核空间中运行的代码被利用来访问受信任应用程序使用的某个外围设备或内存区域?
软件不能保护软件!
所以我们需要硬件上的支持来实现TEE。我们需要一种方法来划分和隔离硬件(总线、外围设备、内存区域、中断等),以便运行的代码不能访问受保护的资源。
这就是ARM的TrustZone、RISC-V的多区域和许多其他解决方案的用武之地。
实现TEE的硬件支持
在现代处理器中有许多技术可用于实现TEE:
通常,ARM Cortex-A 处理器有3种执行模式:用户模式、内核模式和hypervisor模式。在运行GNU/Linux的典型系统中,应用程序以用户模式运行,Linux内核以内核模式运行,而hypervisor模式不使用。
ARM的TrustZone引入了一种新的模式:安全监控模式。
在这种新模式下运行时,CPU处于安全状态,可以访问设备的所有外围设备和内存。不在这种模式下运行时,CPU处于非安全状态,只能访问外设的子集和特定范围的物理内存。
TrustZone 利用的是CPU时间片切换来模拟了安全世界,这两个世界(REE和TEE)可以将它理解成一个CPU上处理的两个进程,它们通过上下文切换来将CPU的时间片占满以利用CPU。从安全角度,仅仅分时复用或拟化,是不足以确保安全的,因此ARM另外定义了安全框架,从硬件级别两个世界,包括Timer、TRNG、TZPC、MMU、Cache等相关设备,不同的芯片厂商会有自己的考虑,这个设备可能是双份的,或者是动态切换以达到隔离目的。同时,安全侧也需要有一个可信操作系统执行应用。从原理上,REE侧和TEE侧是对等的,因此并不会性能的差异。应用程序的开发,除了使用TEE定义的标准接口,依赖的都POSIX API,使用标准的开发语言。
Trustzone技术硬件框图
当安全配置寄存器bit0为1时,CPU切换执行REE侧os,CPU不能访问安全模块和安全内存(提前配置好)。
当安全配置寄存器bit0为0时,CPU切换执行TEE侧os,CPU可以访问任何模块和内存。