英特尔 SGX 是一项为满足可信计算行业需求而开发的技术,其方式与 ARM TrustZone 类似,但这次适用于台式机和服务器平台。它允许用户代码创建专用内存区域(称为安全区),这些区域与以相同或更高权限级别运行的其他进程隔离。在安全区内运行的代码有效地与其他应用程序、操作系统、虚拟机管理程序等隔离。
它于 2015 年推出,搭载了基于 Skylake 微架构的第六代英特尔酷睿处理器。可以通过执行设置结构化扩展功能页标志的 CPUID 指令并检查是否设置了 EBX 寄存器的第二位来检查 SGX 支持。为了能够使用SGX,它必须由BIOS启用,并且只有少数BIOS真正支持这项技术。这是它没有被广泛使用的原因之一。
英特尔 SGX 的实施可以概括为几点:
应用程序分为两部分:安全部分和非安全部分;
应用程序启动安全区,该安全区放置在受保护的内存中;
调用安全区函数时,只有安全区内的代码才能看到其数据,外部访问始终被拒绝;当它返回时,安全区数据将保留在受保护的内存中。
安全执行环境是主机进程的一部分,这意味着:
应用程序包含自己的代码、数据和安全区;
安全区包含自己的代码和自己的数据;
SGX保护安全区代码和数据的机密性和完整性;
安全区入口点在编译期间预定义;
支持多线程(但正确实现并非易事);
安全区可以访问其应用程序的内存,但不能以相反的方式访问。
英特尔 SGX 定义了 18 条新指令:13 条供主管使用,5 条供用户使用。所有这些指令都是在微代码中实现的(以便可以修改它们的行为)。有关完整的说明列表,请参阅下文。
英特尔 SGX 还定义了 13 种新数据结构:8 种用于飞地管理,3 种用于内存页面管理,2 种用于资源管理。有关完整的结构列表,请参见下文。
SGX飞地控制结构SGX Enclave Control Structure(SECS)
线程控制结构Thread Control Structure (TCS)
State State Area(SSA)
页面信息Page Information (页面信息)
安全信息Security Information(SECINFO)
分页加密元数据Paging Crypto MetaData (PCMD)
版本数组Version Array (VA)
安全区页面缓存映射Enclave Page Cache Map (EPCM)
安全区特征码结构Enclave Signature Structure (SIGSTRUCT)
EINIT Token Structure (EINITTOKEN)
报告Report(报告)
报告目标信息Report Target Info (目标信息)
密钥请求Key Request(密钥请求)
在以下各节中,我们将详细介绍相关的说明和结构,然后简要说明如何使用它们来实现某些功能。
安全区代码和数据放置在称为安全区页面缓存 (EPC) 的特殊内存区域中。此内存区域使用内存加密引擎 (MEE) 进行加密,这是一种新的专用芯片。内存总线上的外部读取只能观察加密数据。页面仅在物理处理器内核内解密。密钥在启动时生成,并存储在 CPU 中。
扩展了传统的页面检查,以防止外部访问 EPC 页面。
安全区页面缓存映射 (EPCM) 结构用于存储页面状态。它位于受保护的内存内,其大小限制了EPC的大小(由BIOS设置,最大128MB)。它包含每个页面的配置、权限和类型。
PAGEINFO 结构用作 EPC 管理指令的参数,以引用页面。它包含其线性和虚拟地址,以及指向SECINFO和SECS结构的指针。
SECINFO 结构用于存储页面元数据:访问权限(读/写/执行)和类型(SECS、TCS、REG 或 VA)。
PCMD 结构用于跟踪与逐出页面关联的元数据。它包含页面所属的安全区的身份、指向 SECINFO 结构和 MAC 的指针。
VA 结构用于存储从 EPC 中逐出的页面的版本号。它是一种特殊的页面类型,包含 512 个 8 字节的插槽来存储版本号。
此指令分配一个 4KB 内存页,该页将包含页版本号数组 (VA) 以防止重播。每个元素的长度为 64 位。
此指令阻止对准备逐出的页面的所有访问。以后对此页面的所有访问都将导致页面错误(“页面被阻止”)。
此指令从 EPC 中逐出页面。页面必须已正确准备:必须阻止它,并且不得被 TLB 引用。在将其写入外部存储器之前,对页面进行加密,并生成版本号和元数据,并执行最终MAC。
此指令将以前被逐出的页面加载到内存中,无论是否处于阻塞状态。它检查元数据的 MAC、版本号(来自相应的 VA 条目)和页面加密内容。如果验证成功,页面内容将被解密并放置在所选的 EPC 页面中,并删除相应的 VA 条目。
EPC 内存由 BIOS 定义,并且大小有限。SGX有一种方法可以从EPC中删除页面,将其放在不受保护的内存中,并在以后恢复。由于EPC页面管理指令,页面保持相同的安全属性,允许加密页面并生成额外的元数据。在从所有处理器逻辑内核中删除引用此页的所有高速缓存条目之前,无法删除页。内容以页面粒度(4KB)导出或导入。
每个飞地都与一个SECS结构相关联,该结构将包含其元数据(例如其哈希和大小)。任何安全或非安全代码都无法访问它,只能由处理器本身访问。一旦实例化,它也是不可变的。
每个安全区至少与一个 TCS 结构相关联,该结构指示安全区的执行点。由于 SGX 支持多线程,因此安全区可以与 TCS 一样多的活动线程。与 SECS 结构一样,它只能由处理器访问,并且也是不可变的。
每个 TCS 至少与一个 SSA 结构相关联,该结构用于在异常和中断处理期间保存处理器的状态。它在退出时写入,在恢复时读取。
每个安全区都可以使用其堆栈和堆。RBP 和 RSP 寄存器在进入和退出时保存,但其值不会更改。堆不是在内部处理的,安全区需要自己的分配器。
每个安全区都由其属性及其页面的位置、内容和保护的哈希表示。具有相同哈希的两个安全区是相同的。此度量称为 MRENCLAVE,用于检查安全区的完整性。
每个飞地也由其作者签名。MRSIGNER 包含作者公钥的哈希值。MRENCLAVE 和 MRSIGNER 是使用 SHA-256 哈希函数生成的。
EINIT 指令使用 EINITTOKEN 结构来检查是否允许执行安全区。它包含安全区的属性、哈希和签名者身份。它使用使用启动密钥执行的 HMAC 进行身份验证。
每个安全区都与一个 SIGSTRUCT 结构相关联,该结构由其作者签名,并包含安全区度量、签名者公钥、版本号(ISV,反映安全级别)和产品标识符(ISVPRODID,以区分来自同一作者的飞地)。它允许确保安全区未被修改,然后使用不同的密钥重新签名。
此指令实例化新的安全区,定义其地址空间和信任根。这些信息存储在新分配的 SECS 中。
此指令允许向安全区添加新页面。操作系统全权负责选择页面及其内容。EPCM 的初始条目表示页面类型及其保护。
此指令允许按 256 字节块将页面的内容添加到安全区度量中。必须调用 16 次才能向度量值添加完整的页面。
此指令在初始化之前检查安全区是否与其 EINITTOKEN(相同的度量值和属性)相对应。它还检查令牌是否使用启动密钥进行签名。
此指令从安全区中永久删除页面。
1、应用程序请求将其安全区加载到内存中;
2、ECREATE 指令创建并填充 SECS 结构;
3、每个页面都使用 EADD 指令加载到受保护的内存中;
4、每个页面都使用 EEXTEND 指令添加到安全区的度量中;
5、EINIT 指令完成安全区的创建。
此指令将控制权从应用程序转移到安全区内的预定位置。它检查 TCS 是否可用并清除 TLB 条目。然后,它将处理器置于安全区模式,并保存 RSP/RBP 和 XCR0 寄存器。最后,它禁用基于事件的精确采样 (PEBS),使安全区执行显示为一条巨大的指令。
此指令将进程恢复到其原始模式,并清除位于安全区内的地址的 TLB 条目。控制权被转移到位于应用程序中并在RBX寄存器中指定的地址,并且TCS结构被释放。安全区需要在退出之前清除其寄存器,以防止数据泄露。
1、执行EENTRY指令;
2、应用程序上下文已保存;
3、处理器处于安全区模式。
1、执行EEXIT指令;
2、处理器处于正常模式.
此指令从当前 SSA 恢复上下文并恢复执行。
中断和异常会导致异步安全区退出 (AEX)。异步退出指针 (AEP) 指向位于应用程序内部的处理程序,该处理程序将在中断服务例程 (ISR) 处理异常后恢复执行。处理程序可以通过执行 ERESUME 指令来决定恢复或不执行安全区。
发生 AEX 时,安全区的上下文将保存在当前 SSA 中,并还原应用程序上下文。执行 ERESUME 指令时,将恢复安全区上下文。TCS 包含一个表示当前 SSA 的计数器,形成上下文堆栈。
1、中断或异常到达处理器;
2、保存安全区上下文,恢复应用程序上下文;
3、在操作系统的处理程序中继续执行;
4、处理程序返回 (IRET) 到 AEP,一个蹦床函数;
5、如果 AEP 决定恢复安全区执行,则执行 ERESUME;
6、将恢复之前保存的飞地上下文;
7、执行在安全区内停止的位置恢复。
安全区使用此指令来访问平台提供的不同密钥。每个密钥启用不同的操作(密封、证明)。
实例化安全区时,其代码和数据将受到保护,防止外部访问。但是当它停止时,它的所有数据都会丢失。密封是一种将数据安全地保存在安全区之外的方法,例如在硬盘驱动器上。安全区必须使用 EGETKEY 指令检索其密封密钥。它使用此密钥来加密并确保其数据完整性。使用的算法由安全区作者选择。
可以使用安全区标识完成密封。然后,密钥派生基于 MRENCLAVE 的值。两个不同的安全区具有不同的密钥,但同一安全区也具有两个版本,这会阻止数据的本地迁移。
也可以使用签名者身份进行密封。然后,密钥派生基于 MRSIGNER的值。两个不同的安全区仍然具有不同的密钥,但两个版本的安全区共享相同的密钥,并且可以读取密封的数据。如果多个安全区使用相同的密钥进行签名,则它们都可以读取彼此的数据。
不应允许较旧版本的安全区读取由较新版本的安全区密封的数据。为了防止这种情况,使用了安全版本号 (SVN)。它是每次更新后递增的计数器,会影响安全区的安全性。密钥是使用 SVN 派生的,其方式是安全区可以检索与当前或较旧安全级别相对应的密钥,但不能检索较新的密钥。
KEYREQUEST 结构用作 EGETKEY 指令的输入。它允许选择要获取的密钥,以及派生可能需要的其他参数。
TARGETINFO 结构用作 EREPORT 指令的输入。它用于标识哪个安全区(哈希和属性)将能够验证 CPU 生成的报告。
报告结构是 EREPORT 指令的输出。它包含安全区的属性、度量、签名者身份以及一些要在源和目标安全区之间共享的用户数据。处理器使用报告键在此结构上执行 MAC。
安全区使用此指令生成包含有关它的多个信息的 REPORT 结构,并使用目标安全区的报告密钥进行身份验证。
安全区代码和数据在初始化之前为纯文本格式。虽然部分在技术上可以加密,但解密密钥不能预安装(或者它不会提供任何额外的安全性)。秘密必须来自外部,可能是密钥和敏感数据。安全区必须能够向第三方证明它可以受信任(未被篡改)并在合法平台上执行。
存在两种类型的证明:
本地证明:同一平台的两个飞地之间的证明过程;
远程证明:安全区与不在平台上的第三方之间的证明过程。
1、必须在安全区 A 和安全区 B 之间建立通道。它被飞地 A 用来检索 B 的 MRENCLAVE。
2、安全区 A 将 EREPORT 与 B 的 MRENCLAVE 调用,为后者生成签名报告。
3、安全区 B 调用 EGETKEY 来检索其报告密钥并验证 EREPORT 结构的 MAC。如果有效,则安全区是预期的安全区,并在合法平台上运行。
远程证明需要一个称为引用安全区 (QE) 的体系结构安全区。此 enclave 通过使用另一个特殊密钥(预配密钥)对其进行签名,验证报表(本地可验证)并将其转换为报价(可远程验证)。
1、最初,安全区通知应用程序它需要位于平台外部的机密。应用程序与服务器建立安全通信。服务器以质询作为响应,以证明执行的飞区未被篡改,并且它执行的平台是合法的;
2、该应用程序提供报价安全区身份和对其安全区的挑战;
3、安全区生成一个清单,其中包括质询答案和一个临时公钥,稍后将用于保护服务器和安全区之间的通信。它生成清单的哈希,该哈希包含在 EREPORT 指令的用户数据部分中。该指令为报价安全区生成一个报告,该报告将清单绑定到安全区。安全区将报告传递给应用程序。
4、应用程序将报告传输到报价隔区进行验证和签名。
5、QE 使用 EGETKEY 指令检索其报告键并验证报告。它创建 QUOTE 结构,并在将其返回给应用程序之前使用其预配密钥对其进行签名。
6、应用程序将 QUOTE 和关联的清单发送到服务器进行验证。
7、服务器使用英特尔提供的证明服务来验证 QUOTE 签名。然后,它使用 QUOTE 用户数据中的哈希检查清单完整性。最后,它确保清单包含质询的预期答案。
从概念上讲,SGX飞地可以被视为能够执行任意算法的黑盒。这个黑匣子可以使用下面介绍的三种不同方式与外界进行通信。
应用程序可以在 enclave 内调用预定义的函数,将输入参数和指针传递给应用程序中的共享内存。从应用程序到安全区的那些调用称为 ECALL。
当安全区执行时,它可以对应用程序中的预定义函数执行 OCALL。与 ECALL 相反,OCALL 不能与应用程序共享安全区内存,因此它必须在 OCALL 之前将参数复制到应用程序内存中。
执行也可能由于中断或异常而退出安全区。这些安全区退出事件称为异步退出事件 (AEX)。他们可以从安全区内的任意点将控制权从安全区转移到应用程序。
开发使用 SGX 安全区的应用程序需要确定要保护的资源、包含这些资源的数据结构以及管理这些资源的代码。然后,必须将已识别的所有内容都放置在安全区内。安全区文件是与传统操作系统加载程序兼容的库。它包含安全区的代码和数据,这是磁盘上的纯文本。
必须仔细设计应用程序与其安全区之间的接口。安全区声明应用程序可以调用哪些函数,以及它可以调用应用程序中的哪些函数。安全区输入参数可以通过非安全代码进行观察和修改,因此必须对其进行广泛检查。由于安全区无法直接访问操作系统的服务,因此必须调用其应用程序。这些调用不应暴露任何机密信息,也不保证按安全区预期执行。
软件开发工具包 (SDK) 为开发人员提供了开发支持 SGX 的应用程序所需的一切。它由一个用于在应用程序和安全区之间生成接口函数的工具、一个用于在使用安全区之前对其进行签名的工具、一个用于调试它的工具以及用于衡量性能的最后一个工具组成。它还包含模板和示例项目,用于在Windows下使用Visual Studio或在Linux下使用Makefiles开发安全区。
平台软件 (PSW) 是允许启用 SGX 的应用程序在目标平台上执行的软件堆栈。它适用于Windows和Linux操作系统,由4个主要部分组成:
提供对硬件功能的访问权限的驱动程序;
用于执行和证明的多个支持库;
环境运行所需的建筑飞地;
用于加载安全区并与之通信的服务。
为了允许安全环境执行,需要多个架构安全区 (AE)。它们由英特尔提供和签名。他们实施启动策略,执行预配和证明过程,甚至更多。
启动飞地(LE)是负责将EINITTOKEN结构分发给希望在平台上执行的其他飞地的飞地。它会检查安全区的签名和身份,以查看它们是否有效。为了生成令牌,它使用启动密钥,这是唯一能够检索它的飞地。
配置隔区 (PvE) 是负责通过与英特尔供应服务服务器通信来检索证明密钥的安全区。为此,它使用PcE提供的证书证明平台的真实性。
平台服务安全区 (PSE) 是为其他安全区提供多种服务的体系结构安全区,例如单调计数器、可信时间等。这些飞地利用管理引擎(ME),这是一个隔离的,据称是安全的协处理器,用于管理平台。
每个支持 SGX 的 CPU 都包含两个存储在电子保险丝内的根密钥:根配置密钥 (RPK) 和根密封密钥 (RSK)。英特尔知道 RPK 启用远程认证过程,而 RSK 仅由平台知道。尽管SGX的攻击者模型不包括物理攻击,但已经努力使处理器架构难以适应,或者至少使提取密钥成为一项非常昂贵的操作。有了足够的硬件,就可以读取电子保险丝,但以一种破坏性的方式。这就是为什么电子保险丝上仅存储加密版本的密钥的原因。物理不可克隆函数 (PUF) 用于存储用于在处理器执行期间破译其他密钥的对称密钥。
英特尔在制造过程中创建的第一个密钥是根配置密钥 (RPK)。此密钥在位于称为英特尔密钥生成设施 (iKGF) 的设施内的专用硬件安全模块 (HSM) 上随机生成。英特尔负责维护一个包含 HSM 生成的所有密钥的数据库。RPK 被发送到多个生产设施,嵌入处理器电子保险丝内。
位于电子保险丝内的第二个钥匙称为根密封钥匙 (RSK)。与第一个密钥一样,它保证在生产的每个单元之间在统计上有所不同。与RSK相反,英特尔宣布从其生产链中删除这些密钥的每一条痕迹,以便每个平台都有一个只有自己知道的唯一密钥。
根据设计,安全区无权访问根密钥。不过,它可以访问从根密钥派生的密钥。派生函数允许安全区作者指定密钥派生策略。这些策略允许使用受信任的值,如 MRENCLA、MRSIGNER 和/或安全区的属性。安全区无法派生属于 MRENCLAVE 或其他安全区的 MRSIGNER 的密钥。此外,当密钥派生策略不使用字段时,它会自动设置为零。因此,即使非专用密钥可用,也无法从中派生专用密钥。
为了添加来自用户的熵,在派生过程中使用一个名为所有者纪元的值作为参数。此值在启动时通过派生密码进行配置,并在每个电源周期期间保存在非易失性存储器中。此值必须保持不变,安全区才能检索相同的密钥。相反,当平台所有者更改时,必须更改此值,因为它会阻止新所有者访问旧所有者的个人信息,直到恢复原始密码。
SGX基础设施支持其硬件和软件组件的TCB更新。每个组件都有一个SVN,每次安全更新后都会递增。新的SVN导致新的密封钥匙。存在一个过程,允许较新的 TCB 访问较旧 TCB 的密封密钥,以允许数据迁移。旧 TCB 无法访问新 TCB 的密钥。
此密钥派生自 RPK,并用作英特尔配置服务和处理器之间的信任根(绑定到 TCB 版本)。由于将非 SGX 处理器允许进入一组合法的 SGX 处理器会损害所有处理器的远程证明,因此必须采取极端预防措施来禁止访问预配密钥。目前,仅当安全区由英特尔签名时,启动隔区才允许访问此密钥(英特尔的 MRSIGNER 在启动隔区代码中硬编码)。
此密钥派生自 RPK 和 RSK。在组中注册处理器期间,每个平台的私钥都使用此密钥加密并发送到英特尔认证服务。必须注意的是,私钥不能仅使用 RPK 加密,因为这会破坏使用的匿名注册协议。同样,私钥不能仅使用 RSK 加密,因为它将允许非特权飞地访问平台的私钥。不幸的是,已知 RSK 生成过程存在不确定性,人们可能会认为英特尔知道每个平台的私钥。
此密钥派生自 RSK,由启动隔区用于生成 EINITTOKEN。每个未由英特尔签名的飞地都必须获取此令牌,否则处理器无法实例化它。只有特定的 MRSIGNER(其对应的私钥只有英特尔知道)才能访问启动密钥。在 SGXv2 中,可以通过编程方式更改启动隔区的 MRSIGNER,但目前尚不清楚英特尔打算如何将访问控制应用于配置密钥。
此密钥派生自 RSK,用于加密与当前平台相关的数据。重要的是不要使用非专用的密封密钥 - 无论是用于加密还是身份验证 - 因为这会损害安全区的安全性。
此密钥派生自 RSK,用于本地证明过程。
多年来,英特尔 SGX 因其缺乏对各种侧信道攻击的弹性而臭名昭著。虽然英特尔一直警告说,飞地必须以防止侧信道攻击的方式编写,但完全安全的技术不会对飞地开发人员施加这样的限制。下面总结了对英特尔 SGX 的一些攻击,让读者大致了解执行此类攻击所需的条件,以及执行这些攻击可以获得哪些信息。
为了在英特尔 SGX 围圈上执行高速缓存定时攻击,作者将两个内核线程固定到共享同一物理内核和 L1 高速缓存的两个逻辑内核(请参见下图)。受害线程正在运行的算法版本容易受到安全区内的缓存攻击。探测缓存行是使用 RDPMC 指令完成的,该指令要求在主管模式下启动计数器,这完全在 SGX 安全模型中。
与安全区的通信是使用共享内存而不是 ECALL/OCALL 执行的,因为不必从正在运行的安全区进行上下文切换。这是攻击与现实世界场景拉开距离的地方。ECALL/OCALL将导致整个缓存被逐出,从而阻止攻击起作用。
攻击者线程不能位于不同的进程中,因为进程上下文切换需要更新页表 (PT),因此必须更改包含 PR 基址的 CR3 寄存器,从而触发 TLB 和 L1 缓存刷新。
SGX SDK的AES实施不易受到此类侧信道攻击。
Johannes Götzfried, Moritz Eckert, Sebastian Schinzel, and Tilo Müller. Cache Attacks on Intel SGX. In Proceedings of the 10th European Workshop on Systems Security (EuroSec'17). ACM. 2017. http://www.sharcs-project.eu/m/documents/papers/a02-gotzfried.pdf
AsyncShock 背后的想法是促进利用安全区内的现有同步错误。特别是,它有助于利用释放后使用(UAF)和检查时间使用时间(TOCTOU)问题。控制平台(位于英特尔 SGX 威胁模型中)的攻击者可以随时中断安全区线程。
中断线程是使用 mprotect(2) 系统调用来删除页面上的读取和执行权限来完成的。由于传统的页面遍历是在检查是否允许访问 EPC 页面之前执行的,因此应用程序可以了解允许 enclave 访问哪些内存页面(即使它无法查看页面包含的内容)。当线程退出安全区时,将在不受信任环境中的相应处理程序中恢复执行。
应用程序启动允许执行的第一个线程。读取和执行权限将从包含 free(3) 函数的代码页中删除。当线程调用 free(3) (1) 时,会发生访问冲突,导致应用程序 (2) 捕获 AEX 和分段错误。在允许线程继续之前,将恢复此页面的权限,但删除包含调用指令的页面的权限。当下一个标记的页面被点击 (3) 时,导致另一个 AEX 和分段错误 (4),它表示 free(3) 已返回。在信号处理程序中,将再次还原权限。第一个线程停止,第二个线程启动并进入安全区 (5)。此示例的示例代码可在下面找到:
// Thread 1 enters the enclave
...
free(pointer);
// Thread 1 is interrupted, exits the enclave
pointer = NULL;
...
// Thread 2 enters the enclave
...
if (pointer != NULL) {
// Thread 2 uses a pointer to freed memory
}
...
结合结构内的函数指针和为新分配重用释放内存的内存分配器,这些类型的错误有可能允许远程代码执行 (RCE)。TOCTOU 错误可能允许在安全区中使用不正确的参数,这也可能会产生巨大的安全隐患。考虑下面的简单示例:
...
/* 1 */ static int g_index = 0;
/* 2 */ static int g_value = 0;
/* 3 */ static int g_array[256];
/* 4 */
/* 5 */ void ocall_set_index(int index) {
/* 6 */ g_index = g_index;
/* 7 */ }
/* 8 */
/* 9 */ void ocall_set_value(int value) {
/* 10 */ if (g_index < sizeof(g_array)) {
/* 11 */ g_array[g_index] = value;
/* 12 */ }
/* 13 */ }
...
似乎无法使用无效g_index访问g_array。第一个线程可以执行ocall_set_value函数的第 9 行和第 10 行,然后被中断。然后,第二个线程可以执行ocall_set_index的第 5 行到 7 行,以在第一个线程检查g_index的值后更改该值。然后可以恢复第一个线程,并且在第 11 行执行的访问将使用第二个线程设置的值 g_index 完成。这会导致越界 (OOB) 访问。
这些攻击需要完全控制平台,知道安全区内正在运行哪些代码,并在其中发现同步错误。针对此攻击的最佳保护是禁用安全区内的多线程,但这显然会阻碍程序的性能。另一种解决方案可能是加密安全区的代码,并使用远程证明过程为安全区提供解密其代码所需的密钥。
Nico Weichbrodt, Anil Kurmus, Peter Pietzuch and Rüdiger Kapitza. AsyncShock: Exploiting Synchronisation Bugs in Intel SGX Enclaves. In: ESORICS 2016. Lecture Notes in Computer Science, vol 9878. Springer. 2016. https://www.ibr.cs.tu-bs.de/users/weichbr/papers/esorics2016.pdf
在 CPU 内部,分支预测单元 (BPU) 使用分支目标缓冲区 (BTB) 来记录对分支预测有用的信息。虽然此信息仅由处理器内部使用,但英特尔 SGX 在安全区模式切换期间不会清除其分支历史记录。这允许在安全区内获取(或不采用)分支影响对安全区内分支的预测。开发了一种称为分支阴影的技术来推断正在运行的飞地的控制流。
这个想法是在不受信任的环境中复制安全区程序的控制流,仔细选择映射此新代码的地址,以便在 BTB 内部引入冲突。通过先在安全区代码中执行分支,然后在阴影代码中执行分支,第二个分支的预测将受到第一个分支结果的影响。要了解 CPU 预测的内容,最后分支记录 (LBR) 只能在不受信任的环境中使用,因为它对安全区禁用。
为了使此攻击起作用,必须尽可能频繁地中断安全区执行,以执行必要的测量以推断安全区的控制流。APIC 计时器可用于每 ~50 个周期中断一次执行,如果需要更高的精度,禁用 CPU 缓存最多允许每 ~5 个周期中断一次。
以下是对安全区内发生的条件分支的检测说明(绿色表示分支被占用的情况,红色表示未采用分支的情况):
1、执行安全区的条件分支指令。如果采取,相应的信息存储在 BTB 中。由于这是在安全区内发生的,因此 LBR 不会报告此信息。
2、安全区执行被 APIC 计时器中断,操作系统将获得控制权。
3、操作系统启用 LBR 并执行重影代码。
4、如果占用了安全区中的分支,则 BPU 会正确预测将占用该分支,即使目标地址无效,因为它位于安全区内。如果未采取,BPU 会错误地预测分支不会被占用。
5、通过禁用和检索 LBR 内容,OS 可以通过检查是否正确预测了阴影条件分支来了解是否采用了安全区分支。
该论文的作者提出了类似的技术来检测无条件分支和间接分支(攻击无法恢复目标地址)。这种攻击需要完全控制平台,并了解在安全区内执行的代码。它还引入了安全区可能能够检测到的显著减速(但它并不像执行 RDTSC 那么简单,因为它不允许在安全区内)。
Sangho Lee, Ming-Wei Shih, Prasun Gera, Taesoo Kim, Hyesoon Kim, and Marcus Peinado. Inferring fine-grained control flow inside SGX enclaves with branch shadowing. In Proceedings of the 26th USENIX Conference on Security Symposium (SEC'17), USENIX. 2017. https://www.usenix.org/system/files/conference/usenixsecurity17/sec17-lee-sangho.pdf
SGX用户表达的第一个担忧是,他们必须信任英特尔。值得注意的是,英特尔表示,它不会在其制造工厂重新训练嵌入在每个CPU芯片中的RPK。但是,如果事实证明他们以任何可能的方式这样做了,它将使每个平台的安全性无效。此外,由英特尔签名的飞地被授予特殊权限,例如启动飞地 (LE),用于将允许执行的飞地列入白名单。开发人员需要注册到英特尔程序中,才能对飞地的发布版本进行签名。存在一个开源计划来开发替代 LE,应该允许从 SGXv2 开始替换当前的 LE。
第二个问题是,恶意软件有可能在飞地内执行其恶意代码,基本上不受所有人和所有人的影响。但是,请务必记住,安全区内的代码没有 I/O。它完全依赖于其随附的应用程序来访问网络、文件系统等。因此,从技术上讲,分析应用程序可以告诉您很多关于安全区可以对系统执行的操作,从而减轻对“在安全区内运行的受保护恶意代码”的恐惧。另一方面,缺乏可信的I / O是保护用户信息的一个问题,并且已经在这个问题上做了一些工作,包括专有解决方案,如保护音频视频路径(PAVP)和学术解决方案,如SGXIO。
第三个问题是Meltdown和Spectre对SGX飞地的影响。虽然它们不容易受到前者的影响,但SgxPectre论文的作者已经证明,Spectre的变体允许读取安全区内存和寄存器值。这使得平台的密封密钥以及证明密钥的恢复成为可能,有效地绕过了SGX提供的整体安全性。英特尔发布了微代码更新以防止这些攻击,并且由于安全版本号(SVN),它还能够确保已应用这些补丁以通过远程证明过程。最近发布了一种名为SpectreRSB的新攻击,它能够通过针对返回堆栈缓冲区(RSB)而不是BTB来绕过补丁。英特尔将不得不发布另一个微代码更新来修复这个新问题。
英特尔 SGX 是一项很有前途的技术,仍处于起步阶段。它满足了可信计算行业的需求,允许保护飞地免受平台上执行的其他软件的影响,并以有限的方式免受硬性脾气的影响。它这样做的同时,为平台所有者提供了对执行的某种程度的控制,以允许资源管理。证明过程允许机密安全地传输到安全区。由于提供了SDK,开发支持SGX的应用程序变得非常容易。
但是,英特尔 SGX 的当前迭代仍然存在一些问题。可悲的是,容易受到侧信道攻击限制了平台提供的安全性,迫使开发人员主动确保他们的程序不会受到攻击。在一个完美的世界里,开发人员不需要担心这些考虑,SGX应该确保这些攻击是不可能的。这些攻击都可以通过加密安全区的代码并通过远程证明来证明密钥来防止,但这会带来不便。最后,用户必须对英特尔充满信心,虽然到目前为止他们已经展示了完美的事件响应,但不确定性仍然存在。
源于博客https://blog.quarkslab.com/overview-of-intel-sgx-part-2-sgx-externals.html,仅供参考。此博客为笔记。