赞
踩
本文内容来自于Intel vol3 Chapter 33 Introduction to Intel® Software Guard Extensions
Intel Software Guard Extensions (Intel SGX) 是添加到 Intel 架构处理器中的一组指令和机制,用于内存访问。Intel SGX硬件使用户空间应用程序能够保留私有的代码和数据内存区域。旨在以硬件安全为强制性保障, 不依赖于固件和软件的安全状态, 提供用户空间的可信执行环境。
Intel SGX 可以包含两个指令扩展集合,分别称为 SGX1 和 SGX2。
我手中的一台Intel® Core™ i3-9100,只支持SGX1(Intel SGX)硬件功能,有的处理器默认是不开启的,比如我手中的这台处理器,需要在BIOS中打开。
# cpuid | grep -i sgx
SGX: Software Guard Extensions supported = true
......
SGX1 supported = true
SGX2 supported = false
SGX1 扩展允许应用程序实例化一个受保护的容器,称为保护区域(enclave)。保护区域是一个可信的内存区域,其中应用程序功能的关键部分具有硬件增强的机密性和完整性保护。还引入了新的访问控制来限制对不驻留在保护区域中的软件的访问。
SGX2 扩展允许在保护区域内对保护区域资源和线程执行进行更灵活的运行时管理。
"enclave"在计算机安全领域中指的是一种受保护的内存区域,它具有独立的安全性和隔离性。为了保持准确性,"enclave"在这里应该保留为英文术语。
Intel SGX1 和 SGX2提供基于硬件的内存加密,可隔离内存中的特定应用程序代码和数据。“Intel SGX”允许用户级代码分配称为“enclave”的专用内存区域,这些区域旨在保护其不受以更高权限级别—所有Ring0级别的攻击者(OS、VMM等)运行的进程的影响。只有英特尔SGX提供如此精细的控制和保护。
我后续还是把enclave翻译为保护区域。
上图中的Enclave code和Enclave data存储在普通的EPC页面中,其EPCM(Enclave Page Cache Map)页面类型为PT_REG。因此,SSA的内容对Enclave软件是可访问的。
而SESC 和 TCS 存储在一个专用的EPC页面中,该页面的页面类型为PT_SECS和PT_TCS。Enclave代码不可以访问SECS页面和TCS页面。Enclave代码无法直接读取或写入持有SESC 和TCS的EPC页面的内容。这确保了SESC 和TCS中的敏感信息的机密性和完整性。Enclave需要通过SGX提供的特定接口和机制来与SESC 和TCS进行交互,而不是直接访问EPC页面。
Enclave是嵌入在进程中的受信任执行环境,具有以下特点:
(1)拥有自己的代码和数据:Enclave 是一个独立的执行环境,具有自己的代码和数据,与主进程的其他部分隔离开来。
(2)提供机密性:Enclave 使用加密技术保护其内部的代码和数据,防止未经授权的访问和泄露。
(3)提供完整性:Enclave 使用安全机制确保其内部的代码和数据的完整性,防止被篡改或修改。
(4)受控入口点:Enclave 只能通过指定的入口点进行访问和交互,而其他部分无法直接访问 Enclave 内部。
(5)支持多线程:Enclave 可以在其内部支持多个线程的执行,允许并行处理和并发操作。
(6)对应用程序内存的完全访问权限:Enclave 具有对其所属进程的内存的完全访问权限,可以读取和修改应用程序内存中的数据。
Intel SGX 允许应用程序的受保护部分在明文中进行分发。在构建保护区域之前,保护区域的代码和数据是可以自由检查和分析的。受保护部分被加载到保护区域中,其中的代码和数据会被测量。一旦应用程序的受保护代码和数据加载到保护区域中,内存访问控制会限制外部软件的访问。保护区域可以向远程方证明其身份,并提供安全提供密钥和凭证所需的基本构件。应用程序还可以请求一个特定于保护区域和特定于平台的密钥,用于保护希望存储在保护区域外部的密钥和数据。
受保护部分的分发:Intel SGX允许应用程序的受保护部分在明文中进行分发,这意味着保护区域的代码和数据可以在没有加密或混淆的情况下共享和分发。这使得保护区域的分发和部署变得更加容易。
保护区域的构建和检查:在构建保护区域之前,保护区域的代码和数据是公开的,可以进行检查和分析。这种透明性允许进行安全审计,验证保护区域的功能和安全性。
测量和内存访问控制:一旦应用程序的受保护代码和数据加载到保护区域中,它们将进行测量过程。这个测量过程确保了保护区域内代码和数据的完整性。在建立保护区域之后,将强制执行内存访问控制,以限制外部软件对保护区域的访问。这种隔离性有助于保护保护区域内容的机密性和完整性。
身份和安全提供:保护区域具有向远程方证明其身份的能力。这使得安全通信成为可能,并在保护区域与外部实体之间建立信任。保护区域可以提供安全密钥和凭证的必要构建模块,增强系统的整体安全性。
保护区域特定密钥:在保护区域内运行的应用程序可以请求一个特定于保护区域和特定于平台的密钥。这个密钥可以用于保护敏感信息,例如应用程序希望在保护区域外部存储的密钥和数据。这个特性为需要在保护区域安全内存之外持久保存的数据提供了额外的安全层。
Intel SGX引入了两个对于Intel架构来说非常重要的功能。
第一个是保护区域内存访问语义的改变( the change in enclave memory
access semantics)。第二个是对应用程序地址映射的保护(protection of the address mappings of the application)。
这两个功能完成了对保护区域的机密性和完整性的保护。
(1)保护区域内存访问语义:Intel SGX在保护区域内引入了新的内存访问语义。在保护区域内部进行的内存访问是受到保护且与外部软件隔离的,提供了增强的机密性和完整性。保护区域内存访问语义确保敏感数据和代码在保护区域内部得到安全访问和处理,防止未经授权的访问或篡改。
(2)保护地址映射:Intel SGX还对应用程序的地址映射提供了保护。地址映射将应用程序使用的虚拟地址与物理内存位置关联起来。通过保护地址映射,Intel SGX防止恶意攻击试图篡改或操纵内存映射,确保保护区域内存的完整性和安全性。
如下图所示:
保护区域内存管理分为两个部分:地址空间分配和内存提交。
(1)地址空间分配(虚拟地址):地址空间分配指定了保护区域可以使用的线性地址范围,这个范围被称为ELRANGE(Enclave Range)。在这个区域内,实际的资源并没有被分配。地址空间分配为保护区域提供了可用的虚拟地址范围。
(2)内存提交(物理内存):内存提交是将实际的内存资源(作为页面)分配给已分配的地址空间的过程。
这个两阶段的技术允许保护区域灵活控制其内存使用,并在保护区域需求较低时动态调整,避免过度使用内存资源。内存提交将物理页面添加到保护区域中,使得保护区域可以使用这些页面存储数据或代码。操作系统可能会支持单独的分配和提交操作,以提供更灵活的内存管理控制。
通过地址空间分配和内存提交的机制,保护区域可以根据需要动态地管理其内存使用情况。它可以根据实际需求调整内存资源的分配,避免浪费和过度使用,提高内存的利用效率。这种灵活性使得保护区域能够适应不同的内存需求,并在资源有限的环境中有效地管理内存。
在创建保护区域时,保护区域的代码和数据是从明文源(非保护区域内存)加载的:
(1)保护区域的代码和数据通常存储在非保护区域内存中,例如主机内存或磁盘上的文件。在创建保护区域时,这些代码和数据会从非保护区域内存加载到保护区域中。
(2)加载过程包括将代码和数据从非保护区域内存复制到保护区域的内存空间中。这些代码和数据在加载过程中可能会经过验证和测量,以确保其完整性和安全性。
(3)一旦代码和数据被成功加载到保护区域内存中,保护区域就可以在受保护的环境中执行这些代码和访问这些数据。通过将代码和数据加载到保护区域中,可以实现对敏感信息的保护,防止未经授权的访问和篡改。
需要注意的是,加载过程中的明文源是指非保护区域内存,因此在加载过程中需要采取适当的安全措施,以防止潜在的安全漏洞和攻击。
在通常情况下,不受信任的应用程序代码通过使用Intel SGX提供的EENTER叶子函数来启动一个已初始化的保护区域。这将控制转移到位于受保护的保护区域页面缓存(EPC)中的保护区域代码上。保护区域代码通过EEXIT叶子函数返回给调用者。在进入保护区域时,硬件将控制权转移到保护区域内部的软件。保护区域内部的软件将堆栈指针切换到保护区域内部的一个堆栈上。当从保护区域返回时,软件会切换回原始的堆栈指针,然后执行EEXIT叶子函数。
具体流程如下:
不受信任的应用程序代码调用EENTER叶子函数,将控制权传递给保护区域内的代码。
硬件将控制转移到保护区域内部的软件。
保护区域内的软件将堆栈指针切换到保护区域内的堆栈上,使得执行过程在保护区域内进行。
在保护区域内部执行相应的代码和操作。
当需要从保护区域返回时,软件将堆栈指针切换回原始的堆栈,然后执行EEXIT叶子函数。
EEXIT叶子函数将控制权返回给调用者,不受信任的应用程序代码继续执行。
通过使用EENTER和EEXIT叶子函数,控制权可以在不受信任的应用程序代码和受保护的保护区域代码之间进行安全的转移。这样可以确保保护区域内的代码在受保护的环境中执行,并且与不受信任的应用程序代码之间存在明确的边界。这有助于保护保护区域内的敏感数据和功能免受不受信任应用程序代码的恶意访问和篡改。
在支持SGX2扩展的处理器上,保护区域编写者可以使用SGX2指令集在保护区域构建和运行后向保护区域添加内存。这些指令允许向保护区域添加额外的内存资源,用于堆等区域的使用。此外,SGX2指令还允许保护区域添加新的线程。SGX2特性为软件模型提供了额外的能力,而不会改变Intel SGX架构的安全属性。
通过SGX2指令,保护区域可以动态地增加内存和线程,以满足运行时的需求。这为保护区域内的应用程序提供了更大的灵活性和扩展性。例如,当保护区域需要更多的内存来处理大量数据或动态分配内存时,可以使用SGX2指令来向保护区域添加额外的内存资源。同样地,当保护区域需要并行执行任务时,可以使用SGX2指令来添加新的线程。
值得注意的是,SGX2特性提供了额外的功能,但不会改变Intel SGX架构的安全属性。保护区域的安全性仍然由SGX的安全保护机制和硬件隔离提供。通过在运行时动态添加内存和线程,保护区域可以更好地适应动态需求,同时保持保护区域内数据和代码的安全性和隔离性。
从保护区域中调用外部过程通常可以使用EEXIT叶子函数,并在受信任部分和不受信任部分之间建立软件约定。
以下是该过程的一般概述:
保护区域内的受信任部分准备需要传递给外部过程的参数和数据。
受信任部分调用EEXIT叶子函数,将控制权转移到保护区域外的不受信任部分。
不受信任部分位于保护区域外的不受信任环境中(如操作系统或应用程序代码),从EEXIT函数接收控制权。
不受信任部分使用传递的参数和数据执行外部过程。
外部过程完成后,不受信任部分可能需要处理返回值或结果。
控制权然后转移回保护区域内的受信任部分,通常使用受信任部分和不受信任部分之间约定的软件方式
这个软件约定定义了受信任部分和不受信任部分之间的通信方式、数据交换和控制流管理。它确保了在保持Intel SGX提供的隔离和安全保证的同时,受信任部分可以安全地调用外部过程并在保护区域内部接收结果。
需要仔细设计和实现这个约定,以确保保护区域数据和代码的完整性和安全性。可能需要适当的参数验证、数据编组和安全通信机制来建立一个稳健的受信任-不受信任接口。
一个活动的保护区域会消耗Enclave Page Cache(EPC)中的资源(参见5节)。Intel SGX提供了EREMOVE指令,保护区域管理器可以使用该指令来回收分配给保护区域的EPC页面。当保护区域被拆除时,保护区域管理器会对每个保护区域页面使用EREMOVE。
EREMOVE指令的成功执行将使该EPC页面可供分配给其他保护区域使用。通过使用EREMOVE,可以有效地管理EPC资源的分配和回收,确保资源的高效利用。
当保护区域不再需要某个页面时,保护区域管理器可以使用EREMOVE指令来释放该页面,以便将其分配给其他需要的保护区域。这样可以最大程度地提高EPC资源的利用率,并避免资源浪费。
需要注意的是,EREMOVE指令的使用需要谨慎,确保只在适当的时机和情况下使用,以避免对活动中的保护区域造成不必要的影响。对于正在运行的保护区域,应在确保其安全性和正确性的前提下进行资源回收操作。
在运行一个保护区域(enclave)时,有两个主要的数据结构与之相关:SGX保护区域控制结构(SGX Enclave Control Structure,简称SECS)和线程控制结构(Thread Control Structure,简称TCS)。
还有一个比较重要的数据结构:状态保存区域(State Save Area,SSA)。
SECS在执行ECREATE指令时创建。
每个保护区域都有一个对应的SECS,其中包含关于保护区域的元数据,这些元数据由硬件使用,无法直接被软件访问。SECS中包含一个字段用于存储保护区域的构建测量值(build measurement value)。这个字段名为MRENCLAVE,由ECREATE指令初始化,并在每次EADD和EEXTEND指令执行后更新。它在EINIT指令执行后被锁定。
SGX在与每个Enclave相关联的SECS中存储每个Enclave的元数据。每个SECS都存储在一个专用的EPC页面中,该页面的页面类型为PT SECS。这些页面不打算映射到任何Enclave的地址空间中,而是由CPU的SGX实现专用使用。
通过将SECS存储在专用的EPC页面中,SGX确保了Enclave的元数据的机密性和完整性。SECS的访问仅限于CPU的SGX实现,从而保护了Enclave的关键信息免受非授权访问和篡改。
Enclave的身份几乎等同于它的SECS。将Enclave启动的第一步是分配一个EPC页面作为Enclave的SECS,而销毁Enclave的最后一步是释放持有其SECS的页面。标识拥有EPC页面的Enclave的EPCM条目字段指向Enclave的SECS。系统软件在调用SGX指令时使用Enclave的SECS的虚拟地址来识别Enclave。
SECS是一个包含了关键信息的数据结构,用于管理和保护Enclave的状态、机密信息以及与Enclave相关的安全属性。SECS包含了Enclave的基址、大小、权限设置、密钥材料等重要信息。在Enclave的生命周期中,SECS的存在始终与Enclave的身份相对应。
所有的SGX指令都以虚拟地址作为输入。由于SGX指令使用SECS地址来标识Enclave,系统软件必须在其页表中创建指向所管理的Enclave的SECS的条目。然而,系统软件无法访问任何SECS页面,因为这些页面存储在PRM中。SECS页面不打算在其Enclave的虚拟地址空间内进行映射,而且支持SGX的处理器明确阻止Enclave代码访问SECS页面。
这种看似任意的限制是为了让SGX实现能够在SECS中存储敏感信息,并确保没有潜在恶意软件能够访问这些信息。例如,SDM(Software Developer’s Manual)中指出,每个Enclave的测量值存储在其SECS中。如果软件能够修改Enclave的测量值,SGX的软件认证方案将无法提供安全保证。
SECS结构体字段如下所示:
// linux-sgx/common/inc/internal/global_data.h
typedef struct _global_data_t
{
......
uint64_t elrange_start_address; /* the base address provided in the enclave's SECS (SECS.BASEADDR) */
uint64_t elrange_size; /* the size of the enclave address range provided in the enclave's SECS (SECS.SIZE) */
......
} global_data_t;
// linux-sgx/sdk/trts/init_enclave.cpp
extern "C" int init_enclave(void *enclave_base, void *ms)
{
......
g_enclave_size = g_global_data.elrange_size;
......
//if elrange is set, we should set enclave_base to correct value
g_enclave_base = g_global_data.elrange_start_address;
......
}
// linux-sgx/common/inc/internal/global_data.h
#define RELRO_SECTION_NAME ".data.rel.ro"
// linux-sgx/sdk/trts/init_enclave.cpp
uint64_t g_enclave_base __attribute__((section(RELRO_SECTION_NAME))) = 0;
uint64_t g_enclave_size __attribute__((section(RELRO_SECTION_NAME))) = 0;
# readelf -S app There are 37 section headers, starting at offset 0x7fc0: Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align ...... [23] .data.rel.ro PROGBITS 0000000000003d20 00002d20 0000000000000038 0000000000000000 WA 0 0 32 ...... Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), l (large), p (processor specific)
g_enclave_base 和 g_enclave_size便是Enclave的基址、大小,是两个全局变量,保存在ELF文件中的".data.rel.ro"节中。
我们可以在程序中打印出来:
extern uint64_t g_enclave_base;
extern uint64_t g_enclave_size;
void ecall_get_enclave_address()
{
size_t enclave_start = (size_t)g_enclave_base;
size_t enclave_end = enclave_start + (size_t)g_enclave_size - 1;
printf("enclave_start = %p, g_enclave_size = 0x%lx, enclave_end = %p\n", enclave_start, g_enclave_size, enclave_end);
}
enclave_start = 0x7f65ef000000, g_enclave_size = 0x1000000, enclave_end = 0x7f65efffffff
Enclave的线性(虚拟)地址范围从:0x7f65ef00000 ~ 0x7f65efffffff,大小:0x1000000(16MB)。
0x1000000 / 0x100000 = 16MB
我们可以根据Enclave的基址、大小,来判断一个address是否在Enclave中,已经有现成的API:
// linux-sgx/common/inc/sgx_trts.h
/* sgx_is_within_enclave()
* Parameters:
* addr - the start address of the buffer
* size - the size of the buffer
* Return Value:
* 1 - the buffer is strictly within the enclave
* 0 - the whole buffer or part of the buffer is not within the enclave,
* or the buffer is wrap around
*/
int SGXAPI sgx_is_within_enclave(const void *addr, size_t size);
// linux-sgx/sdk/trts/trts.cpp extern uint64_t g_enclave_base; extern uint64_t g_enclave_size; // sgx_is_within_enclave() // Parameters: // addr - the start address of the buffer // size - the size of the buffer // Return Value: // 1 - the buffer is strictly within the enclave // 0 - the whole buffer or part of the buffer is not within the enclave, // or the buffer is wrap around // int sgx_is_within_enclave(const void *addr, size_t size) { size_t start = reinterpret_cast<size_t>(addr); size_t end = 0; size_t enclave_start = (size_t)g_enclave_base; size_t enclave_end = enclave_start + (size_t)g_enclave_size - 1; // g_global_data.enclave_end = enclave_base + enclave_size - 1; // so the enclave range is [enclave_start, enclave_end] inclusively if(size > 0) { end = start + size - 1; } else { end = start; } if( (start <= end) && (start >= enclave_start) && (end <= enclave_end) ) { return 1; } return 0; }
TCS可以使用EADD指令或SGX2指令创建。
每个保护区域包含一个或多个TCS结构。TCS包含由硬件使用的元数据,用于在进入/退出保护区域时保存和恢复线程特定信息。TCS中有一个字段名为FLAGS,可以被软件访问。这个字段只能被调试保护区域访问。标志位DBGOPTIN允许单步调试与TCS相关联的线程。
SGX的设计完全支持多核处理器。通过不同的线程,多个逻辑处理器可以同时执行同一个Enclave的代码。
SGX允许在多核处理器上并发地执行同一个Enclave的代码。这意味着Enclave可以利用多个核心的计算能力,提高并行处理的效率。不同的线程可以同时执行Enclave的代码,从而在同一时间内完成更多的计算任务。
SGX的实现为每个执行Enclave代码的逻辑处理器使用一个线程控制结构(TCS)。因此,Enclave的作者必须为Enclave预留至少与其预期支持的最大并发线程数相同数量的TCS实例。
每个TCS都存储在一个专用的EPC(Enclave Page Cache)页面中,其EPCM(Enclave Page Cache Map)条目类型为PT TCS。SDM(Software Developer’s Manual)描述了TCS中的前几个字段。这些字段被认为属于结构的体系结构部分,因此在所有支持SGX的处理器上具有相同的语义。TCS的其余部分没有详细文档说明。
持有TCS的EPC页面的内容不能被直接访问,即使是拥有该TCS的Enclave的代码也无法访问。这种限制类似于对访问持有SECS实例的EPC页面的限制。然而,TCS中的体系结构字段可以通过Enclave调试指令读取。
这种限制是为了确保EPC中存储的敏感信息的安全性。EPC是SGX用于存储Enclave和相关数据结构的保护区域,包括TCS和SECS。为了保护这些敏感信息,SGX限制了对EPC页面的直接访问。
Enclave代码无法直接读取或写入持有TCS的EPC页面的内容。这确保了TCS中的敏感信息的机密性和完整性。Enclave需要通过SGX提供的特定接口和机制来与TCS进行交互,而不是直接访问EPC页面。
TCS中的体系结构字段定义了逻辑处理器在从执行非Enclave代码切换到执行Enclave代码时进行的上下文切换。
当逻辑处理器从执行非Enclave代码切换到执行Enclave代码时,需要进行一系列上下文切换操作,以确保Enclave的执行环境正确被加载和保护。TCS中的体系结构字段描述了这些上下文切换的操作和过程。
OENTRY字段指定了在使用TCS启动执行Enclave代码时将加载到指令指针(RIP)中的值,因此Enclave作者对Enclave的宿主应用程序可用的入口点具有严格控制权。此外,OFSBASGX和OFSBASGX字段指定了加载到FS和GS段寄存器中的基址,这些寄存器通常指向线程本地存储(TLS)。
TCS结构体字段如下所示:
当处理器在执行Enclave内部的代码时遇到硬件异常,例如中断,它会执行特权级别切换并调用系统软件提供的硬件异常处理程序。然而,在执行异常处理程序之前,处理器需要一个安全区域来存储Enclave代码的执行上下文,以确保执行上下文中的信息不会被不可信的系统软件泄露。
这个安全区域就是状态保存区域(State Save Area,SSA)。SSA是一个保护的内存区域,用于存储Enclave代码的执行上下文。当处理器遇到硬件异常时,它会将Enclave代码的执行上下文保存到SSA中,以便在执行异常处理程序之前能够恢复Enclave的执行状态。
在SGX设计中,用于在处理硬件异常时存储Enclave线程的执行上下文的区域称为状态保存区域(State Save Area,SSA),如下图所示。每个TCS引用一系列连续的SSA。SSA数组的偏移量(OSSA)字段指定了Enclave虚拟地址空间中第一个SSA的位置。SSA的数量(NSSA)字段表示可用的SSA数量。
上图显示了保护区域的虚拟地址空间的可能布局。每个保护区域都有一个SECS,每个支持的并发线程有一个TCS。每个TCS指向一个SSA序列,并为RIP以及FS和GS的基地址指定初始值。
每个SSA从一个EPC页面的开头开始,并使用Enclave的SECS中指定的EPC页面数量,这个数量由SSAFRAMESIZE字段指定。这些对齐和大小限制很可能简化了SGX的实现,减少了需要处理的特殊情况的数量。
Enclave线程的执行上下文包括通用寄存器(General-Purpose Registers,GPRs)和XSAVE指令的结果。因此,执行上下文的大小取决于XSAVE使用的请求特征位图(Requested-Feature Bitmap,RFBM)。Enclave中的所有代码使用相同的RFBM,该RFBM在XFRM Enclave属性中声明。每个SSA保留的EPC页面数量(由SSAFRAMESIZE指定)必须足够大,能够容纳由XFRM指定的特征位图的XSAVE输出。
SSAs(State Save Areas)存储在普通的EPC页面中,其EPCM(Enclave Page Cache Map)页面类型为PT REG。因此,SSA的内容对Enclave软件是可访问的。SSA的布局是体系结构级别的,并在SDM(Software Developer’s Manual)中完全记录。
由于SSA的内容对Enclave软件可访问,这为Enclave提供了一种可能性,即在硬件异常发生后,由主机应用程序调用Enclave异常处理程序,并根据SSA中的信息采取相应的操作。
详细信息可以参考Intel v3 文档的第34.7节(SECS)、第34.8节(TCS)和 第34.9节 (SSA) 。
Enclave的代码和数据存储在处理器保留内存(Processor Reserved Memory – PRM)中,它是DRAM的一个子集,其他软件(包括系统软件和SMM代码)无法直接访问这部分内存。CPU的集成内存控制器也会拒绝针对PRM的DMA传输,从而保护它免受其他外设的访问。
PRM是一段连续的内存范围,其边界通过使用基址和掩码寄存器进行配置,其语义与变量内存类型范围相同。因此,PRM的大小必须是2的整数次幂,其起始地址必须与相同的2的幂对齐。由于这些限制,可以在硬件中非常廉价地检查一个地址是否属于PRM。
软件开发者手册(SDM)没有详细描述PRM和PRM范围寄存器(PRMRR)。这些概念在SGX手册和SGX论文中有详细说明。因此,PRM是一项微架构细节,在未来的SGX实现中可能会发生变化。我们对SGX的安全分析依赖于围绕PRM的实现细节,对于SGX未来的实现版本,我们需要重新评估其安全性分析。
SGX利用Enclave Page Cache (EPC)来存储与enclave相关联的页面。它位于BIOS保留的物理内存区域中,是PRM的一个子集。与用于常规内存的页面不同,只有在通过特殊的、受限制的SGX指令构建enclave时,才能从enclave外部访问页面。
enclave的代码(code)和数据(data)保留在EPC的这块特殊内存区域中。这个内存区域通过“Memory Encryption Engine”(MEE)进行加密,MEE是一个专用芯片或处理器中的功能。在内存总线上,外部读取只能观察到加密数据。只有在物理处理器核心内部时,页面才会被解密。密钥在启动时生成,并存储在CPU内部。
保护区域页面缓存(Enclave Page Cache,EPC)是用于存储正在执行的保护区域的页面的安全存储空间。对于一个EPC页面,硬件执行额外的访问控制检查,限制对该页面的访问。在执行当前页面的访问检查和地址转换之后,硬件会检查当前执行的程序是否可以访问EPC页面。通常情况下,只有保护区域的所有者或正在设置EPC页面的指令才能访问EPC页面。
EPC提供了一个受硬件保护的内存区域,用于存储保护区域的代码和数据。这些页面不受普通内存管理机制的影响,因此对于未经授权的程序或操作系统来说是不可见的。硬件会执行额外的访问控制检查,确保只有拥有相应访问权限的程序才能访问EPC页面。
由于EPC页面是受保护的,通常只有保护区域的所有者可以访问和操作这些页面。其他程序或操作系统无法直接读取或写入EPC页面。只有在设置EPC页面的过程中,其他指令可能会访问EPC页面。
比如:当OS这个特权软件访问enclave区域时,硬件会执行额外的访问控制检查,检测到OS没有相应访问权限的程序才能访问EPC页面,限制OS对enclave区域的访问。
EPC(Enclave Page Cache)被划分为多个EPC页面。每个EPC页面的大小为4KB,且始终按4KB边界对齐。
这意味着EPC页面在EPC内存中占据连续的4KB空间,并且始终从4KB的倍数位置开始。对于每个EPC页面,硬件会分配4KB的存储空间,并确保它们之间没有重叠。这种页面对齐和大小的限制是硬件所要求的,以便有效地管理和访问EPC内存。
如下图所示:
SGX的设计支持在一个系统上同时有多个保护区域,这在多过程环境中是必要的。这是通过将EPC分割成4 KB的页面来实现的,它们可以分配给不同的保护区域。EPC使用与体系结构的地址转换特性相同的页面大小。这并不是一个巧合,因为未来的部分将揭示SGX实现与地址转换实现是紧密耦合的。
EPC(Enclave Page Cache)中的页面可以是有效的(valid)或无效的(invalid)。每个有效页面都属于一个保护区域实例。每个保护区域实例都有一个EPC页面,用于保存其SECS(SGX Enclave Control Structure)。每个EPC页面的安全元数据存储在一个名为Enclave Page Cache Map(EPCM)的内部微架构结构中。
EPC(Enclave Page Cache)由特权软件进行管理。Intel SGX提供了一组指令,用于向EPC添加和移除内容。在启动时,BIOS可以配置EPC。在EPC内存是系统DRAM的实现中,EPC的内容受到加密引擎的保护。
特权软件负责管理EPC的分配、回收和访问控制。通过使用指定的SGX指令,特权软件可以将保护区域的代码和数据加载到EPC中,并在不再需要时将其从EPC中移除。这些指令允许特权软件有效地管理EPC内存,并确保保护区域的安全性和隔离性。
在系统启动时,BIOS可以配置EPC的大小和位置。这意味着BIOS可以决定将多少系统内存用作EPC,并将其分配给SGX使用。这样可以为保护区域提供足够的安全内存空间。
只有在enclave内部执行的CPU才能直接访问enclave内存。然而,在enclave内部执行的CPU可以访问enclave外部的普通内存。
内核管理enclave内存的方式类似于其对待设备内存的方式。
访问enclave内存控制检查流程图如下:
对传统的页面检查进行了扩展,以防止外部访问EPC页面。
图片来自于:https://blog.quarkslab.com/overview-of-intel-sgx-part-1-sgx-internals.html
访问一个EPC物理页面的流程如下:
当安全区访问EPC物理页面时有两次权限检查:第一次是MMU,第二次是EPCM。
其他的访问流程图请参考:SGX内存访问控制和Enclave虚拟内存视图
查看EPC物理页面大小范围:
# cat /proc/iomem | grep INT0E0C
80200000-85f7ffff : INT0E0C:00
0x85f7ffff - 0x80200000 = 0x5D7 FFFF = 98,041,855
98,041,855 / (1024 * 1024) = 93
EPC物理页面大小为93M.
每个Enclave都指定了一个在其虚拟地址空间中的区域,称为Enclave线性地址范围(enclave linear address range – ELRANGE),用于映射存储在Enclave的EPC页面中的代码和敏感数据。ELRANGE之外的虚拟地址空间被映射为通过与Enclave的宿主进程相同的虚拟地址访问非EPC内存。如下图所示:
SGX设计确保Enclave在ELRANGE范围内的内存访问遵守虚拟内存抽象,而在ELRANGE之外的内存访问则没有任何保证。因此,Enclave必须将其所有代码和私有数据存储在ELRANGE内,并且必须将ELRANGE之外的内存视为对外界的不可信接口。
ELRANGE是使用Enclave的SECS中的基址(BASEADDR字段)和大小(SIZE)来指定的。ELRANGE必须满足与变量内存类型范围和PRM范围相同的约束条件,即大小必须是2的幂,并且基址必须与大小对齐。这些限制是为了使SGX实现能够以廉价的方式检查一个地址是否属于Enclave的ELRANGE,无论是在硬件还是软件中。
当一个Enclave表示一个动态库时,将ELRANGE设置为加载器为该库保留的内存范围是很自然的。从Enclave代码中访问非Enclave内存的能力使得可以轻松重用现有的库代码,这些代码期望与由宿主进程中的代码管理的内存缓冲区指针一起工作。
非Enclave软件无法访问PRM内存。在PRM内存范围内解析的内存访问会导致事务中止,这在架构级别上是未定义的。在当前的处理器上,中止的写操作会被忽略,中止的读操作则返回一个所有位都设置为1的值。这在上述场景中发挥作用,其中一个Enclave作为动态加载库加载到宿主应用程序进程中。系统软件将Enclave的代码和数据映射到EPC(Enclave Page Cache)页面中的ELRANGE内。如果应用程序软件尝试访问ELRANGE内部的内存,它将遇到中止事务的语义。当前的语义不会导致应用程序崩溃(例如,由于页面错误),但也确保宿主应用程序无法篡改Enclave或读取其私有信息。
页面的类型:SECS页、常规页、TCS页或VA页:
(1)SGX Enclave Control Structure (SECS)
SGX Enclave Control Structure(SECS)定义了enclave的地址范围、属性和其他全局数据。
(2)Regular (REG)
Regular (REG)页面包含enclave的代码和数据。
(3)Thread Control Structure (TCS)
Thread Control Structure (TCS)页面定义了enclave的入口点,并跟踪enclave线程的执行状态。
(4)Version Array (VA)
Version Array (VA)页面包含512个槽位,每个槽位可以存储从EPC中驱逐的页面的版本号。
为了进行安全检查,SGX记录了有关系统软件对每个EPC页面的分配决策的一些信息,并将其存储在Enclave Page Cache Map (EPCM)中。EPCM是一个数组,每个EPC页面对应一个条目,因此计算页面的EPCM条目的地址只需要进行位移操作和加法运算即可。通过对EPCM进行索引,SGX可以追踪和验证Enclave页面的正确性和完整性。这种设计使得SGX能够高效地管理和维护Enclave页面的状态信息,并进行必要的安全检查。
EPCM(Enclave Page Cache Map)是处理器使用的安全结构,用于跟踪EPC(Enclave Page Cache)的内容。EPCM准确地持有每个当前加载到EPC中的页面的一个条目,描述了所属的enclave、访问权限和页面类型等信息。EPCM对软件不可访问,并且EPCM字段的布局是实现特定的。
EPC是Intel SGX(Software Guard Extensions)中的一个关键组件,它是用于存储受保护的隔离区域(enclave)页面的内存区域。EPC在物理内存中保护了这些页面,并提供了保密性和完整性的保护。
为了跟踪EPC中的页面,处理器使用EPCM进行管理。每个加载到EPC的页面在EPCM中都有一个对应的条目。EPCM记录
了页面的状态、访问权限和其他相关信息。通过EPCM,处理器可以有效地管理EPC中的页面,并确保页面的安全性。
EPCM权限与普通页面表分开。这可以防止内核允许对enclave希望保持只读的数据进行写入等等。EPCM权限只能在普通x86页面权限的基础上施加额外的限制。
EPC页面的访问控制信息保存在EPCM结构中,用来判读访问EPC页面(即enclave)时是否有权限。
需要注意的是,EPCM是处理器内部的数据结构,对软件是不可见的。软件无法直接访问或操纵EPCM。EPCM的布局和字段的具体含义是由具体的实现所确定的,因此可能会因处理器型号和实现而有所不同。
在SGX体系结构中,处理器可以随时使所有EPCM条目无效。这要求软件随时准备处理EPCM故障。在实际应用中,这可能发生在诸如电源转换时,当用于加密enclave内存的短暂密钥丢失时。
然而,EPCM包含以下结构信息:
• 相对于有效性和可访问性,EPC页面的状态。
• 页所属的保护区域的SECS标识符(参考Table 34-29)。
• 页面的类型:常规页、SECS页、TCS页或VA页。
• 保护区域被允许通过的线性地址来访问该页面。
• 在该页面上指定的读取/写入/执行权限。
EPCM结构在处理器的地址转换流程中用于对EPC页面进行访问控制。
EPCM结构的描述在表格34-29中,访问控制流程的概念性描述在intel vol3第34.5节中。
EPCM条目由处理器作为各种指令流的一部分进行管理。
在Intel SGX中,可用的保护区域指令被组织为三个指令助记符下的叶子函数:ENCLS(特权级0)、ENCLU(特权级3)和ENCLV(VT根模式)。每个叶子函数使用EAX寄存器来指定叶子函数索引,并可能需要额外的隐式输入寄存器作为参数。ENCLS、ENCLU和ENCLV指令隐式地使用EAX,因此不使用ModR/M字节编码。对于ENCLS、ENCLU和ENCLV指令,不使用ModR/M编码,并且使用额外寄存器的使用由各自的叶子函数索引隐含地表示。
每个叶子函数索引也与一个唯一的叶子函数助记符相关联。Intel SGX指令的长格式表达形式采用ENCLx[LEAF_MNEMONIC]的形式,其中’x’可以是’S’、‘U’或’V’。长格式表达式清晰地表明了给定“叶子助记符”所需的特权级别要求。为简单起见,在本文档中,将仅使用唯一的“Leaf_Mnemonic”名称(省略ENCLx)。
表格提供了Intel SGX初始实现(引入于第6代Intel Core处理器)中可用的指令叶子的摘要。
英特尔SGX1定义了18条新指令:13条由Supervisor使用,5条由User使用。所有这些指令都是在微代码中实现的(以便可以修改它们的行为)。请参阅下面的完整说明列表。
Supervisor and User Mode Enclave Instruction Leaf Functions in Long-Form of SGX1:
Supervisor Instruction | Description | User Instruction | Description |
---|---|---|---|
ENCLS[EADD] | Add an EPC page to an enclave. | ENCLU[EENTER] | Enter an enclave. |
ENCLS[EBLOCK] | Block an EPC page. | ENCLU[EEXIT] | Exit an enclave. |
ENCLS[ECREATE] | Create an enclave. | ENCLU[EGETKEY] | Create a cryptographic key. |
ENCLS[EDBGRD] | Read data from a debug enclave by debugger. | ENCLU[EREPORT] | Create a cryptographic report. |
ENCLS[EDBGWR] | Write data into a debug enclave by debugger. | ENCLU[ERESUME] | Re-enter an enclave. |
ENCLS[EEXTEND] | Extend EPC page measurement. | ||
ENCLS[EINIT] | Initialize an enclave. | ||
ENCLS[ELDB] | Load an EPC page in blocked state. | ||
ENCLS[ELDU] | Load an EPC page in unblocked state. | ||
ENCLS[EPA] | Add an EPC page to create a version array. | ||
ENCLS[EREMOVE] | Remove an EPC page from an enclave. | ||
ENCLS[ETRACK] | Activate EBLOCK checks. | ||
ENCLS[EWB] | Write back/invalidate an EPC page. |
请注意,这些指令的行为可以通过微码进行修改。这使得Intel能够通过微码更新来更新和增强Intel SGX的功能,而无需更改底层硬件。
表格总结了未来Intel处理器的Intel SGX增强功能。
Supervisor and User Mode Enclave Instruction Leaf Functions in Long-Form of SGX2:
Supervisor Instruction | Description | User Instruction | Description |
---|---|---|---|
ENCLS[EAUG] | Allocate EPC page to an existing enclave. | ENCLU[EACCEPT] | Accept EPC page into the enclave. |
ENCLS[EMODPR] | Restrict page permissions. | ENCLU[EMODPE] | Enhance page permissions. |
ENCLS[EMODT] | Modify EPC page type. | ENCLU[EACCEPTCOPY] | Copy contents to an augmented EPC page and accept the EPC page into the enclave. |
如下图所示:
Intel v3 Chapter 33
https://www.intel.com/content/www/us/en/developer/tools/software-guard-extensions/overview.html
https://blog.csdn.net/weixin_42492218/article/details/121318550
https://caslab.csl.yale.edu/workshops/hasp2016/HASP16-16_slides.pdf
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。