LibOS概念
库操作系统 (Library OS) 的思想是,将应用程序所依赖的操作系统个性(操作系统个性是操作系统的应用程序编程接口(api)和应用程序可见语义的实现,用于构建应用程序的OS服务)作为库在应用程序的地址空间中运行。一个小的、固定的抽象集将库OS连接到主机OS内核,提供了更好的系统安全性和更快速的OS组件独立演化的可能性。
SCONE: Secure Linux Containers with Intel SGX
SCONE是一个屏蔽的执行框架,它使未经修改的应用程序能够利用SGX提供的隔离。使用SCONE,程序会根据修改后的标准C库(SCONE libc)重新编译,这有助于系统调用的执行。应用程序的地址空间仅被限定为enclave内存,而不受信任的内存只能通过系统调用接口访问。特殊的包装器复制enclave内部和外部的系统调用参数,并提供以透明的加密方式保护任何数据的功能,否则这些数据可能会以明文形式离开enclave边界(所谓的shield)。
SCONE是一种Docker的安全容器机制,它使用Intel CPU的SGX可信执行支持来保护容器进程免受外部攻击。
SCONE的特征:
- 支持安全策略和透明认证
- 原生应用程序支持:不过仍然建议将已有的应用进行重新编译再放入SCONE
- 不仅支持静态链接,也支持动态链接:共享库可以在应用程序开始运行后被加载,共享库被SCONE文件系统shield保护
- 支持fork
威胁模型
我们假设有一个强大而活跃的对手,他拥有对系统和物理硬件的超级用户访问权。它们可以控制整个软件栈,包括特权代码,如容器引擎、操作系统内核和其他系统软件。这使对手能够重播、记录、修改和删除任何网络数据包或文件系统访问。
设计权衡
-
为了在容器中安全执行Linux进程,应该在enclave中放置怎么样的系统支持?
-
不同的设计方案会影响:
- 容器的安全属性,包括TCB的大小和对外公开的接口
- SGX固有限制对性能的影响
可选设计方案
外部容器接口
要在安全容器中执行未修改的进程,容器必须支持C标准库(libc)接口,从而必须使用系统调用,这不能在enclave内部执行,因此安全容器必须向主机OS公开外部接口。关键的决策变成了(a)外部接口和(b)在enclave中实现接口所需的TCB的大小。
图1a显示了一个先前的设计方案,它通过在enclave中放置一个完整的Windows library OS来最小化外部接口。这种方法的一个好处是,它只公开一个包含22个调用的小外部接口,因为一个进程的大部分系统支持可以由库操作系统提供。然而,库OS增加了enclave内部的TCB大小。此外,由于库OS引入了额外的抽象(例如,执行I/O时),它可能会增加性能开销。
图1b的设计是外部接口用于执行应用程序发出的所有libc库调用。这对接口的安全性要求很高。这种方法的一个好处是,它在enclave内部产生了最小的TCB—只有一个很小的shim C库需要将libc调用中继到enclave外部的宿主libc库。
图1c的设计是前两者取中值,在libc实现执行的系统调用级别上定义了外部接口
系统调用的开销
有效的系统调用支持是安全容器的关键需求。因此,安全容器设计不能仅仅简单的使用线程转换来支持系统调用。
内存访问开销
出于性能原因,安全容器设计应该减少对enclave内存的访问。理想情况下,它应该尽可能多地使用不可信的非enclave内存,而不损害提供的安全保证。
SCONE设计
- SCONE将一个基于系统调用的外部接口暴露给OS,在将参数传递给应用程序之前,执行完整性检查并将所有基于内存的返回值复制到enclave内部
- SCONE支持M:N线程来避免不必要的enclave转换,当应用程序线程发出系统调用时,SCONE检查是否有另一个应用程序线程可以唤醒并执行,直到系统调用的结果可用为止
- SCONE为容器提供了一个到主机OS的异步系统调用接口,使用共享内存来传递系统调用的参数和返回值,并发出执行系统调用的信号,系统调用由SCONE内核模块中运行的独立线程执行,因此在执行系统调用时,enclave中的线程不需要退出
- SCONE集成了现有的Docker容器环境,并确保安全的容器与标准Linux容器兼容
外部接口防护
文件系统防护
保护文件的完整性和机密性。容器映像创建者定义三组不相交的文件路径前缀:
-
未受保护的文件的前缀
-
加密和经过身份验证的文件的前缀
-
经过身份验证的文件的前缀
当文件被打开时,防护层确定文件名的最长匹配前缀。根据匹配情况,对文件进行身份验证、加密或直接传递给主机操作系统。
SCONE还通过其文件系统防护支持专用的安全临时文件系统。防护层保证了临时文件的完整性和机密性:临时文件系统维护非enclave内存中被修改的文件的状态。
网络防护
使用TLS为容器服务建立安全通道,封装了所有的套接字操作,并将它们重定向到一个网络防护层。在建立新连接时,网络防护层将执行TLS握手并对通过套接字传输的任何数据进行加/解密。
这种方法不需要客户端或服务端更改,私钥和证书是从容器的文件系统中读取的,因此,它们受到文件系统防护层的保护。
控制台防护
容器环境允许授权的进程附加到stdin、stdout和stderr控制台流。为了确保发送到这些流的应用程序数据的机密性,SCONE支持对它们进行透明加密。控制台流是单向的,这意味着它们无法受到网络防护层的保护,因为网络防护层的底层TLS实现需要双向流。控制台防护通过基于刷新模式将流分割成可变大小的块来加密流。通过为每个块分配一个唯一的标识符(由授权的SCONE客户端检查),可以保护流免受重播和重新排序攻击。
异步系统调用
同步系统调用的缺点:由于SGX不允许系统调用从一个enclave内部发出,必须通过对enclave之外的函数的调用来实现。这意味着执行线程必须将基于内存的参数复制到非enclave内存,退出enclave并执行外部函数来发出系统调用。当系统调用返回时,线程必须重新进入enclave,并将基于内存的结果复制回enclave。效率很低
因此,SCONE提供了一个异步系统调用接口。该接口由两个无锁的、多生产者-多消费者队列组成:一个请求队列和一个响应队列。系统调用是通过将请求放入请求队列来发出的。SCONE内核模块中的一个操作系统线程接收并处理这些请求。当系统调用返回时,操作系统线程将结果放入响应队列。
Ryoan: A Distributed Sandbox for Untrusted Computation on Secret Data
Ryoan提供了一个安全的分布式沙箱,利用SGX来保护沙箱实例免受潜在恶意计算平台的攻击,受保护的沙箱实例限制了不可信的数据处理模块,允许用户在数据处理服务中对数据保密,而不需要信任提供服务的第三方平台
Graphene-SGX: A Practical Library OS for Unmodified Applications on SGX
Graphene-SGX为SGX提供一个端口来增强SGX的功能,如对动态加载库的完整性支持和安全多线程的支持
将LibOS进程实现为Enclave-Isolated进程(EIP),每个EIP由一个Enclave内的一个LibOS实例托管,即n个EIP需要n个LibOS实例和n个Enclave。
不足(Occlum中提出):
- 由于Enclave创建的成本很高,进程创建非常昂贵
- EIP之间的进程间通信(IPC)很昂贵,因为EIP完全被Enclave边界隔离,必须通过不可信内存来传输加密的消息来彼此通信
- 在多个LibOS实例之间同步时困难的,因为多个LibOS会存在于多个Enclave中
设计考量
功能性
在一个极端,像Haven这样的LibOS将操作系统的大多数应用程序支持代码拖到enclave中。在另一个极端,只有薄薄一层shim,如SCONE和Panoply封装了一个API层(系统调用表)。在enclave中添加更多代码会增加TCB的大小,但可以减少enclave和不受信任的OS之间的接口和攻击面的大小和复杂性。
在设计时需要考虑:
- 进出enclave十分消耗资源
- EPC的大小有限
防护层的复杂性
SGX硬件可以将应用程序与不受信任的操作系统隔离,但SGX本身无法保护需要从操作系统获得功能的应用程序。Iago攻击是来自不受信任的操作系统对应用程序的语义攻击,通过未经检查的系统调用返回值损害SGX应用程序。
因此,任何SGX框架都必须提供一些防护支持,以验证或拒绝来自不受信任的操作系统的输入。防护层的复杂性与接口的复杂性直接相关:由于一个LibOS或shim可以减少enclave API的大小或复杂性,Iago攻击成功的概率就降低了。
应用程序代码的复杂性
将应用程序运行在Enclave中,可以有以下方法:
- 修改应用程序,以减少运行时所需的时间
- 对不受信任的操作系统开放和屏蔽更多接口
- 将更多的功能引入到shim或LibOS中
设计大纲
威胁模型
不可信的组件包括:
- 英特尔CPU之外的硬件
- 操作系统、hypervisor和其他系统软件
- 在同一主机上执行的其他应用程序,包括不相关的enclave
- 驻留在应用程序进程中但enclave之外的用户空间组件
可信组件包括:
- 英特尔CPU
- Enclave中的代码,包括LibOS、未经修改的应用程序及其支持库
- Intel SGX SDK提供的enclave:aesmd。它用来验证enclave签名中的属性并批准enclave创建。除了aesmd和驱动,不信任Intel SGX SDK
多进程应用
在每个进程中运行一个单独的LibOS实例来支持多进程应用程序。每个LibOS实例通过消息传递来协调状态。例如,通过fork创建第二个enclave,并通过消息传递复制父enclave的内容
屏蔽Linux抽象
动态加载
为了运行未经修改的Linux二进制文件,Graphene-SGX实现了动态加载和运行时链接。在Linux系统中二进制文件大都是动态链接的,但静态链接在SGX框架中很流行,因为它很简单,便于使用硬件enclave度量。动态链接需要动态加载器中的根信任,然后动态加载器必须度量库。对于Haven,enclave度量仅验证Haven本身的完整性,并且同样的度量适用于在相同的Haven二进制文件上运行的任何应用程序。
Graphene-SGX扩展了Haven模型,为任何可执行库和动态链接库的组合生成唯一签名。下图显示了一个enclave的结构和动态加载过程。Graphene-SGX从一个不受信任的平台适配层(pal-sgx)开始,该层调用SGX驱动程序来初始化enclave。enclave的初始状态决定了CPU随后验证的度量结果,它包括一个屏蔽库(libshield.so)、要运行的可执行文件和一个清单文件(指定了enclave中的属性和可加载二进制文件)。然后屏蔽库加载一个Linux LibOS (libLinux.so)和标准C库(ld-linux-x86-64.so和libc.so)。在enclave初始化之后,加载程序继续加载其他库,这些库由屏蔽库检查。如果SHA-256哈希值与清单不匹配,屏蔽层将拒绝打开库。
清单包括所有组件的完整性度量以及签名,这个清单对于每个应用程序都是唯一的,并作为enclave初始化的一部分进行度量。这种策略需要信任Graphene-SGX(in-enclave)引导加载程序和屏蔽模块,从而能够根据清单正确加载二进制文件,并拒绝OS提供的任何错误二进制文件。这并不比放置在Haven的动态加载器中的信任级别差,但不同点在于Graphene能区分不同的应用程序,甚至相同应用程序的使用不同库的实例。
存储权限
默认情况下,Linux链接器格式(ELF)经常将代码和链接数据(例如跳转目标)放在同一个页面中。库在链接期间将可执行页面临时标记为可写,然后将该页面保护为仅执行页面。这种行为在当前的Linux共享库中普遍存在,但是可以在编译时更改,将可写的部分填充到单独的页面上。
SGX1不能在enclave初始化之后更改页面权限。为了支持这种ELF行为,我们目前将所有enclave页面映射为可读、可写和可执行。这可能会导致一些安全风险,例如enclave中的代码注入攻击。在一些情况下,这也会损害功能,例如,一些JVM实现使用页面错误来同步线程。
依赖位置的可执行文件
SGX要求所有的enclave大小都是2的幂,并且起始地址从与enclave大小对齐的虚拟地址开始。大多数Linux可执行文件被编译成依赖于位置的,通常从地址0x400000开始。挑战在于,要创建包含此地址且大于4MB的enclave将必须包含地址0。
我们认为在enclave中包含地址0是一个正面的结果,但并不是严格必要的,因为我们不愿意在空指针后面的代码中进行强声明。Graphene-SGX仍然可以在enclave中将该地址标记为未映射。因此,空指针仍然会导致页面错误。另一方面,如果地址0在enclave之外,则存在不受信任的OS将该地址映射到危险数据的风险,从而破坏enclave的完整性。
Occlum: Secure and Efficient Multitasking Inside a Single Enclave of Intel SGX
Occlum设计了一种新的软件故障隔离技术(SFI Software Fault Isolation)用于沙箱不可信模块的软件检测,通过SFI隔离流程(SIP)实现LibOS,从而能够安全共享Enclave的单个地址空间,并且实现既安全又高效的多任务处理
在SGX中添加LibOS的目的在于:
SGX开发人员需要将SGX保护的应用程序分成enclave和非enclave两部分,这导致了需要大量的工作来重构SGX的遗留代码。最近的工作试图通过在enclave中引入库操作系统(LibOSes)来尽量减少工作量。通过LibOS提供系统调用,遗留代码可以在enclave中运行,而不需要修改。
AccTEE: A WebAssembly-based Two-way Sandbox for Trusted Resource Accounting
远程计算通常在沙箱环境中进行:
- 隔离执行以保护主机环境免受未经授权的访问
- 控制和限制资源使用
数据所有者和计算提供者存在相互的不信任,因为:
- 数据所有者会失去对代码和数据的控制权
- 不能确定代码执行环境的完整性
- 资源使用审计缺少双方信任
AccTEE结合SGX和WebAssembly实现一个双向沙箱,在保证代码和数据的机密性和完整性的同时,进行细粒度地资源核算(通过计算WebAssembly指令,内存分配以及I/O操作)。
- SGX:保护代码和数据不被计算提供者未经授权访问
- WebAssembly:防止数据所有者未经授权访问计算提供者的机器
背景
使用场景
-
志愿计算 缺点:
- 通过计量捐赠的CPU时间来决定贡献,而不考虑内存、IO或CPU性能
- 多次执行每个任务来保证结果的完整性,浪费资源
- 志愿者可以获得数据和代码
通过AccTEE可以保护结果的完整性,避免多次执行浪费资源;也可以跟踪资源使用情况,防止有作弊行为。
-
补偿计算:参与者提供他们私有机器的空闲资源,并以此获得奖励,例如加密货币。但计算资源提供者和基础设施提供者相互不信任,可能存在基础设施提供者恶意修改计算资源提供者的贡献值。
通过AccTEE,计算资源提供者可以保护自己的贡献不被恶意修改。 -
无服务计算:由功能即服务(Function-as-a-Service FaaS)驱动,开发人员不需要管理服务器,只需要编写和提交函数代码,由云提供商来设置函数的执行上下文,衡量并行函数实例的数量,连接函数的输入输出。但会存在代码所有者和计算提供者间的不信任。
-
Pay-by-Computation:网络内容提供者主要依靠在线广告获得运营资金,但是用户想方设法删除广告,浏览器也有了拦截广告的技术,因此需要一种替代的,侵入性较小的机制来补充网络内容提供者。
通过AccTEE,用户通过使用空闲资源在后台运行短期任务来换取网站的访问权,由双向沙箱来保护任务的机密性和完整性。
WebAssembly
WASM是一种新型的、平台无关的二进制指令格式,其目标是一种安全、快速和可移植的低级代码格式。
在技术层面,WebAssembly代表了一个基于软件故障隔离的单向沙箱,WebAssembly模块通过不相邻的内存空间相互隔离:代码的内存空间、执行栈、执行环境数据结构和堆是分开的,从而防止任意代码执行以及WebAssembly模块自身数据之外的数据损坏。
除了内存隔离之外WASM还提供一个受保护的调用堆栈,它只包含固定大小的变量,更复杂的结构存放在线性存储器的栈中,以防止缓冲区溢出。
WASM提供人类可读的格式WAT,等同于二进制格式。
AccTEE构建在WASM的内置软件故障隔离之上,以防止程序干扰核算系统。
威胁模型
假设代码数据所有者和计算提供者都是强大的攻击者,可以进行任意行为,所有参与的执行平台都是不可信的。但是信任Intel和SGX。
AccTEE设计
系统需求
- 系统支持各种高级编程语言
- 平台独立性:核算的结果独立于平台,平台只需要将workload代码转换为可执行指令
- 双向隔离:workload隔离于平台环境,平台提供者不能干涉代码执行
- 可信资源核算:双方都不能干预核算机制
- 代码和数据的完整性和机密性
- 低性能开销
资源核算方法
AccTEE使用中间代码来获得平台独立性,具体来说,使用WebAssembly来支持更多的语言:对于相同的(确定性的)任务和输入参数,在不同的硬件平台,甚至不同的WebAssembly运行时,执行的WebAssembly指令的数量是相同的。
-
execution sandbox防止不可信的数据和代码访问主机或干预资源核算
-
accounting enclave(AE)防止不可信主机窃听数据代码或操控资源核算
- accounting enclave基于WASM提供的基于语言的隔离实现
-
instrumentation enclave(IE)和AE通过Enclave度量来确保代码正确执行
总体工作流程:
- 将应用程序编译为WebAssembly
- 度量WebAssembly代码(在IE中),并输出度量后的WebAssembly代码和一个认证(确保输出是由该IE生成)
- IE的输出作为AE的输入,AE在认证通过后执行代码,并生成资源核算日志
I/O操作
wasm没有为I/O操作指定接口,因此wasm代码被嵌入到运行时系统中,该系统将必要的原语暴露为wasm代码可以调用的函数。
SGX Enclave中不允许系统调用,必须退出Enclave后才能执行不可信的I/O操作。AccTEE依赖SGX-LKL来执行遗留二进制文件,SGX-LKL处理Enclave内部的系统调用,但是直接访问外部资源的系统调用(如I/O)是不受信任的。
Accounting Enclave
AccTEE跟踪三种资源类型,其衡量方式如下:
- CPU使用:执行的WASM指令的数量
- 内存
- I/O使用:各种I/O通道发送和接收的字节数
CPU
通过维护一个计数器(指令计数器)来跟踪CPU的使用情况,每执行一条wasm指令就递增。
AccTEE将一个全局计数器变量添加到原始wasm代码中,初始化为0,同时也在每个代码块的最后添加wasm指令来增加计数器的值。
wasm指令有不同的复杂度,在计数时需要加权。指令访问内存的成本取决于内存访问模式和访问范围:线性访问便宜而随机访问昂贵,但由于访问内存的指令的成本是无法预测的,所以AccTEE采用峰值内存来估计内存访问的成本。
指令计数器的优化:
- flow-based(基于数据流):不用每个代码块都进行计数,当一个代码块有多个父节点时,可以在这个代码块加上所有父节点计数的最小值,在父节点上只要加上差值即可,如下图所示
- loop-based(基于循环):将指令计数器的增量移出循环,不要在每个循环中都增加,而是退出循环之后增加一次。
内存
每个wasm模块都可以访问一块线性内存(连续的一段内存,使用模块定义的大小初始化,但可以动态增长到某个最大值,并且只能增长不能减小),因此AccTEE使用线性内存的大小来计算workload消耗的内存,包含两个策略:
- 在代码执行结束时将所有线性内存相加得到内存使用峰值
- 将指令计数器和线性内存大小相结合,实现细粒度的内存计算
I/O
在AccTEE上下文中,wasm运行时时受信任的部分,因此可以通过检测运行时的I/O函数流入和流出wasm模块的字节数来测定。
AccTEE实现
-
使用SGX-LKL来在Enclave中运行未修改的二进制文件。【创新点:可以进行修改?】
-
关于wasm的执行环境,采用Node.js JavaScript运行时,底层使用Chrome的JavaScript引擎V8来执行JavaScript和WebAssembly。【可替代方案:WAVM、wasmi】
- V8引擎需要“粘合代码”来在JavaScript和wasm执行上下文之间架起桥梁,粘合代码通常是专门为相应的WebAssembly代码定制的,并与之一起生成
- 基于Emscripten提供的主模块和副模块的分离。main模块提供了一个接口,包含了它导入的所有标准库函数,并生成所有必要的JavaScript粘合代码。每个附加模块(也称为side模块)只从main模块中导入所需的标准库函数。加载side模块时不需要额外的粘合代码。在我们的框架中,我们只是静态地包含了一个提供所有标准库函数及其粘合代码的main模块,而每个动态加载的模块都是一个从main模块中导入所需功能的side模块。编译和实例化每个side模块的代码直接集成到框架中
AccTEE评估
SGX HW模式开销比SIM模式和SGX-LKL模式下大得多?(是由于EPC页切换带来的开销?)
表现为当workload超过可用的EPC内存(93MB)时,性能显著下降。
A Practical Intel SGX Setting for Linux Containers in the Cloud
将SGX部署到云环境应该满足:
-
对远程认证的有限支持:SGX的一个非常重要的特性是能够向第三方(如云用户)证明SGX应用程序的身份和完整性,但原生的Haven和SCONE都没有提供对CPU远程认证的支持;
-
SGX的应用安全:将整个应用包含在一个安全的enclave中的那些解决方案 (Haven, Graphene-SGX, SCONE) 都不一定保证安全,因为它们都扩大TCB,并且可能包含现存的应用或库中的漏洞;
-
限制EPC内存:当前最大的EPC大小是128MB,用户可用的大约是93MB。虽然Linux上支持EPC页面交换,但这会导致相当大的性能损失。EPC限制还意味着云提供商需要保护EPC免受(恶意的)过度使用,这是现有解决方案没有考虑到的一个因素。SGX2甚至允许在enclave运行时期间动态地分配EPC页面,从而加剧了EPC内存消耗;
-
对应用程序的支持:为了减小enclave内部的TCB(可信计算基), Intel强制要求对程序进行分区,这使得SGX的编程变得困难。
提出lxcsgx:
- 为容器化应用程序启用SGX远程认证
- 在Linux内核中强制每个容器的EPC内存使用进行控制,以防止(恶意的)资源过度使用
- 实现一个GCC插件来帮助程序分区,以减少enclave中的TCB,并更好地支持可伸缩性
- 使用SGX实现软件TPM,为遗留应用程序提供快速的硬件TPM替换以及套接字api
- 基于lxcsgx改进并评估Nginx/OpenSSL和Memcached
Motivation
Haven、Graphene-SGX、SCONE等提供一种方案来使用户不需要仔细划分SGX程序,但代价是增加了PCB和Enclave大小,忽视远程认证、EPC大小的硬件限制。
非官方SDK的不足
- 不提供远程认证,就不能像远程用户提供保证(应用程序是否确实在Enclave中运行以及Enclave是否具有正确的度量)
- Enclave中的运行时存在安全问题:Enclave内部使用的传统加密库(如OpenSSL)会受到侧信道攻击,Graphene-SGX和SCONE直接将glibc和musl放入Enclave中,存在包含不安全的函数的问题;相比而言,所有危险的函数都从Intel的可信C库中移除,对于敏感的函数则使用硬件指令完成
程序分区
程序分区要求开发人员找出代码中最安全敏感的部分,放入SGX的可信区域,从而减小TCB。由于系统调用不允许在Enclave内部进行,所以任何不需要分区的方案都依赖于额外的中间层(如LibOS)来模拟系统调用,然而这样会增大TCB。
程序分区的另一个好处是在加载时和运行时都可以减少EPC内存的消耗。
EPC内存控制
在一台云服务器上只能使用128MB的EPC内存来支持多用户,可能存在的内存泄露会导致SGX内核驱动程序交换其他用户的Enclave,并且也有可能存在恶意用户对EPC内存发起DoS攻击。
lxcsgx强制对每个容器的EPC内存使用进行控制以防止以上问题。
软件TPM
Enclave不能由不同的进程共享从而减少EPC内存消耗,每个进程都需要分配一个新的虚拟地址区域来加载相同的Enclave,会映射到不同的EPC页面,即EPC页面是不能共享的。
SGX所需的功能(加密、随机数生成、安全存储等)通常在多个应用之间共享,因此可以在通用平台服务上创建一个单一的Enclave,同时为不同的应用程序服务。
lxcsgx使用了tpmsgx将SGX通用加密服务实例化为软件tpm,提供给开发者套接字api。
设计实现
威胁模型
-
我们并不一定信任云提供商,它可能对破坏其客户的托管容器的机密性感兴趣。恶意的云提供商还可能主动尝试破坏托管容器的机密性和完整性;
-
Linux内核和运行在云服务器上的LXC程序都不受信任;
-
我们不认为DoS攻击是由ring 0攻击者发起的(例如,防止用户使用Intel SGX)
-
不考虑来自ring 0攻击者的控制通道攻击或来自ring 3攻击者的侧通道攻击
LXC应用的远程认证
由于LXC/Docker无法挂载非filebackend的套接字,所以容器化应用程序无法直接使用SGX提供的使用QE的远程认证。
解决方案:
- 为Linux内核添加一个新特性以支持容器的抽象UNIX套接字传递
- 为了使LXC能够使用内核提供的抽象UNIX套接字直通特性,我们向LXC添加了一个名为lxcsgx.sgx.sock的新配置
控制EPC内存使用
计算每个容器分配的EPC页面数量,如果请求超过EPC额度的页面,则拒绝分配。然而,找到负责每个EPC分配请求的相应容器并非易事,因为容器对底层Linux内核是透明的,内核只看到进程。
我们使用网络名称空间作为容器的唯一标识符,因为它由在容器内运行的所有应用程序共享。在大多数情况下,容器配置了不同的虚拟网卡(LXC中的veth),因此具有不同的网络名称空间。当一个网络名称空间被多个容器共享时,EPC控制将应用于名称空间中的每个容器。
- SGX内核驱动程序实现:SGX内核驱动程序负责EPC内存管理,包括分配、交换和回收。在每次尝试EPC页面分配(EADD)时,我们使用SGX驱动程序维护的enclave所有者信息找到请求进程的PID。给定PID,我们找到相应的网络名称空间并检索EPC控制记录。如果激活了记录,并且请求的EPC使用在限制内,则允许分配,并增加使用计数。类似地,对于EPC页回收,我们减少相应EPC控制记录的当前使用计数。
- LXC实现:为了利用EPC控制机制,将另外两个新配置(lxyz .sgx. EPC . limitandlxyz .sgx. EPC .control)添加到LXC中
tpmsgx:软件TPM
MPTEE: Bringing Flexible and Efficient Memory Protection to Intel SGX
内存保护扩展(MPX)现在在Linux上已失效。如果使用GCC 9.1及更高版本,它实际上已经无效,因为去年删除了编译器端支持,而现在在Linux 5.6中取消了内核支持。
内存保护扩展是英特尔设计的,用于在运行时检查指针引用,以避免缓冲区溢出以及Skylake和更新的处理器的其他潜在相关漏洞。但是,英特尔一直没有保持对MPX软件的支持,他们表示,未来的英特尔CPU可能会删除MPX功能。 MPX从未真正与基于编译器的消毒器一起真正起飞,它更优雅地解决了相同领域的问题,不需要专门的硬件支持。
Understanding TEE Containers, Easy to Use? Hard to Trust - 安全性分析
提出TECUZZER来对各个SGX容器(Tcon)进行模糊测试,包括Graphene-SGX, SCONE, Occlum, SGX-LKL, Chancel, Deflection 和 Ratel
不完整的OCALL接口保护
基于系统调用的隐蔽通道
使用系统调用参数来开启隐蔽通道,应用程序可以将飞地内数据转移到不受信任的操作系统
- 只有Occlum提供防御
- Tcon应该只允许必要的系统调用(如网络I/O和文件I/O)以及用于安全控制的包装器(如应用加密和限制系统调用参数的范围)
被动系统调用窥探攻击
大多数Tcons不能处理I/O请求,特别是磁盘I/O。因此,他们不得不求助于不受信任的内核来处理请求。然而,这会向操作系统暴露大量信息。以文件操作为例,内核知道哪个文件被打开并被处理,甚至知道发生读或写操作的偏移量。
- Occlum和SGX-LKL各自运行一个内嵌文件系统,不将文件的操作暴露给不受信任的操作系统;Ryoan使用内存中的POSIX api来访问预加载的文件,这对操作系统是不可观察的;Graphene保护一部分文件,其他文件保存在Enclave外,通过I/O访问时会暴露访问模式;其他Tcon不提供防御
- 使用in-enclave文件系统,或采用ORAM
缺乏返回值校验
除了传出参数之外,Tcon还应该控制系统调用的返回值,以减少Iago攻击等漏洞的风险
- Graphene-SGX和SCONE可以很好地实现对返回值的安全检查;SGX-LKL、Ryoan和Occlum对某些系统调用的返回值进行校验;一些Tcons实际上由不受信任的组件来检查Enclave外的系统调用的返回值
- 对Enclave内所有公开的系统调用强制执行返回值检查
软件隔离的缺陷(只针对安全威胁中Enclave内代码不可信的场景UAM)
缺乏直接的分支检查
需要对所有分支指令进行控制,这样程序就不会跳过保护跳转到指令化代码和关键指令之间的位置
错误的内存边界检查
当前的Tcon设计执行内存边界检查,以确保应用程序只能写入自己的数据段
- 在Deflection和Chancel中,没有进行很好地内存边界检查;Occlum AE所以来的MPX已经被Intel废弃了
- Tcon应该强制执行细粒度的内存边界检查,这要求加载器拥有关于应用程序内存布局的详细信息
库缺少工具
注入飞地的未受控恶意库可以完全打破Tcon保护
受限的侧信道保护
基于故障的侧通道攻击
页面错误攻击(更改页表项上的标志,以诱导页面错误,以观察访问模式)和AC错误攻击(更改对齐检查标志,以诱导缓存线内秘密数据访问)
- 没有Tcon可以抵御页面错误攻击;Graphene-SGX可以减缓AC错误攻击
- 将已有的解决方案集成到Tcon中,如T-SGX、地址随机化、ORAM、HyperRace等,目前尚不清楚这种保护会不会影响其性能
认证和秘密配置问题
- Ratel根本没有认证支持;Deflection和Chancel只提供远程认证接口,而没有完全实现;SCONE包含完整的远程认证实现,但不支持秘密配置
- 在实际部署之前,应该包括这些关键功能
对执行环境配置的保护不完全
除了在enclave中运行的应用程序外,还应该评估其参数、环境变量和必要的配置文件,以确保它们的完整性得到保护,并且它们不会破坏enclave中的安全保护
- Occlum提供了最好的保护;Chancel, Deflection 和 Ratel没有提供任何保护
- 所有这些元数据都应该具有完整性和机密性,对于在加载到Enclave之前无法确定其正确内容的环境变量,Tcons应该对其执行安全校验