赞
踩
目录
uRTS维护Enclave、tRTS端构建Enclave总结
Intel SGX的目标就是为了解决目前日益受关注的“远程计算的安全问题”。
以云环境为例子,云租户会将自己的产品部署在云平台中,但是云平台现在普遍认为是一个不可信的地方,因为可能会有云平台管理者、同一云主机其他租户的恶意攻击,也可能云平台本身存在漏洞,使得黑客轻易的攻击并拿到Ring0权限(就好比我租了房东的一间卧室,我害怕房东、其他租户、陌生人对我房间东张西望,甚至搞破坏。)。这种情况下,云租户就开始担心了。
与此同时,Intel SGX出现了,它对自己做了一个安全内存Enclave的概念,对安全内存实施权限控制、加密等安全措施,防止别人(Ring0级别的攻击者)非法对安全内存内的敏感数据代码进行机密性、完整性、真实性的破坏(Intel SGX对可用性并不保障),其中完整性主要通过可信建立Enclave保证,真实性通过由硬件背书的本地/远程认证来确保。就好比我租了房东卧室后,我对自己卧室的墙进行加固,并且对门加上自己的锁(内存访问控制),甚至让房间内的东西也进行上锁(内存加密),不让人家偷窥、搞破坏。
除了云环境,Intel SGX旨在防所有Ring0级别的攻击者(OS、VMM等),服务器中也可以对敏感部分就行加固。开发商下放版权也可以放到客户端的SGX保证版权保护。此外还有对区块链这种分布式客户端的形式就行客户端本地的SGX保护。
Intel SGX在学术圈属于非常热门的一个点,论文很多,这说明大家感觉Intel SGX的安全特性很有意义,也说明Intel SGX目前也有不少值得探讨的问题存在。
由于Intel SGX会导致应用开发方式的不同,使得Intel SGX很难真正用于实际生产,这里主要指无法将原有的产品直接放到SGX中,这是第一点。第二点,对于未来将开发的产品,由于产品往往依赖于某些库,但是实际中,这些库并没有人将它费劲的搬到SGX中,导致SGX只有Intel维护的标准C/C++库等,并没有丰富的库,导致Enclave内部开发起来也费劲。此外,Enclave内部目前应该只支持C、C++的开发,Python、Java这种个人感觉更适合上层开发的语言目前没有支持。
上述说明SGX是个学术宠儿,但是实际应用中,除非工业界非常感兴趣,不然没有那么多人力物力将不重要的产品搬到SGX中。所以就看产品是否敏感到非用SGX不可。
此外也有Graphene-SGX等能够让传统APP不需要改代码就能跑在SGX中,但是其会引入LibOS等相关内容,使得Enclave内部冗杂,TCB变大;并且效率受影响,SGX本身由于进出Enclave刷新TLB等安全措施导致效率有损耗;兼容性值得考量,个人不是很了解LibOS,但是对LibOS能够提供的兼容性值得考虑。
以我现在观察发现,基于Graphene-SGX等的产品数量貌似不如直接用SGX开发的多,(这个观察不一定准确),一方面是Graphene-SGX知名度不如SGX,一方面是Graphene-SGX出现时间也略晚,还有一方面就是Graphene-SGX某些特性上并不如直接从SGX开发来的高效,稳定。
Intel SGX的好伙伴——ARM上的TrustZone,我们似乎也没有观察到TrustZone也有很普遍的应用,一般还是敏感到需要用到了才不得不用。(观察不一定准确)或许未来又是另一番场景,我便不得而知了,但是可以肯定的是SGX想要广泛应用,必须要SGX支持足够的中间件、库,能让上层便捷的开发。
Intel SGX还有一点比较要命的就是,它对性能会带来一定程度的影响,出入Enclave会有3k+ Cycle,而系统调用也就0.2k+Cycle,另一个由于EPC容量有限,目前最大只支持256M,EPC的Swap相对会比较频繁,并且会引起40K+Cycle。
希望有一天,若为安全故,两者皆可抛?毕竟解决远程计算安全问题的需求还是很大的。
在SGX之前,可信计算中可信启动其实挺火,主要是说从底层Bootloader->BIOS->OS/VMM->APP的一步步递进的可信度量和启动。但是这种模式局限程度高,而且也有人说这限定了就几个大厂的产品满足可信启动的条件,相当于某种垄断。而且这种效率其实也有影响,且TCB大。
SGX主要还是CPU硬件里面强制将某块内存定义为安全内存,并施加硬件级别的访问控制等,这样的话,就不要求整个主机都是可信的,只要SGX所管理的Enclave安全内存是可信就行(包括Enclave代码的可信度量和建立)。
下面这个是画的旧图。
简单来说SGX就是提供了一个安全内存及其相关。下面稍微讲一下SGX软件栈结构(具体见《SGX软件栈》文档)
总的来说,SGX是划分两个世界的——可信世界和不可信世界。每一个世界中,想要使用SGX的开发都需要开发哪一个世界的代码,一般来说,不可信世界开发非敏感代码(称为APP,另一种理解就是APP也包含Enclave,这样为了区分,就把不可信的叫做APP),可信世界开发敏感代码(Enclave),或者说敏感代码移入了可信世界。
既然有了两个世界,他们之间的连接就需要有一个叫做桥函数的东西,ECALL桥能让APP可以调用桥函数间接调用Enclave中写好的API函数。反向的有个叫OCALL桥的东西。桥函数上承载着两个世界间传递的参数,而且ECALL中,Enclave并不信任APP传给Enclave的ECALL参数,所以需要参数的消毒检查。OCALL有点类似。
既然要开发程序,就要用到SDK(我这里是把可信Enclave使用的SDK称为SDK,这也符合Intel的叫法,另一种理解是SDK包括给不可信APP使用的PSW、给可信Enclave使用的SDK、桥函数)和PSW,这两个都是Intel提供的(linux下见github.com/intel/linux-sgx)。由于Enclave要保证自己内部开发的函数尽可能不会离开Enclave,所以Enclave内部用的SDK都是用静态库链接,除非万不得已,比如系统调用等,那么就得同OCALL桥到不可信世界完成任务。然后顶多是启发式的对OCALL返回值进行检查(而且目前Intel并无消毒检查,除非Enclave开发者自己做检查)。
PSW、SDK一部分功能是用于我们传统的那种为了具有某个功能而开发的函数,还有一部分是对CPU提供的SGX功能指令的包装,主要用于SGX特性的支持,为了让你真正和CPU沟通,并获得SGX特性支持。SGX特性是通过CPU向外面提供Ring0指令和Ring3指令,其中Ring0指令ENCLS主要有一些比如创建Enclave这种生命周期管理、页权限管理的指令。Ring3指令ENCLU主要是让控制流能够在两个世界之间流动,比如进出Enclave这种。
这一块的细节可以看《SGX软件栈》。
SGX访问控制是说对Enclave安全内存进行访问控制,不能让攻击者非法访问敏感内存。这主要还是通过CPU内部实现的。有SGX特性CPU能够让不可信APP只有满足进入它的Enclave的条件时才能放行,而且Enclave A和Enclave B之间是互相不可访问的。这种逻辑是CPU里面的EPCM和内存RAM中被CPU定义为EPC里面的SECS结构体、TCS结构体这些单元连动完成的。
《SGX技术的分析和研究》有介绍具体有哪几则访问控制。
EPC,Enclave Page Cache,是被加密的安全内存页,由MEE加密。
MEE是Memory Encrypt Engine,内存加密引擎,会对从CPU缓存、寄存器之类的地方往其他如内存(比如EPC)、硬盘运输之前都加密,因此在内存、硬盘的敏感数据都是加密的。
这种好处就是能够抗总线攻击,防止攻击者直接物理连接总线窃取敏感数据。劣势,就是或多或少会有加密导致效率的影响,虽然说MEE已经是一个专门的用来加密的模块。
这张图主要是讲SGX初始化过程的,也可以拿来讲解CPU里面多了哪些部件。下面中间RAM这个是内存,内存里面一部分EPC就是存放Enclave的安全内存池,里面有多个安全内存页,每个Enclave按需从这里拿取Enclave安全内存页。
最左下角EPCM(Enclave Page Cache Map)是一个安全内存管控的内置微架构结构体(internal micro-architecture structure ),会由PMH硬件模块进行查EPCM,进行访问控制。PMH和EPCM主管对EPC的访问控制,会依赖SECS、TCS联动判断。
图片右下角就是CPU及其MMU、MEE部件,MMU是传统的地址翻译部件,MEE是说SGX能够做到在EPC中的敏感数据能够明文存在(因为有访问控制,不担心被偷窥),但是EPC中的数据一旦会转到普通硬盘中的(由于EPC大小一般是256M,因此会出现换入换出到硬盘的情况),那么MEE就加密那个明文,只让密文存在于硬盘中。其实MEE不单单是对换入换出到硬盘就行加密,它对任何离开CPU安全边界的明文都进行加密。
最左上角是Enclave代码,这里代表的意思是Enclave代码已经放到了EPC中,然后图片上讲原来在RAM的EPC中的Enclave,单独画出到外面来,它本质是存在于EPC中的。
上面这个APP和Enclave代码是一个二进制文件,最终会被加载到内存的普通内存(APP部分代码)和安全内存中(Enclave部分代码)。
中间OS是在Enclave启动过程中(从无到有),完成对安全内存页申请,代码复制进安全内存页等一系列操作的管理(《SGX软件栈》文档中有专门讲这个)。我之前说了OS是不可信的,所以通过OS启动Enclave会需要一些额外的措施:Architectural Enclave这个特殊的Enclave(由Intel签名并启动起来的Enclave)会对Enclave的完整性进行签名保证,Enclave被OS启动过程中,相应的启动过程的度量会放在EPC的SECS中,最后会对AE签名的那个度量值比对,为了防止OS对Enclave启动过程中做小动作。
总结一下,CPU本身扩充了很多硬件指令,可以分为两大类ENCLS、ENCLU。上图可以看到CPU所增加的硬件部件,有MEE、PMH(查EPCM)、Intel ME(粗粗了解到它提供可信输入和可信时间)(其他暂且没想到,似乎还有)。
SGX初始化过程大概就是建立时候申请安全内存页,然后将Enclave代码放进去,并且度量建立过程是否可靠。(细节见《SGX软件栈》)
APP依然还是那个APP,有着常见的虚拟地址空间(比如4G,32位地址下),然后其中有一整块,比如0X700-0X800(通过观察一般都是高地址,这里只是随便写了)是给Enclave的,因为Enclave是一个.so动态库链接给APP的,Enclave虚拟地址的起始地址依赖于ALSR地址空间随机化给定。
那我们假设访问某个Enclave函数时,我们用的这个函数的虚拟地址(和正常虚拟地址空间里面调用函数一样),然后会经过MMU的虚实地址转换,变成物理地址,这个物理地址会指向EPC,前面讲了EPC是RAM中的一部分(而且是靠前的一部分,存在于PRM中,由BIOS和范围寄存器来决定EPC的大小),所以EPC也是有物理地址的,这也很正常。物理地址拿到后,想要访问EPC物理页,那么请先经过EPCM的访问控制检查。如果通过了,那么IP寄存器就会给到那个Enclave函数了。
和传统应用开发不同,上图可以看到APP、Enclave是分开编写的。命名倒是无所谓,具体会通过Makefile里面说明把哪些编程Enclave。
此外,通过这个EDL文件可以清楚的看到光是进出Enclave的接口就分开了。一部分trusted括起来的是ECALL用来进入Enclave,untrusted括起来的是OCALL,用来离开Enclave。
要知道可信执行环境不止Intel SGX一家,所以很多思想可能值得借鉴的地方,并且,应该是能够以可信执行环境一个更高的高度来看待这些应用攻防的问题。
硬件比如还有TrustZone、RISC-V KeyStone、AMD SEV、RISC-V 蓬莱TEE。软件有Virtual Ghost、SP3、Overshadow、InkTag、CHAOS、AppShield(这个不一定准确),他们都或多或少有类似Enclave的可信执行环境的概念。
SHIELDING SOFTWARE FROM PRIVILEGED SIDE-CHANNEL ATTACKS(SEC’18)这篇是关于Virtual Ghost的工作。它做了两个工作。第一,针对已有的页表侧信道,它的做法是将页表机制由Virtual Ghost内部来完成,OS所保管的Direct Map中对于Virtual Ghost内部安全有用户空间的映射被删除。第二,针对LLC侧信道,利用Intel Cache Allocation Technology,从硬件层面对LLC实施隔离,不让OS窥探Virtual Ghost内部的存放于LLC中隐私。Intel CAT技术是Intel RDT的子模块,我目前感觉和SGX一样是向用户态提供Ring3指令用于CPU特性管理(可能存在错误)。
接下来我们讲讲现在有哪些SGX的研究了。分类方法主要依赖于CCS’17中,关于SGX的三篇综述
这一类个人觉得很需要结合代码、它们所描述的行业需求和以前的行业产品去考虑问题,毕竟是应用,不然可能体会不到精髓。
我对SGX应用的理解也停留在表层,就是他们拿SGX大概做了个啥,但是有些细节,我目前也说不太上来。
DelegaTEE(SEC’18) Siniša Matetić (ETH Zurich)下一篇也是他
以前Alice(Owner)想将自己部分Paypal中的资产给Bob(Delegatee),需要将账户密码交给对方,这很不安全。(我们不考虑钱能直接通过转账,因为有的资产并不像转账那样可以简单实现,那样单纯是金额的加减。我们讨论的是一大类授权的问题)。
那么现在用上一个凭证和对凭证以及用户身份信息验证的一个服务器Brokered System。Brokered System能够根据Alice具体将多少资产以怎么样的形式分享给Bob这件事生成凭证,并且凭证一方面分享给Bob,另一方面储存在服务器中,Bob登录服务器后,证明自己是Bob,并且把凭证给服务器一看,服务器觉得OK并且Bob想用掉这笔资产的时候,服务器就让Paypal去完成比如支付Money的操作,可以看到验证的事情被放到了Brokered System服务器上面去做,Paypal直接和Brokered System合作,而不再和用户直接接触。带来的好处是什么呢?是Paypal和Bob、Alice之前不需要互相信任,再无瓜葛,只需要信任Brokered System即可。这里可能看起来是一个妖异的设定:我的理解是因为本来Paypal没有这个功能,Brokered System作为第三方模块来实现这个功能,想尽办法完成这种类似可信红娘的牵线工作。
那么我们似乎还没说到SGX。我们可以看到这时Brokered System中凭证的存储、验证、使用非常敏感,同时Alice和Bob的个人信息也需要被严格保护,作者就想到使用SGX来对这个服务器来进行保护。所以这里应该来说时SGX在服务器端的简单尝试,更多的是授权的内容,但是授权的方式已经就有类似的(Kerberos系统也是授予ticket,和使用ticket的模式),所以它讨论的亮点还是SGX的应用,难度可能在于SGX的开发并且做成一个实际产品。
这篇论文通过视频看的,可能理解不到位,有错误欢迎反馈。
BITE(SEC’19) Siniša Matetić (ETH Zurich)
区块链中,我们知道手机等资源有限设备是不可能承载一个区块链的完全节点,所以手机上一般都是轻节点,并且轻节点是根据需求向完全节点申请当前涉及的区块等信息。但是Light Node向Full Node请求地址对应内容时,Full Node势必要知道你所请求的啥,导致信息泄露。之前有个Bloom Filter试图通过一个类似哈希表(或者是个承载多个对等数据单元的数据结构)并且模糊化访问这个数据结构的过程来解决这个信息泄露的问题,但是作者说共享Bloom Filter依然会导致信息泄露(Bloom Filter这一块我只是大概听说过,不了解)。
那么有了SGX这个东西,作者就利用SGX内部部署Full Node端用来接收Address请求的模块,这样部署在服务器上也不用担心Ring0攻击者的迫害了。所以本质也是SGX对原有产品的改进。此外有一些细节是说:通过Scan Window或者ORAM来返回结果值,为了保证SGX执行中的侧信道问题。ORAM已经有挺多论文用来防止访存侧信道问题,后面也会提到(【写到后面时把名字贴上来】)。现实中,走路时拐七绕八的方式让陌生人不知道我们具体要去哪里。你可能说,陌生人会看到我们最终进入哪个建筑,那么如果说有那么一个传送门,进的看起来是A建筑,实际传送到了B建筑,(这是通过查表转换实现),那么陌生人就只能犯糊涂了。这里需要知道的就是说ORAM可以通过类似上述方式让攻击者无法得知受害者的访存情况。
(可以看到目前SGX应用在某些知名产品上,对原有模块的替换或改进,会受到大家很大的关注。)
EnclaveDB(S&P’18)微软和伦敦帝国学院合作的
数据库DB可以说是大部分产品都要依赖的东西,计算机世界基础中的基础。但是现在服务器里面大家都考虑Ring0攻击者的威胁了,那么DB里面的资料可不能让Ring0攻击者偷取,因为人们对于敏感信息的保密要求是越来越高。以前有通过加密方式的DB,加密的方式效率低,这个可想而知,加密算法固有的缺陷。
那么服务器有了SGX,我们就干脆将部分敏感的数据库放入Enclave,通过SGX而不是加密方式来保证安全,同时通过完善的日志记录模式和事务备份恢复来保证完整性。上图蓝色是可信的部分,客户端默认是可信的,一般用户自己不会坑自己,这里不考虑自己电脑被攻击了,只考虑服务端有Ring0攻击。第一步,我们在右上角的东西比如可信DB、预编译的Stored Procs会被通过签名加密等安全措施,被部署到服务器端的Enclave。第二步,其他客户端申请查询请求时候,通过自己的Client库通过左边Host Process间接和Enclave搭上勾并进行真正的查询操作。
这一篇从视频上来看,它告诉我们SGX应用要考虑部署和使用两件事。
小结
上图是CCS’17上一位大佬讲的SGX服务端应用的论文列表(部分文章其实也可以归于SGX Shield Framework类,后面单独拎出来),和我随机看的那几篇有交集。但是我有一个明确的感受就是,想要做SGX应用,得有原来那种产品的很清楚的了解,我光看视频没法深入理解SGX应用的真正意义。以后若有需求会去看论文或者相关的代码框架。
不过总的来说,SGX应用是真正体现SGX价值的地方,现阶段的SGX应用可能思路上简单(实现可能也复杂),但是这将代表SGX这项技术是有意义的。并且服务端的SGX应用你需要考虑SGX应用部署和使用两件事。
另外值得一题的是,我们多多少少可以看出SGX是同态加密的一个好的替换品。同态加密是通过密码学的方法让你无法感知(秘密+秘密=秘密)这个过程,而SGX就是在保险箱里面完成(秘密明文+秘密明文=秘密明文)的工作,明文算起来就很快。
这一块的内容相对少一些,目前大家所能想到的就是比如游戏开发商在下放游戏许可证等版权信息的时候,那么就用SGX内部来保存版权信息,你想玩游戏,得通过SGX内部版权信息的验证。但是我觉得这一点上,可能对于很强的逆向工程高手来说,可能无意义,因为逆向工程逆向的是代码,SGX内部的敏感数据显得不重要了。除非游戏里面的部分关键代码也在SGX里面(个人猜测,正常情况下,Enclave代码是公开可见的,SGX保护的是代码完整性,SGX保护的机密性是隐私数据的机密性,不过也有论文是能够将Enclave代码秘密地加载到SGX中),那么逆向工程会变得极其困难。
这张图大概展示了客户端SGX应用的大概样子,主要我个人对OTP不懂,所以不太好阐述,但是我们可以看到这个框架就是客户端SGX和开发商之间有安全授权、配置的过程,那么Enclave可以看作开发商的飞地了(可以联想领事馆这个概念)
这类的论文和工作也不多,主要可能大家想法有限。我自己有一个想法就是分布式SGX客户端下,我们可以将服务端的某些贴近客户端的部分功能(或者全部功能)给移到客户端来降低服务端的攻击范围和单点失效问题。有一点像客户端冗余来弥补服务端单点的种种问题。
分布式SGX可能的应用模式
有了SGX,我们可以将中心化任务做成分布式,而不用担心分布式客户端上的用户会故意不按照预期流程执行,因为SGX已经不能被Ring0攻击了。这有点像我有个公司,我把我们公司的会计、法务都给派到了顾客家里,而且这会计和法务是绝对忠诚的。
以前也有分布式相关的工作,但是方式都通过加密、冗余备份来实现可靠性。而我们通过SGX先天提供可信执行环境,那么就不再需要加密、冗余备份的操作,而且将流程化简,功能性和扩展性也可以很好的提升。因此又体现了:SGX是加密方案的高效替代品。
中心化任务分布式程度理论上是可以调节的,就是具体有多少模块贴近客户端。借此我们可以可以根据分布式SGX的计算资源和存储资源的多少来进行一个具体的中心化任务分布式程度的界定。
其实上述这种抗Ring0攻击的Enclave其实不单单只有SGX可以做到,还有其他SGX的小伙伴也能。有一篇【SecTEE】讲的是Trust Zone下提供Enclave的概念,它里面说只要提供隔离机制的CPU均有望实现Enclave。
上面大概讲了下SGX分布式应用的一种可能模式,那么具体的可能可以用于分布式存储、分布式计算、分布式授权。
有一个功能这里也值得一提,【VC3、SGX-Shield】能够做到Enclave代码隐蔽载入Enclave内存(通过远程载入具体代码),或者我想有可能本地Enclave代码加壳也能够做到Enclave代码保密的效果【目前可能尚未实现】(但是一般来说代码加壳可以抗静态分析,能否抗动态分析尚不清楚,而且可能有赖于具体实现)。对此我想利用的点是说,可以将Enclave代码对分布式客户端隐藏,就是悄悄地带入分布式客户端的SGX内,避免不必要的Enclave代码公开。
现在,我们再考虑分布式客户端会有Enclave被开、关、重启的情况,为了保证Enclave内数据在不同时间段依然一致且有效,可以通过密封操作来保证状态连续性。目前密封操作有回滚攻击的危险。对此,密封操作的抗回滚方案有【SGX Monotone Counter、ROTE……】。
单独考虑分布式授权案例,将授权和验证的功能(相当于公司工作人员)派到客户端。为了防止分布式SGX某个节点被攻陷然后对全局产生危害,那就依然可以采用中心化+分布式相结合的方案,也就是说有多少功能下放到分布式SGX的程度进行考量(比如分布式SGX节点只被赋予有限的权限,但也能很大程度满足正常验证需求,使得攻击者攻破分布式SGX节所能获得的权力有限)。
最后,审计的需求、日志的维护可以参考【EnclaveDB、ROTE】的做法。此外,日志管理细节上可以做冗余备份,然后借鉴Counter【SGX Monotone Counter、ROTE……】实现一致性维护。
现在SGX渐渐应用于传统模块的替换,然后提下SGX价值,目前的工作应该说不多。不过也恰恰体现了SGX的潜力,然后未来还有很多SGX的工作可以做。
(其实SGX应用也包括,SGX保护框架,SGX软件层改进,单独拎出来)
Haven(OSDI’14) 微软
SGX已经硬件实现了,但是,很多老的APP并没有用上SGX。并且SGX的代码开发和原来不太一样了,得把代码划分成Enclave内外两个部分。那么意味着老的APP很难用上SGX了,因为不是所有人都愿意花力气把原来的APP移到SGX上。那么怎么把老的APP放到SGX上呢?微软提供了Haven方案。
Haven架构如图:Enclave(APP->LibOS->Shield模块)->uRTS->OS的栈结构(LibOS在这里的作用相当于自己租的卧室内搭建一个小厨房等设施,尽可能的不与外界打交道,尽可能不用外面的大厨房)。这样子,整个APP都是Enclave内部的,APP和LibOS打交道就行,LibOS或者直接满足APP的需求,或者向外让Host OS完成具体需求。总之APP就不用改代码了。
如上所说,Enclave仍然会有小部分的比如系统调用需要与外界接触(好比小厨房的电、气还是得走总的房子的电、气)。此外,SGX还有一些细节限制:EPC大小有限(比如256M),页错误等异常仍然由外界OS来处理,还有很多硬件指令Enclave内不能调用……。
上述这种有Enclave与外界接触的情况,就有被攻击的风险,只要SGX与外部有啥共享的机制,就可能被攻击,SGX侧信道很多就是基于共享机制(后面会讲)。
LibOS和库直接塞入SGX会导致TCB过大的问题,小结处会讨论Haven和他的小伙伴们,进行一个横向对比。
SCONE(OSDI’16)
SCONE的初衷应该就是想让容器能够由SGX进行安全加固。同时最好就是容器可以直接在Enclave中跑,不需要修改,因此它提出如上图架构。
它发现其实并不需要整个LibOS都移进来也能完成对容器的支撑,因此将LibOS概念移除,移除了包含网络和文件Shield层、多线程(不支持多进程)、MUSL等。
另外它还实现了一套异步系统调用的机制(可能是处于安全考虑?目前尚不清楚)。
可以看到SCONE的架构和Haven就有一些区别了,SCONE的TCB相对Haven更小(Haven的LibOS代码、库的代码量很大),同时效率也得到了提升。不过SCONE架构中,Enclave与外界的接口更多了,因为SCONE里面删除了很多东西,意味着这些东西都得找HostOS提供。
Ryoan(OSDI’16)
作者认为SGX原来的机制主要是为了保护Enclave免受Enclave外部的攻击,但是Enclave本身可能有意或无意的将Enclave内的信息泄露给Enclave外部(偏主动式的)。于是作者在Enclave内放置一个沙箱来执行代码(比如与外界的输入输出(包括内存拷贝等)进行加密或管控、系统调用的管控、检查点),在SGX基础上增强安全性,并且还能防御部分软件侧信道。
Panoply(NDSS’17)
为了让传统程序能够不改代码的移植到Enclave中,Haven、Graphene-SGX中将LibOS移入Enclave,并仿真地提供系统调用、线程、事件处理、Forking等功能(最终会转换到Host OS的系统调用),但是也会导致TCB太大(主要是库比较大),效率低等。SCONE、Ryoan使用容器、沙箱来向上支撑传统程序,但是如Fork/Exec等功能无法仿真(因为本身并不是像Haven那样整个LibOS都搬进SGX),这种选择一般来说TCB很小(主要是库不在Enclave内),效率个人猜测会高于Haven这种。
Panoply另辟蹊径,或者说上述两种综合一下,将Libssl等库(Haven中将其放在Enclave中)专门用一个Enclave来执行,目的是为了实现复用(不需要每个Enclave保留一份,降低TCB),然后想要调库,就向库Enclave发出申请,库Enclave返回结果。可以放心的是Enclave间的调用(通信)走的是加密信道,同时彼此实现相互认证。
另一个点和SCONE还是有点像,就是Enclave留一个Shim来执行系统调用来实现各种丰富的功能,具体实现放到不可信的Host OS中。
Panoply这种库Enclave的想法一定程度实现代码复用,降低TCB,不过应该会导致面向HostOS的接口变多,Haven中Enclave与HostOS的接口只有20+。
总之,Haven、Panoply都能帮助传统程序不改代码移植,间接提供系统调用、线程等功能,区别在于Haven通过LibOS实现了很多OS功能,Panoply留了个接口给Enclave,让有些功能由HostOS来做。Panoply库Enclave的概念挺新颖,用来实现代码复用。
Panoply的库Enclave思想其实和RPC有点接近。
Graphene-SGX(ATC’17)
个人觉得这个和Haven类似,或者说Haven架构的Linux下实现,Haven是Win下的实现。Haven应该是20个固定系统调用,Graphene-SGX是28个固定系统调用(18个系统调用会有检查)。除了向上支持Linux传统软件,后来还能够支持容器(这一点可能挺有意思),未来将支持EDMM(Enclave Dynamic Memory Management)。
EDMM这是个SGX v2新增的机制,背后由新增的硬件指令实现,目的是说SGX v1时候,我一开始声明Enclave多大,那加载起来的Enclave就那么大,大小不能再改了,SGX v2增加EDMM,让Enclave可以建立以后,也就是运行的时候动态申请新的EPC页,满足Enclave大小的变化。
Eleos(EuroSys’17)
文章首先讲了SGX带来的开销。第一点,SGX带来的直接开销:进出Enclave要3300/3800周期,而系统调用也就250周期;LLC Miss开销是非Miss下的5.6~9.5倍;EPC页换入换出硬盘Swap区需要40,000周期。第二点,SGX带来的间接开销:由于安全期间进出Enclave会刷新TLB(LLC我忘了是否刷新,L1在Intel的微码补丁之前是不刷新,Foreshadow的出现导致Intel也做L1的刷新了。),LLC污染会造成2倍延迟、TLB污染可能造成6倍延迟。
上述实验结果主要说明了进出Enclave开销大。无论是正常的Enclave退出还是页错误之类的问题导致Enclave退出(AEX)都会带来很大的延迟,因此通过非Enclave退出的方式——RPC,来替换Enclave退出的功能;而关于页错误则通过一个安全的用户空间页表机制SUVM(见下图,大概是说软件实现了虚实地址翻译工作,Enclave页表也放在Enclave内部,原来都是统一用的内核页表,如果发现有页被换出到普通内存,那么就Enclave内部仿真一个错误处理机制,将换出到普通内存的EPC页再放回EPC中,并完成完整性度量。也就是说Enclave内部做了一个软件的用户态页表机制,将硬件页表机制架空。)来避免Enclave退出。相比与改进之前的SGX,Eleos RPC增加23%带宽,Eleos RPC+SUVM增加50%带宽,可喜可贺。
这里让我联想到了SGX的Switchless模式,Switchless模式大概是说我先专门弄一个线程出来让他们直接跑在Enclave环境,然后把他们称为ECALL工人线程,工人线程自然是用来干活的。现在我们运行APP,然后APP调用一个ECALL函数,那么ECALL任务放到任务池,并通知(通过发送Signal)之前一直空转的ECALL工人起床干活了,然后ECALL工人将ECALL任务跑起来。
CoSMIX(ATC’19)
以前,SQLite的fast_read_db之类的函数依赖内存映射文件(mmap),这会通过调用OS错误句柄将内容从硬盘带到内存,但是OS不可信,因此OS的错误处理也不可信。如果使用请求页面指令,这个指令的功能和流程定死了,不灵活。如果使用用户自定义处理句柄,由于会通过OS来调用Enclave内部用户自定义句柄,流程很长,效率低(而且个人认为给了OS攻击的可能性)。
CoSMIX在Enclave内部仿真了页表机制来完成虚实地址转换,目标虚拟地址转变成不可信的物理地址,然后将内容取回EPC,该页的数据同时会保留到缓存(Foreshadow中说,可以利用这个缓存造成攻击)中,可以加快访问“内存”(怎么听着很像SUVM)。
总的感觉是将页表机制移入Enclave,通过LibOS来实现,并完成加密内存的解密等操作。会想起Sectum将页表移入Enclave的做法。
这也体现了有些SGX漏洞就是由于Enclave部分功能需要通过OS来完成(比如页表机制)产生泄露。通过LibOS实现部分机制可以缓解此类漏洞。
Rust-SGX SDK(CCS’19)百度
Rust语言号称是一个能够实现内存安全(不会出现指针越界之类由于指针这个东西导致的问题)的语言,SGX又是个能抵抗特权攻击CPU特性,两者优势互补,就是Rust-SGX了。不过当然不只是这样,除了能够用上Rust语言的内存安全性和SGX提供的安全内存,Rust-SGX还让开发者多了一个使用Rust语言的机会。
看上图,Rust-SGX下,Enclave可以使用Rust语言书写,然后会调用Rust库来使用SGX,Rust库通过Rust-to-C FFI调用C语言的SGX SDK。
Rust-SGX有一个近亲,Fortanix的Rust EDP SDK方案,它将SGX SDK也用Rust重写,这可以将Rust的内存安全特性实现地更充分。但是百度的Rust-SGX SDK能够避免SGX SDK的上游更新导致后续又要用Rust重写,同时C语言的SGX SDK效率比Rust更高(安全性降低)。
百度的Rust-SGX能够保证除SGX SDK以外的其他部件都是安全的,不会引入新的漏洞,且经过形式化验证。
Fortanix Rust EDP SDK
SGX攻防是SGX论文中非常多的一大块,不过目前的我没有太多时间来写这块。先留坑。
Intel SGX攻防工作是为了让Intel SGX更加完善。目前很多的SGX攻防工作的思想是从CPU攻防、其他TEE攻防和软件攻防借鉴的。如从Intel SGX架构、微架构、软件栈攻击。
Intel SGX软件层攻防。对SGX SDK等软件层发动攻击,对软件层攻击进行防御。代表工作有Iago attacks(ASPLOS’13)【恶意构造系统调用返回值对Enclave攻击】、A Tale of Two Worlds(CCS’19)【首先对SGX SDK中ABI、API攻击进行系统调研,然后实现了新型ABI、API攻击】、COIN Attacks(ASPLOS’20)【首先分析了软件层SGX常见攻击模型,然后根据攻击模型实现了漏洞自动挖掘框架】……
微架构数据采样(Micro-architectural Data Sampling)指利用推测执行导致微架构信息泄露给攻击者。SGX下代表的MDS工作有Foreshadow(SEC’18)【SGX版Meltdown,触发异常提供瞬态执行窗口,使信息泄漏到缓存被攻击者窃取。与Meltdown不同,Foreshadow需额外构造异常绕过SGX中止页面语义并提供瞬态执行窗口】、RIDL(S&P’19)【攻击者窃取泄漏到微架构LFB的信息,SGX下也有该问题。相较L1攻击,LFB攻击只要更少的地址位匹配】、Strong and efficient...(SEC’17)【Intel TSX事务入口加载冗余缓存,增加缓存侧信道噪声】……
超线程攻防。超线程下利用兄弟核的微架构信息泄露进行攻击,及相关防御。Racing in Hyperspace(SP’18)【受害者通过度量它的两个线程间通讯时长确定两个线程是否在兄弟核上,避免攻击者线程和受害者线程处于兄弟核上】、Varys(ATC’18)……
内存安全攻防。SGX下,以内存安全问题为主的攻防。代表工作有SGX-Shield(NDSS’17)【Enclave内部署加载器将代码加密带入Enclave,并在Enclave内实现ASLR】、SGXBOUNDS(EuroSys’17)【利用EPC的地址Bits中空余Bits,对缓冲区Load/Store边界进行检查】、Dark-ROP(SEC’17)【利用侧信道等手段定位Gadgets,通过Gadgets链实现ROP攻击。二进制代码复用攻击】、The Guard’s Dilemma(SEC’18)【源码代码复用攻击,利用程序原有的内存漏洞,实现控制流、栈、寄存器的劫持】……
未初始化的Padding Bits:利用传参数据结构中的Padding Bits实现数据偷偷传输。Leaking Uninitialized...(arXiv’17)【利用E/OCALL参数的Padding Bits将数据传入/出Enclave】……
执行流痕迹——页表痕迹。通过页地址泄露信息反推执行流。Controlled-channel attacks(S&P’15)【页错误泄露页地址,利用页地址链反推控制流】、SGX-PTE(SEC’17)【缓存侧信道反推被加载进缓存的PTE,进一步反推页地址链及控制流】、T-SGX(NDSS’17)【利用Intel TSX的特性,使攻击者只能获取Abort Handler的页地址信息,避免真正的控制流泄露,Abort Handler还能记录AEX频率】……
执行流痕迹——影子分支。利用分支预测器的共享进行侧信道信息泄露。代表工作有Branch Shadowing(SEC’17)【退出Enclave时不刷新分支预测器,SGX内外共享分支预测器,攻击者通过(地址碰撞的)影子分支反推受害者分支选择,反推SGX内控制流】、BranchScope(ASPLOS’18)……
执行流痕迹——指令时延。Nemesis(CCS’18)【利用APIC时间中断,单步中断Enclave代码并计算代码执行时长,通过时延序列反推控制流】……
执行流痕迹——其他防护。ZeroTrace(NDSS'18)【本文针对ORAM低效率问题使用SGX进行性能提升】、OBFUSCURO(NDSS’19)【将代码、数据访问模式固定避免控制流痕迹泄露】……
云计算是一种基于互联网的计算方式,通过这种方式,共享的软硬件资源和信息可以按需求提供给计算机各种终端和其他设备,使用服务商提供的电脑基建作计算和资源。【维基百科】
云计算非常契合各个实体对计算资源的定制需求,同时是一种典型的远程计算场景。Intel SGX是一种良好的远程计算安全方案,非常有应用前景。不过SGX开发细节有别于传统开发,因此工程实现存在阻力。目前已有部分SGX应用诞生,体现了SGX的价值,未来SGX应用将更加丰富。
Intel SGX目前很多安全细节仍处于讨论之中,随着SGX应用丰富,SGX的安全性将会受到更多的讨论。
此外,其他芯片厂商未来可能也将学习Intel SGX来解决远程计算安全问题,以满足远程计算安全需求。
1. Intel SGX
Intel SGX狭义上是指一组CPU指令,该组指令增强应用程序代码和数据的安全性,为它们提供更强的保护以防泄漏或修改。开发人员可将敏感信息放入Enclave中,Enclave是内存中具有更强安全保护性的执行区域。
Intel SGX广义上是指以SGX指令为基础所构建的包括Intel CPU等硬件、CPU提供的硬件指令、驱动、Platform Software(用于构建不可信运行时环境uRTS)、SDK(用于构建可信运行时环境tRTS)等在内的一种新的安全机制,既Intel SGX软硬件栈。
SGX平台需要Intel 6代及以上处理器,并且BIOS支持并开启了SGX选项。
2. 常用名词
Intel SGX:Intel Software Guard Extensions的简称。
Enclave:下述条目针对Enclave不同的角度来表述,实际表述中不太加以区分,并且更侧重于指Enclave实例。
Enclave内存:Enclave是内存中具有更强安全保护性的执行区域。
Encalve环境:通过Enclave内存及硬件保护机制、可信运行时共同来保护敏感代码数据的环境,或者说安全世界。
Enclave代码:希望放在Enclave中执行的敏感代码数据。
Enclave文件:保存着Enclave代码数据的镜像文件。与实例的区别好比程序代码与进程的区别,一个静态,一个动态。
Enclave实例:指从Enclave文件具体执行起来的进程。
EPC:Enclave Page Cache。Enclave的物理内存是一种抽象的表示,Enclave物理内存会最终落实到一个个具体的物理页,这些页就是来自于EPC。也就是说EPC是一块加密的处于系统保留内存的物理内存区域,用来存放Enclave的页和SGX数据结构。
EP:Enclave Page。EPC中一个个具体的页。为了方便读者理解,也可称为EPC页
SGX世界观:SGX将软硬件资源等划分成安全世界和不安全世界
安全世界:包括可信运行时和用户的Enclave实例,安全世界中Enclave实例会利用可信运行时提供的API完成敏感功能等。而每个开发者进程都有自己的独立的Enclave环境,不同Enclave的安全世界相互隔离。
不安全世界:包括不可信运行时和用户的非敏感代码以及具有内核权限的驱动。
uRTS:Untrusted Runtime Service,不可信运行时环境,不安全世界、普通世界的一部分。
tRTS:Trusted Runtime Service,可信运行时环境,安全世界、Enclave环境的一部分。
AE:Architectural Enclave。由SGX平台提供完成特定功能的特殊的Enclave,包括:Launch Enclave,用于决定在当前SGX平台上运行哪些其他Enclave(主要指用户的Enclave实例);Provisioning Enclave,提供长期平台证明密钥;Quoting Enclave,使用非对称平台证明密钥,用于为远程使用者签署本地证明报告;Platform Service Enclave,平台服务Enclave,用于提供如可信的时间等安全功能。
OCALL:从安全世界进入不安全世界所用到的桥函数。
ECALL:从不安全世界进入安全世界所用到的桥函数。
ISV:Individual Software Vendor个体软件厂商
SgxEdger8r:SGX Edge Routine,主要用于在编译过程中对.edl文件中的ecall和ocall重新封装编写,即将用户编写的e/ocall改写成实际执行的e/ocall
3. 常用结构体
SECS:SGX Enclave Control Structure。每个Enclave实例都具有一个该结构体,用于保存关于该实例的信息,如Enclave的线性基址(对于整个程序而言)和大小。保存在EPC中该Enclave的内存空间,只能由CPU访问。
TCS:Thread Control Structure。每个Enclave实例可以拥有很多个具体执行Enclave函数的Worker Thread,每个线程都对应一个TCS,用于描述这个线程的信息,如线程执行flag、SSA的位置、当前使用的SSA(若干个SSA组成一个栈)。存储在EPC中,只能由处理器访问。
SIGSTRUCT:ENCLAVE SIGNATURE STRUCTURE。每个Enclave文件具有一个SIGSTRUCT来证明它是被某个SGX平台签署的。(见后续“EINIT指令过程”章节)
EINITTOKEN:EINIT TOKEN STRUCTURE。从Enclave文件创建Enclave实例时,需要向AE申请一个令牌,后续EINIT指令使用EINITTOKEN结构来检查是否允许执行Enclave。(见后续“EINIT指令过程”章节)
EPCM:ENCLAVE PAGE CACHE MAP。被硬件用来跟踪EPC内容,每一个Entry对应一个EP。软件不可访问。每个Entry会说明EPC页的线性地址等。
TrustZone将系统划分为安全世界和普通世界,实现了执行环境以及存储、网络和屏幕等设备的安全隔离,敏感代码放入安全世界执行。TrustZone里面程序是直面硬件资源的,并且TrustZone内部的多个程序间并没有安全隔离,直到有相关工作在TrustZone里面安置了一个安全内核,如T6安全微内核(上海瓶钵主导的工作,在Trustzone里实现了安全操作系统的功能,实现了敏感应用之间的隔离,还可以让开发者更好地使用物理硬件,安全微内核只有六千行代码,非常轻量级,同时经过安全审计)。【SecTEE】等工作也试图在TrustZone内部提供Enclave的概念(包括了SGX所提供的可信度量、加密、访问控制、密封、本地认证、远程认证中的部分功能),之前也听到有相关工作在ARM芯片的普通世界构建Enclave,而不是在TrustZone内部,似乎硬件实现机制有一些区别,忘记了。
SGX中,对于每一个进程,可以创建多个类似于“安全世界”的Enclave,并且不同进程之间的Enclave是互相硬件隔离的——通过MEE使用独立的密钥加密Enclave内存进行保障。
这一块很多资料来源于:
王鹃, 樊成阳, 程越强, 等. SGX 技术的分析和研究[J]. Journal of Software, 2018, 9: 2778-2798.
1. SGX结构简介
每个进程可以创建若干个Enclave实例(不过比较常见的情况是一个实例),Enclave执行程序的敏感代码,保护敏感数据。Enclave之间、Enclave与普通世界之间都存在访问控制(后续“SGX访问控制”章节会讲述)。基本结构如图4所示(详细的软件栈构造会在后续“SGX软件栈”章节中描述)。
图1:SGX基本结构
2. Processor Reserved Memory布局
如图2所示,BIOS通过配置一组范围寄存器分配Processor Reserved Memory(PRM)。其中包括EPC和其他保留给硬件使用的内存。EPC中会分配Page给SGX数据结构供Enclave使用。
图2:Processor Reserved Memory布局
3. Enclave内存结构
如图3所示,每个Enclave内存由EPC中分出的若干Page构成,用于存储Enclave代码、Enclave数据——比如涉及金融等敏感操作的代码数据、TCS。
线程控制信息TCS。Enclave代码的执行是由某个具体线程(进程只有一个线程时就是指进程对应的主线程,或者说进程)来执行,那么这个线程在Enclave中需要保存一份描述其针对于Enclave管理用的相关控制信息,既Thread Control Structure(TCS),换句话说,TCS保存着进出Enclave时候所恢复或保存的Enclave线程信息。举个例子就是,线程1从普通世界进入安全世界,需要佩戴安全世界的工作证,当离开安全世界,需要放下安全世界工作证,拿上linux环境的工作证。
图3:Enclave结构
4. Enclave Page Cache Map结构
如图4所示。Enclave Page Cache Map(EPCM)是一个硬件结构,保存着分配给Enclave的Page的控制信息,一个Page对应一个 EPCM 表项,控制信息包括页面是否已被使用、该页的拥有者、页面类型、地址映射和权限属性等。EPCM 结构由 PMH(Page Miss Handler)硬件模块访问,这个模块通过查询页表、范围寄存器、EPCM 进行内存访问。
图4:Enclave Page Cache Map结构
5. SGX访问控制
Enclave基本访问控制如图5所示。
图5:Enclave基本访问控制
SGX软件栈如图所示。下面将先对硬件、驱动、Platform Software提供的不可信运行时、SDK提供的可信运行时、开发者的应用程序、开发者的Enclave程序这六个模块进行介绍,之后将对硬件指令、驱动接口、API接口、桥函数这四个接口进行介绍。
下面这张为旧图
最下层是SGX硬件,主要指支持SGX特性的CPU(需要Intel 6代CPU及以上),此外还包括PRM、EPCM、PMH等(具体见上文“SGX硬件原理”章节)。CPU向上提供硬件指令ENCLS(内核权限级Enclave硬件指令)及ENCLU(用户权限级Enclave硬件指令),其中内核权限指令提供对Enclave的生命周期管理等功能,用户权限指令提供环境切换等功能。
驱动处于内核权限,向上会接收不可信运行时要求调用ENCLS的命令,然后向下调用ENCLS硬件指令,并将结果反馈给不可信运行时。因此驱动一种功能是不可信运行时想要调用ENLCS指令的代理(主要是Enclave生命周期管理以及EP的部分管理),并完成与该指令相关工作,其中一个非常重要的工作就是sgx_encl结构体的管理(其中包括保管每个Enclave所被分配到的EP集合)。另一方面,由于SGX不信任驱动,要求驱动通过调用内核权限指令完成如TLB刷新、EP页交换等安全性和高效性的保障,只有如此,程序才能继续正常运行。
不可信运行时处于用户态权限。一方面,不可信运行时向下调用驱动接口来管理Enclave生命周期,向上将该功能以API形式提供给开发者。另一方面,还能调用用于进入Enclave的用户态权限硬件指令,提供不可信环境下SGX设备能力查询、不可信密钥交换API等功能(见下文“SGX API”章节)。
可信运行时同样处于用户态权限。可信运行时向下能够调用用户态权限硬件指令用于离开可信世界、创建加密报告等。可信运行时向上能够给开发者提供Enclave开发的API。由于安全原因以及环境隔离,Enclave代码不能调用外部任何库,只能静态链接安全库,同时SGX设计者希望能够让Enclave代码开发能够满足常规的开发需求,提供良好的开发环境,因此可信运行时包含了很多经过安全审计的标准库和开发库,比如C\C++标准库、加密库等(具体见下文“SGX API”章节)。
应用程序处于用户态权限,并属于不可信世界,能够利用不可信运行时API完成Enclave生命周期管理,还能调用普通世界的任意库函数,也就是说应用程序开发与传统的程序开发没有区别。
需要执行的敏感程序,利用可信运行时提供的API来完成开发,同时由于EPC大小有限,开发者应该保证Enclave程序规模不能太大。
硬件指令分为内核权限硬件指令和用户权限硬件指令。内核权限硬件指令指的是指令需要通过内核态下才能访问,缩写是ENCLS。用户权限硬件指令指的是指令用户态下便能访问,缩写是ENCLU。每一个具体的功能指令被称为叶功能,如EADD叶功能,因为叶功能之间的区分是硬件指令(如ENCLS指令:0x 0F 01 CF)的EAX值不同,因此ENCLS指令的EAX在输入时都是用作叶功能号。
如图2所示,SGX 1代指令中,ENCLS主要用于管理Enclave生命周期等。比如下文将介绍的Enclave初始化,ECREATE指令创建Enclave,主要是创建SECS,然后EADD添加EP(Enclave Page)并把Enclave文件内容拷贝到EP中,EEXTEND度量EP,最后EINIT确定这个Enclave建立是否合法可信。
如图3所示,SGX 2代指令在1代基础上添加了动态增加EP、修改EP权限类型的功能,在1代中,在Enclave初始化以后,不能动态增加EP或者修改EP权限属性。
图2:SGX 1代内核权限硬件指令
图3:SGX 2代新增内核权限硬件指令
这个叶功能将源页面从非Enclave内存复制到EPC中,将EPC页面与EPC中驻留的SECS页面相关联,并将线性地址和安全属性存储在EPCM中。Enclave偏移量和安全属性作为关联内容的一部分被度量并扩展到SECS.MRENCLAVE。此指令只能在当前特权级别为0时执行。
RBX包含PAGEINFO结构的有效地址,而RCX包含EPC页面的有效地址。
这个叶功能导致EPC页面被标记为阻塞。此指令只能在当前特权级别为0时执行。
RCX的内容是EPC页面的有效地址。DS段用于创建线性地址。不支持段重写。在RAX中返回一个错误代码。
ENCLS[ECREATE]是Enclave构建过程中执行的第一条指令。ECREATE将EPC外部的SECS结构复制到EPC内部的SECS页面。SECS的内部结构是软件无法访问的。
ECREATE将在受保护的SECS中设置字段,并在EPC中将页面标记为有效。ECREATE初始化或检查未使用的字段。
软件在源结构中设置以下字段:SECS:BASEADDR, SECS:SIZE(以字节为单位)和属性。SECS:BASEADDR必须按照SECS.SIZE范围自然对齐。SECS.SIZE最小是2页(8192字节)。
源操作数RBX包含一个PAGEINFO结构的有效地址。PAGEINFO包含源SECS的有效地址和SECEINFO的有效地址。PAGEINFO中的SECS字段未被使用。RCX寄存器是目标SECS的有效地址。它是EPC中的一个空槽的地址。SECS结构必须是页面对齐的。SECINFO标记必须将页面指定为SECS页面。
这个叶功能将一个四字/双字从属于调试Enclave的EPC页面复制到RBX寄存器中。在64位模式下读取8个字节,在非64位模式下读取4个字节。无法重写读取的数据的大小。
EPC内部源位置的有效地址在寄存器RCX中提供。
这个叶功能将EBX/RBX中的内容复制到属于调试Enclave的EPC页面。8个字节以64位模式写入,4个字节以非64位模式写入。无法重写数据的大小。EPC内部源位置的有效地址在寄存器RCX中提供
这个叶功能通过测量一个扩展字符串来更新一个SECS的MRENCLAVE测量寄存器。此指令只能在当前特权级别为0且未初始化enclave时执行。
RCX包含要测量的EPC页面的256字节区域的有效地址。DS段用于创建线性地址。不支持段重写。
这个叶功能是在Enclave构建过程中执行的最后一条指令。EINIT之后,MRENCLAVE度量完成,Enclave准备使用EENTER指令开始执行用户代码。
EINIT接收SIGSTRUCT和EINITTOKEN的有效地址。SIGSTRUCT描述了包含MRENCLAVE、ATTRIBUTES、ISVSVN、一个3072位RSA密钥和使用所包含密钥的签名的Enclave。SIGSTRUCT必须填充两个值,q1和q2:
q1 = floor(Signature2 / Modulus);
q2 = floor((Signature3 - q1 * Signature * Modulus) / Modulus);
EINITTOKEN包含MRENCLAVE、MRSIGNER和属性。这些值必须与SECS中的对应值匹配。如果使用调试启动键创建EINITTOKEN,则Enclave也必须处于调试模式。
具体过程可以参考下文“EINIT指令过程”章节。
这个叶功能将页面从常规主存复制到EPC。作为复制过程的一部分,对页面进行密码学验证和解密。此指令只能在当前特权级别为0时执行。
ELDB叶功能在复制后在EPC中的目标页面的EPCM条目中设置BLOCK位。复制后,ELDU叶功能清除EPC中的目标页的EPCM条目中的BLOCK位。
RBX包含一个PAGEINFO结构的有效地址;RCX包含目的地EPC页面的有效地址;RDX包含保存页面版本的版本数组槽的有效地址。
这个叶功能在EPC页面中创建一个空版本数组,其逻辑地址由DS:RCX提供,并为该页面设置EPCM属性。在执行这条指令时,寄存器RBX必须设置为PT_VA。
这个叶功能使EPC页面与其SECE解除关联,并被标记为未使用。此指令叶仅在当前特权级别为0时才能执行。
RCX的内容是EPC页面的有效地址。DS段用于创建线性地址。不支持段重写。
如果操作数没有正确对齐、或没有引用该EPC页面、或页面被另一个线程使用、或其他线程在页面所属的Enclave中运行,则该指令将失败。此外,如果操作数指向所关联的SECS,则指令失败。
这个叶功能提供了一种机制,让硬件跟踪软件是否成功地完成了所需的TLB地址清除。该指令只能在当前特权级别为0时执行。
RCX的内容是EPC页面的有效地址。
这个叶功能将一个页面从EPC复制到常规主存。作为复制过程的一部分,页面受到加密保护。此指令只能在当前特权级别为0时执行。
这个叶功能为已存在的Enclave新分配EPC页,将使EPC页面清零,将EPC页面与EPC中驻留的SECS页面相关联,并将线性地址和安全属性存储在EPCM中。作为关联内容的一部分,将安全属性配置为阻止访问EPC页面,直到EACCEPT叶或EACCEPTCOPY叶的相应调用确认将新页面添加到Enclave为止。此指令只能在当前特权级别为0时执行。
RBX包含PAGEINFO结构的有效地址,而RCX包含EPC页面的有效地址。
此叶功能限定已初始化的Enclave中的EPC页面的访问权限。SECINFO参数的RWX位被视为一个权限掩码;没指定页面权限的值将无效。此指令只能在当前特权级别为0时执行。
RBX包含SECINFO结构的有效地址,而RCX包含EPC页面的有效地址。
这个叶功能修改EPC页面的类型。将安全属性配置为:在调用EACCEPT确认修改之前,阻止作为新类型访问EPC页面。此指令只能在当前特权级别为0时执行。
RBX包含SECINFO结构的有效地址,而RCX包含EPC页面的有效地址。
如图4所示,SGX 1代指令中,ENCLU主要用于进出Enclave、创建用于Enclave验证的报告等。
如图5所示,SGX 2代指令在1代基础上让用户决定是否接受的ENCLS对EP权限类型的修改、扩展EP权限、EP拷贝到EAUG新创建的EP。
图4:SGX 1代用户权限硬件指令
图5:SGX 2代新增用户权限硬件指令
ENCLU[EENTER]指令将执行转移到Enclave。在指令结束时,逻辑处理器以Enclave模式在EnclaveBase+TCS.OENTRY的RIP上执行。
如果目标地址不在CS段(32位)内,或者不在标准的地址范围(64位),则会得到一个#GP(0)结果。
ENCLU[EEXIT]指令从当前执行的Enclave和分支退出到RBX中指定的位置。
RCX接收当前的AEP(异步退出指针)。如果RBX不在CS(32位模式)或不在标准的地址范围(64位模式),则会产生#GP(0)结果。
ENCLU[EGETKEY]指令从处理器特定的密钥层次结构中返回一个128位的密钥。寄存器RBX包含KEYREQUEST结构的有效地址,指令据此决定被请求的密钥。RCX寄存器包含将返回密钥的有效地址。RBX和RCX中的地址都应该是Enclave中的位置。EGETKEY使用处理器唯一的值根据许多可能的输入创建特定的键来派生键。这个指令叶只能在一个Enclave内执行。
EGETKEY使用处理器唯一的值根据多种可能的输入创建特定密钥来派生密钥。这个指令叶只能在一个Enclave内执行。
这个叶功能创建一个描述Enclave内容的加密报告。这个指令叶只能在Enclave内部执行。其他Enclave可以使用密码报告来确定Enclave是否在相同的平台上运行。
RBX包含Enclave的MRENCLAVE值的有效地址,MRENCLAVE使用REPORT密钥验证输出的REPORT。RCX包含一个64字节的REPORTDATA结构的有效地址,该结构允许指令的调用者将数据与目标Enclave相关联。RDX包含指令输出的REPORT的地址。
ENCLU[ERESUME]指令使用之前存储在SSA中的机器状态,继续执行由于异常或中断而中断的ENCLU指令。
通过验证SECINFO中指定的安全属性与EPCM中页面的安全属性匹配,这个叶函数接受对运行中的Enclave中的页面的更改。这个指令叶只能在Enclave内部执行。
RBX包含SECINFO结构的有效地址,而RCX包含EPC页面的有效地址。
这个叶功能将现有EPC页面的内容复制到未初始化的EPC页面(由EAUG创建)。初始化之后,该指令还可以修改与目标EPC页面关联的访问权限。这个指令叶只能在Enclave内部执行。
RBX包含SECINFO结构的有效地址,而RCX和RDX分别包含EPC页面的有效地址。
这个叶功能扩展了运行中的Enclave现有EPC页面的访问权限。SECINFO参数的RWX位被视为一个权限掩码;若值表示不扩展页面权限,那么指令将不起作用。这个指令叶只能在Enclave内部执行。
RBX包含SECINFO结构的有效地址,而RCX包含EPC页面的有效地址。
这里将以SGX初始化为例,使读者能够对SGX指令有更直观的感受。SGX初始化过程如图6所示。
图6:SGX初始化流程
EINIT指令的执行过程体现了Enclave实例是如何被可信的启动起来,因此这里将对EINIT指令过程展开描述。
如图7讲述了EINIT指令的执行过程,既EINIT如何最终完成Enclave创建,用到了三个结构:SIGSTRUCT、EINITTOKEN和SECS。
驱动接口的主要功能还是向不可信运行时uRTS提供管理Enclave生命周期的功能,会在内核权限硬件指令基础之上完成具体的生命周期管理能力。
这里将介绍运行时环境(uRTS由Platform Software提供、tRTS由SDK提供)向开发者提供了哪些API供使用。这是SGX开发者直接接触的部分。
由于Enclave程序会被放在Enclave Page中,与其他内存存在隔离,因此无法链接动态链接库来实现各种丰富的传统开发能有的功能,只能链接静态链接库,也就是将需要用到的静态链接库函数一并放到Enclave内存中。因此静态链接库的丰富程度决定了Enclave程序开发的便利程度。为了满足Enclave程序尽可能能够像传统开发一样便利,因此提供了一系列包括C/C++标准库、可信密码学库等源码用于静态链接。由于静态链接库一旦出现安全性问题会直接影响Enclave程序,因此所能使用的库函数是需要经过安全审计的,所以需要剔除或者重新实现不安全的库函数,此外为了便于开发提供可信的密码学相关操作的库函数。总而言之,可信库函数的提供需要满足安全性及便利性。
a. 可信运行时系统服务
一些起到帮助性质的库函数。
b. 自定义异常处理函数
当Enclave中发生了硬件异常,将由异常处理链来逐级处理硬件异常。tRTS提供了函数使得开发者的Enclave程序能通过注册处理函数来具体处理部分硬件异常,然后再将异常交给原来的异常处理链处理,或者说将这个异常处理句柄追加到异常处理链中。
c. 为CPUID准备的自定义异常处理函数
Enclave中不支持直接使用CPUID指令,若想在Enclave中操作CPUID指令,得通过libsgx_tstdc.a中的函数sgx_cpuid、sgx_cpuid_ex或内联函数__cpuid、__cpuidex调用ocall进入uRTS具体实现。由于是uRTS下执行,所以最好检查CPUID指令返回值和Ocall返回值。如果Enclave中用到第三方库用到了CPUID指令,需要开发者做分析检查,处理CPUID异常或者开发者直接给出CPUID结果而不去真正调用CPUID。
d. 可信服务库
可信服务库sgx_tservice主要用于安全的数据操作和保护。第一部分函数是对SGX硬件指令包装。
第二部分函数是用于将数据密封到SGX平台的不可信存储中的函数。Enclave被关闭或重启的情况下,Enclave中数据将随Enclave销毁而消失,如果有些数据未来需要被用到,那么就需要加密存储不可信存储中。
第三部分函数用于帮助计算密封数据的大小、加密文本长度和消息验证码(MAC)文本长度。
e. 可信平台服务函数
允许开发者使用平台服务(PSE,Paltform Service Enclave)或者获得平台服务安全属性。.
f. Diffie–Hellman (DH)会话建立函数
帮助开发者使用ECDH密钥交换协议在两个Enclave间建立安全会话。
g. C 标准库
sgx_tstdc提供了可信标准C库,同时这个库只能在Enclave中使用。目前支持C99子集,代码来自OpenBSD项目。不支持部分函数的原因:
具体的函数支持情况:
h. C++ 语言支持
C++语言特性支持情况。ISO/IEC 14882:SGX对定义的C++库大部分语言特性完全支持,包括:
× 不支持全局Destructors,因为Enclave销毁时,EPC会被回收。
× Enclave接口定义中不支持C++对象,如果需要外部往Enclave传参,需要另外保存成C结构体。
C++标准库支持情况:支持了一套遵循C++11标准的可信C++标准库(包括STL)。有多个版本的C++标准库可以被链接:
不支持的函数如下:
只有C语言函数可以作为Enclave与外部的桥接函数。
i. 密码学库
SDK提供了可信密码学库sgx_tcrypto,这同时会被其他可信库如sgx_tservice用到。可信密码学库基于Intel Integrated Performance Primitives (Intel IPP)或Intel Software Guard Extensions SSL cryptographic library (Intel SGX SSL)。sgx_tcrypto库函数包括(除IPP、SGX SSL外的函数,一类适用于单独的直接对单数据集进行密码学运算,另一类是构建管理句柄对多个数据集进行管理和运算):
j. 可信密钥交换函数
k. Intel受保护文件系统库
提供了常规C语言文件操作API的子集,写过程中,文件被加密存储在不可信磁盘中,读取过程中会验证文件的机密性和完整性,功能上总体接近传统的文件库函数。
l. TCMalloc库
m. Switchless调用库
不可信世界包含switchless调用的不可信部分,如sgx_create_enclave_ex使用switchless模式创建enclave;可信世界中libsgx_tswitchless.a库提供switchless调用的可信部分,主要是维护可信世界中switchless调用的特性,能够让不可信世界switchless调用能够进入到可信世界正常运作。(见下文“SGX Switch模式及Switchless模式”章节)
n. 受保护代码加载器库
维护不可信世界的“受保护代码加载”
a. Enclave创建与销毁
b. 证明函数
向应用程序或Enclave程序证明目标Enclave程序的确运行在SGX环境中。
c. 不可信密钥交换函数
用于不可信环境下远端服务器和Enclave程序的秘密交换
d. 不可信平台服务函数
sgx_get_ps_cap:说明平台服务PSE支持哪些功能
e. Intel SGX 使能和启动控制函数
f. Intel SGX 设备能力函数
想象这样一个场景,一个应用程序启动了若干不同Enclave实例,我们想让实例间构建起可信的会话通道,既ECDH密钥交换及会话建立(API函数见上文“Diffie–Hellman (DH)会话建立函数”章节)。
下文“桥函数”章节将会具体讲述应用程序如何进出Enclave。这里将简化此细节,直接表述为应用程序从不可信环境切换环境进入Enclave。
如图8所示,这里描述Enclave1、Enclave2(简称E1、E2)之间的会话建立。创建E1、E2实例,线程从APP切换至E1,然后调用sgx_dh_init_session这个API函数进入可信运行时(tRTS,由SDK提供,tRTS和Enclave同处于安全世界,不需要环境切换),将自己标记为会话请求方。E1会继续要求外部应用程序转告E2它想要和E2建立通讯。
切换至E2后,E2调用sgx_dh_init_session进入tRTS将自己初始化为应答方,然后调用sgx_dh_responder_gen_msg1,这样会调用硬件指令EREPOTE产生E2的报告,此外创建E2的公私钥对,把公钥、报告封装成Msg1用于返回给E1。
E1调用sgx_dh_initiator_proc_msg1处理Msg1产生Msg2:E1创建自己的公私钥对,通过指令创建E1报告,用Msg1的E2公钥和E1私钥创建共享密钥,将E1公钥、报告等封装成Msg2交给E2。
E2最终会返回Msg3:E2调用sgx_dh_responder_proc_msg2处理Msg2,既用E1公钥和E2私钥构建共享密钥,并用Msg2中的共享密钥散列值验证之。
E1调用sgx_dh_initiator_proc_msg3处理Msg3。最后验证对方身份完成会话建立。
(可以见博客——SGX本地认证)
与传统的C++程序开发不同,SGX应用程序会分为两块,一块是执行在Enclave中的代码,一块是执行在普通环境中的代码。此外,需要在.edl文件中的trusted标记中写上在Enclave中执行的函数的声明,在untrusted标记中写上在普通环境中执行的函数的声明。
SgxEdger8r(SGX Edge Routine,主要用于在编译过程中对.edl文件中的ecall和ocall重新封装编写,即将用户编写的e/ocall改写成实际执行的e/ocall)工具会在应用程序编译过程中根据edl文件将可信与不可信函数声明重新封装成给Enclave环境、普通环境下代码所调用的桥函数,实现两种环境之间的切换。如普通环境下代码调用桥函数会进而通过sgx_ecall进入Enclave环境,Enclave环境下代码调用桥函数进而通过sgx_ocall进入普通环境,其中调用sgx_e/ocall的代码由SgxEdger8r根据用户编写在edl文件中trusted/untrusted标记下的函数声明来自动生成,即具体的进出Enclave代码不需要用户来实现,只需要打上标记即可。
环境切换步骤如下:第一步,通过工具生成的桥函数会调用sgx_ecall、sgx-ocall进而调用硬件指令来切换环境;第二步,由于那些打上标记的函数本身有用户定义的执行代码,因此在切换环境后会进入真正的函数定义。举个例子,Main()->不可信环境ECALL_A()->sgx_ecall()->EENTER->可信环境ECALL_A()。
总而言之,这些打上标记的函数声明会最终由SgxEdger8r工具在编译过程中改造成桥函数,用于切换环境,然后执行函数声明对应的函数定义。
此外在普通环境中的代码需要显式地管理Enclave的生命周期,如调用“创建初始化Enclave的函数”之后才能调用Enclave中的函数,最后需要调用“销毁Enclave的函数”。
如果想要将在普通环境和Enclave环境中传递一个“指向缓冲区的指针”等参数,需要在.edl文件的函数形参前面声明如[in]、[out]等参数标记,这是因为普通环境的内存往往是不可信的,通过比如将普通环境下的缓冲区拷贝一份到Enclave环境中,然后Enclave代码在拷贝进Enclave的缓冲区上进行操作等才是放心的,不会中途被恶意篡改等,最后可能再拷贝到普通环境供普通环境下的程序使用(具体见下文“SGX参数”章节)。
通过上文的引入,现在总结一下桥函数:桥函数是指在SGX平台下,唯一能够切换可信环境与不可信环境的方式,调用硬件指令ENCLU中的EENTER、EEXIT来具体实现,是由SgxEdger8r工具来生成。
代码层面的环境切换过程大概是这样,以传统Switch模式ecall为例(这种模式便于理解,另一种Switchless模式Ecall见“SGX Switch模式及Switchless模式”章节):
不可信环境->假装调用由用户定义的ecall函数->对应的桥函数(SGX Edger8r重新封装的)>sgx_ecall()->_sgx_ecall()->CEnclave::ecall()->do_ecall()->enter_enclave()->__morestack(汇编)->ENCLU(调用硬件指令)->切换到tRTS->可信环境->enclave_entry(汇编)->enter_encalve()->do_ecall()->trts_ecall()->真正调用由用户定义的ecall函数。
SGX将参数从不可信环境传入可信环境的方法是将保存在不可信环境的栈上的参数拷贝到寄存器,EENTER叶功能会将不可信环境的RSP、RBP保存到SSA结构中,并完成地址的切换进入可信环境。
这里将描述.edl文件中的SGX桥函数(接口)中参数或函数的修饰符说明,用来具体说明函数传参或函数声明的具体属性。ECALL为例子,OCALL类似。
这里是对函数传参属性的说明,下同。
[user_check]:Enclave程序使用数组时该数组不会被验证、数组对应缓冲区不会拷贝到Enclave内存中,Enclave可以直接修改应用程序中数组对应的缓冲区。(这个例子中参数为数组,指针类似)
[in]:Enclave会在内部分配相同大小的缓冲区,外部缓冲区的内容被拷贝到内部缓冲区,内部缓冲区内容修改不会导致(不影响)外部缓冲区任何变化。
[out]:内部缓冲区的修改在函数返回时拷贝到外部缓冲区。
[in, out]:Enclave内部会分配一个缓冲区,将数组缓冲区拷贝进来,同时在函数返回时,将内部缓冲区内容拷贝到外部缓冲区,双向。也就说缓冲区的改造过程被隐藏了,外部应用程序只能知道函数的输入输出。
[isary]:告诉Edger8r用户自定义结构体array_t的变量是一个数组。
[string]:告诉Edger8r,变量str参数是一个NULL结尾的字符串。可以用于strlen等功能。
const:说明字符串str不可修改,所以不适用[out]属性。
[size]:告诉Edger8r ptr对应的缓冲区的字节数。不能对[string]属性施加[size]属性。
[count]:告诉Edger8r需要拷贝的arr的长度。
[isptr]:告诉Edger8r自定义类型是一个指针。
[readonly]:禁止Enclave内部分配的缓冲区被拷贝到外部去,因此不能与[out]同时使用。
这里是对函数声明属性的描述,下同。
[public]:外部可以直接调用该Ecall
[private]:默认,外部不可以直接调用该Ocall,除非有Ocall调用这个Ecall并且是[allow]属性
[allow]:允许OCALL在外部调用[private] ECALL。
(可以见博客——ECALL Switch模式和ECALL Switchless模式)
由上文可见,SGX是通过Ecall来进入Enclave环境,类似的,通过Ocall离开Enclave环境。关于Ecall效率方面,传统的Switch模式,应用程序对应的线程(该进程只有一个Main线程)会切换进入Enclave环境,然后拿上它在Enclave环境的“工作证”,也就是绑定上TCS这个结构体,进行具体的用户定义的Ecall函数的执行。
但是这种模式,只能使用一个线程来完成具体任务(我们将这种调用用户定义的Ecall函数称为Ecall任务,此外还有Ocall任务),效率很低,同时还有伴随开销,比如进入Enclave环境需要拿起TCS“工作证”。因为目前还不支持unix的线程库,因此在Enclave中不支持创建线程,只能支持互斥量、条件变量等的维护(用于外部应用程序创建多个线程分别进入Enclave的场景),目前不支持线程库的原因是一方面Enclave程序旨在保护敏感代码,而远不需要创建线程等功能,另一方面出于数据依赖性、安全性等考量。
为了提高效率问题,定义了Switchless模式,如图9所示。以Ecall为例,uRTS为外部应用程序提供了Ecall任务池,以及联合tRTS初始化了多个可信Worker线程来具体执行Ecall任务。举例来说,外部应用程序调用了Ecall_A、Ecall_B,Switch做法是只有一个线程,它执行Ecall_A之后后回到不可信环境继而执行Ecall_B,是一种上下文环境切换的概念;Switchless做法是构建好Ecall Table管理器保存可能执行的Ecall函数,同时构建一个任务池用于记录每个Ecall具体执行的先后顺序,uRTS线程会唤醒空闲的可信Worker线程从任务池中取任务,然后查询Call Table,进而完成具体任务,因此省去了上下文环境切换的开销。Ocall方向的类似。
图9:Switchless模式调用架构
这张图改自Intel SGX手册的一张图(一年前看的,实在记不住在哪个位置了)。相对于那张图,我把PMH、ME两个硬件模块画上去了。
下图是Enclave初始化时硬件间关系图,Enclave初始化大致经历了(1)申请Enclave内存,(2)创建SECS数据结构,(3)加载Enclave代码进Enclave内存,(4)度量Enclave代码,(5)完成初始化。
图中最下面的内存中一块特定区域用作Enclave内存(一般称为Enclave Page Cache,EPC)。SECS是存储在EPC中的一个重要数据结构,用于Enclave管理。EPCM是存储于EPC中实施EPC访问控制的数据结构。CPU中的MEE硬件模块负责对EPC加密,防止物理攻击。CPU中的PMH硬件模块负责查询EPCM项并实施EPC访问控制。
以sgx_create_enclave为例初始化Enclave,源码流程如图所示。sgx_create_enclave扩展支持SGX PCL、Switchless Calls 初始化和Key Separation & Sharing (KSS).
SGX初始化过程中部分扩展特性的声明、验证和配置(Switchless特性、PCL特性、KSS特性)。
ex_features_p数组项 | 说明 |
0 | pointer to an Intel® SGX PCL sealed key |
1 | pointer to the sgx_uswitchless_config_t structure |
2 | pointer to the sgx_kss_config_t structure |
3:31 | reserved, must be NULL |
将Enclave文件映射到进程的虚拟地址空间。这个映射的位置就是下图Enclave虚拟内存视图的虚框部分。
将Enclave文件这个ELF文件进行全面的ELF格式解析,验证Enclave文件格式的正确性,以及对Enclave文件中关键信息(关键符号、动态Section、元数据【其中包括重要的Enclave布局信息等】)进行记录,后续在构建Enclave时经常会用到这些信息。比如布局直接填充到ELRANGE,起ELRANGE结构性(堆、栈、TCS等)格局作用,比如动态Section中的REL、PLT用于重定位过程,比如关键符号用于进出Enclave时提供出入口。
对当前软件栈平台进行验证,尤其是版本情况进行匹配验证。
对当前CPU的X扩展特性进行验证、分析和记录,后续构建Enclave过程中,需要依据X特性对细节进行指定,比如根据X特性支持情况,在进出Enclave时候针对X特性,额外保存X特性相关的上下文环境(比如SSE、AVX、MPX等CPU扩展特性的上下文内容,并且值得提醒的是Enclave内外是两套不同的上下文环境)。一切的目的是为了让SGX和CPU扩展特性有更好地兼容,并且不会引入任何安全问题。
环境检查的事情终于做完了,然后会进入__create_enclave函数来完成Enclave的创建。
包括部分扩展特性的声明、验证和配置(Switchless特性、PCL特性、KSS特性)。
SGX元数据的验证,后面会用到。
将SGX驱动绑定的设备作为Enclave或者说ELRANGE的基址,构建SECS(管理并代表一个Enclave的数据结构),并加载到EPC中。
对Enclave文件映射打补丁,将一些全局变量等信息更新到Enclave文件映射,后续会使用Enclave文件映射构建ELRANGE。
将PT_LOAD、PT_TLS等类型的Segment加载到ELRANGE和对应的EPC中。
将元数据中堆、线程上下文等布局信息加载到ELRANGE和对应的EPC中。
布局情况可以参考下图
上面提到SECS的构建会涉及到ECREATE硬件指令,并且任何页加载到EPC的过程都会涉及到EADD、EEXTEND硬件指令。并且ECREATE、EADD、EEXTEND都是Ring0权限的ENCLS硬件指令,需要SGX驱动来完成。
之后EINIT硬件指令判断Enclave加载过程是否可信,是否是一个可信启动过程。
uRTS维护一个CEnclave类用来管理使用Enclave。
如果开启了调试模式,那么就对调试模式的相关功能进行初始化,比如VTune。
uRTS请求裁剪敏感的或者动态的EPC页。
进入tRTS完成Enclave初始化相关的配套工作,比如ELRANGE的符号、地址重定位过程,比如字符串库、加密库的优选过程,比如保留内存、线程栈保护机制的初始化,比如初始化或调整线程栈、TCS等线程相关信息。此外还有就是对之前敏感或动态页的裁剪申请进行批准接受(调用EACCEPT硬件指令,Ring3权限的ENCLU硬件指令)。
这里进出Enclave都是通过上下文切换的方式。
将通过裁剪申请的裁剪页重新放入到可用EPC页中。
mprotect设置ELRANGE中各个Section的访问属性以及各个Segment对应的访问属性
如果元数据版本较新,并且当前环境支持EDMM,那么对PT_GNU_RELRO、PT_LOAD的Segment,用Ring0权限的EMODPR硬件指令来设置这些页的访问权限为RX,Ring0权限的EMODPR硬件指令会对管理EPC属性的EPCM进行调整设置。rsrv内存用EMODPR改为RW。不支持EDMM等情况,就不进行改动。
针对上下文相关的内存,内存访问控制属性用mprotect设置为RW。rsrv内存在不支持EDMM情况下,不要用mprotect改变它的属性。
针对EREMOVE掉的页,需要用mprotect设置为PROT_NONE,不然这个页一旦被访问,会发生总线异常(sigbus exception),因为这个EPC页已经被EREMOVE硬件指令给从当前Enclave中去除,EPCM也没有再维护EREMOVE掉的页的信息。
上面所涉及到的ELRANGE的页本身在ECREATE、EADD、EREMOVE时就设置或更改了基本的EPCM项,这里主要是进行调整,以及在进程虚拟地址空间用mprotect进行访问控制设置。
填充TCS最小池,使得TCS最小池现有的TCS数量达到最低要求。
Switchless模式的初始化。
这种方式时SGX最初支持也是最直接的ECALL方式,切换上下文进入Enclave,但是这种切换上下文(EENTER【ENCLU.0x02】)的开销非常大,几千个Cycle,可以查看《Eleos: ExitLess OS services for SGX enclaves》,后来相关学者及Intel就推出了Switchless方案。
这个总结主要讲ECALL Switch/Ordinary
线程想要执行ECALL,那么就带上ECALL索引值并申请一个TCS(TCS相当于线程进入tRTS的许可证或者工作证),然后将uRTS的上下文保存到SSA中,通过EENTER硬件指令切换上下文进入tRTS,第一次进入tRTS时的上下文来自于一个预置的模板,并且进入到tRTS的enclave_entry地址,之后按照ECALL索引值查ECALL表得到ECALL的虚拟地址并执行之。需要补充的是,刚进入tRTS时,线程需要确保线程栈保护机制开启、线程数据已经初始化过。
如果进入Enclave是因为:进入到tRTS完成SGX初始化的部分工作;OCALL返回重新进入到Enclave内部;进入tRTS动态构建TCS;重新进入tRTS为了处理异常(《进入Enclave的目的归类》)。那么就需要调用各自的处理函数来解决这些个特殊目的。
对于OCALL返回重新进入到Enclave内部,线程会使用之前OCALL时保存到tRTS的SSA进行上下文的恢复。对于AEX,是通过ERESUME硬件指令重新进入Enclave。
《SGXv2.8起Enclave内新增pthread库》从linux-sgx v2.8开始,SGX支持在tRTS创建pthread线程,这个会要求在tRTS内部开辟线程空间,然后OCALL到uRTS创建pthread线程并分配TCS给这个pthread线程。创建pthread线程者会重新回到tRTS中(OCALL返回),新创建的pthread线程会切换上下文进入到tRTS。
SGX初始化末期的时候,根据用户选择,可以对ECALL Switchless进行初始化。此时主要完成的任务是uRTS端的ECALL Switchless初始化。(SGXv2.8调整后,tRTS端初始化Switchless的操作被放到了第一次Swtichless ECALL时执行)
内容主要包括:
(SGXv2.8调整后,tRTS端初始化Switchless的操作被放到了第一次Swtichless ECALL时执行)
当发生第一个Switchless ECALL时,主线程需要切换上下文进入Enclave,并在tRTS端对ECALL Switchless进行初始化,主要是为了让tRTS内部也保管一份uSwtichless管理器,并往tRTS内部传入OCALL表。然后唤醒所有工人线程,其中tWorker切换上下文进入tRTS,并且在tRTS初始化ECALL管理器、信号线和ECALL表,等待着信号置位并处理ECALL任务。
调用ECALL Switchless者,会开始构建ECALL任务并发送信号(将信号线某个空闲的Bit置位),此时ECALL任务的状态从【SL_INIT】变成【SL_SUBMITTED】,然后将ECALL任务放到ECALL管理器开辟的任务池中,并循环等待tWorker线程接收【SL_ACCEPTED】及处理完【SL_DONE】ECALL任务。
tWorker工人线程这边,第一次进入Enclave时,会在tRTS端初始化ECALL管理器、信号线管理器和ECALL表。然后tWorker工人线程就循环等待信号置位。当接收到信号时,它就将ECALL任务取出,并将ECALL任务状态设置为【SL_ACCEPTED】。然后tWorker工人线程根据ECALL任务中的索引值查ECALL表并执行对应ECALL,执行完后将ECALL任务状态设置为【SL_DONE】。
这个OCALL Switch/Ordinary和ECALL Switch/Ordinary非常相像,就是方向反了。
将tRTS的上下文保存到SSA,然后使用EEXIT【ENCLU.0x04】回到uRTS并从之前进入tRTS时保存的SSA中上下文信息来恢复uRTS的上下文。EEXIT【ENCLU.0x04】的返回点是当时EENTER【ENCLU.0x02】的下一条指令。然后用OCALL索引值查OCALL表获得OCALL的虚拟地址并执行之。
和ECALL Switchless和接近
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。