SGX是Intel实现的可信执行环境,主要面向服务器和桌面端,提供了内存加密(Memory Encryption)、访问控制(Access Control)、远程认证(Remote Attestation)、本地密封(Sealing)等功能。
0x00 Overview
关于应用程序代码与可信执行环境的基本关系:
- 每个application分为两部分:安全(可信)部分和不安全(不可信)的部分
- application启动后,会在受保护的可信内存中加载一块飞地(enclave)
- application通过把机密数据、代码放到enclave里来保证安全性
- enclave为application提供调用接口,当application调用enclave内的函数时,其内部的任何内存仅enclave自身可见
- enclave内存即使ring 0的攻击者也看不到,因为是CPU层面的保护。实际上在SGX的安全模型里OS、BIOS等等都可以被认为是不可信的
关于可信执行环境与用户进程的关系:
- application 本身包括了自身的代码、数据和enclave
- enclave里面也有其自身的代码、数据
- SGX保证enclave里面的代码和数据的integrity和confidentiality
- enclave的entry points在编译期就确定了
- enclave可以访问它所在的application里的内存,但是反过来不行
- 支持多线程
相关的指令,User模式下和Supervisor 模式下各自有相关的指令支持SGX的使用
Super. | Description | User | Description |
---|---|---|---|
EADD | Add a page | EENTER | Enter an enclave |
EBLOCK | Block an EPC page | EEXIT | Exit an enclave |
ECREATE | Create an enclave | EGETKEY | Create a cryptographic key |
EDBGRD | Read data by debugger | EREPORT | Create a cryptographic report |
EBDGWR | Write data by debugger | ERESUME | Re-enter an enclave |
EINIT | Initialize en enclave | ||
ELDB | Load an EPC page as blocked | ||
ELDU | Load an EPC page as unblocked | ||
EPA | Add a version array | ||
EREMOVE | Remove a page from EPC | ||
ETRACE | Activate EBLOCK checks | ||
EWB | Write back/invalidate an EPC page |
0x01 Memory
访问控制
首先介绍一下Enclave Page Cache (EPC)。EPC是用来存储enclave的代码和数据的内存区域,这部分内存是被CPU内部集成的专用协芯片Memory Encryption Engine (MEE)加密的,其密钥在CPU上电时生成,且仅储存在CPU内部。EPC里面的内存页只有在CPU物理核内部的时候才被解密,所有的外部访问都只能在总线上读取到加密后的数据。
用来存储EPC中内存页状态的结构体叫做Enclave Page Cache Map (EPCM),是一个安全内存管控的内置微架构结构体(internal micro-architecture structure),里面存储了EPC中每个内存页的配置、权限等信息。
。EPCM的大小限制了EPC的大小最多不超过128MB(新版SGX好像是256MB,由BIOS设定)。
具体的访问控制流程可以用下图表示
内存管理
由上述EPCM的解释可知EPC的大小比较有限,所以在很多个程序都要使用自己的enclave时,EPC的内存就不够用了。此时就需要有一个类似于Linux中的Swap Device这样的备用解决方案。在SGX中实现了与Linux的内存管理很相似的一套memory management策略,如下图所示。
当EPC中的内存被用完了的时候,SGX会将其中的一些不活跃的Enclave Page换出到系统存储里面,而在有程序访问到时再换入进来,类似Linux里的Page in/out。这里存储的除了加密的Enclave Page之外,还有一些用来保证完整性和存储信息的结构体SECINFO、PCMD等等。
内存分布
每个enclave的内存分布如下图所示。对于每个enclave,都有一个SGX Enclave Control Structure (SECS) 结构体与之绑定,其中存储了这个enclave的meta-data(例如hash和大小)。另外对于每个线程都有一个Thread Control Structure (TCS) 结构体,存储了线程相关的信息。这两个结构体都是仅能被CPU访问到的,其他的代码(无论普通代码还是enclave自己的代码)都不可以访问,同时一旦Enclave初始化完成之后这些结构体也是不可变的(immutable)。
0x02 Processor
创建Enclave
SGX的初始化,简单地说就是首先申请安全内存页,然后把Enclave代码复制进去,最后度量一下建立过程是否可靠:
- Application请求将自己的enclave加载到内存里
- 首先向OS请求一块EPC的内存
- OS返回EPC列表中的一块内存,表示把该部分的Enclave Page分配给Application
- Application执行ECREATE指令,参数为SECS的初始值。CPU执行该指令初始化该Enclave对应的SECS结构体
- Application使用EADD指令,参数为Enclave代码的源地址和目标地址,CPU执行指令将Enclave的代码复制到第1步中申请到的EPC内的一块内存空间
- Application调用EEXTEND指令,将Enclave的代码所在的每个Page都加入到度量中。这个度量(measure)是一个类似于HMAC的操作(个人感觉其实主要就是用对这堆Pages进行Hash来保证完整性?)
- Application调用EINIT指令,将上一步中的Hash值写到SECS结构体里,完成Enclave的初始化
对于步骤1,我们前面讲过应该认为OS也是不可信的,所以通过OS启动Enclave会需要一些额外的措施:Architectural Enclave这个特殊的Enclave(由Intel签名并启动起来的Enclave)会对Enclave的完整性进行签名保证,Enclave被OS启动过程中,相应的启动过程的度量会放在EPC的SECS中,最后会对AE签名的那个度量值比对,为了防止OS对Enclave启动过程中做小动作。 –引自 小谈Intel SGX
Enclave的调用流程
Application调用Enclave中提供的安全函数的流程如下图所示:
- Application执行EENTRY指令,调用需要的函数
- CPU首先将App的上下文存起来,放到EPC里
- 然后进入Enclave中执行代码
- 函数执行完毕之后,需要使用EEXIT指令退出Enclave
- CPU回到Application中继续执行
中断处理
如下图所示,当Enclave中发生中断的时候:
- 会产生Asynchronous Enclave Exits (AEX),传递给CPU
- CPU从TCS结构体中取出application的上下文,再将enclave的上下文保存在其中
- 然后将转到OS中的Interrupt Service Routine (ISR) 处理该异常
- 处理完之后然后交给Asynchronous Exit Pointer (AEP) 指向的一个application中的handler
- 这个handler负责用RESUME指令回到原来的Enclave发生中断的位置
- CPU从TCS结构体中取出enclave的上下文,再将application的上下文保存在其中
- 继续在enclave中发生中断之后的位置执行
0x03 Sealing and Attestation
认证这部分有两把密钥,一把在Intel需要通过网络连接认证,另一把在厂商手里。过程略有一点复杂,回头研究清楚再补充。
References
所有的图片均来自References
– 小谈Intel SGX
– Overview of Intel SGX – Part 1, SGX Internals