准确检测应用中的英特尔® Software Guard 扩展

英特尔® Software Guard 扩展(英特尔® SGX)SDK 可提供三个函数,用于检测和启用系统对英特尔 SGX 的支持。 CPUID 指令还提供用于检测 CPU 是否支持英特尔 SGX 的界面。 软件开发人员面临的关键问题是:如何正确检测系统是否支持英特尔 SGX,以便应用和安装程序进行相应的操作。

这一问题表面上看似简单。 如果处理器支持英特尔 SGX,应用将能够安全创建安全区,保护系统中其他软件的机密。 如果处理器不支持英特尔 SGX,开发人员可选择停止应用中的函数(并向用户显示错误),或返回至非英特尔 SGX 代码路径。

听着简单,但实际上非常复杂。 要了解个中缘由,首先需要了解有关 CPU 支持英特尔 SGX 的背景知识、如何管理,以及如何报告给应用。

英特尔® Software Guard 扩展平台支持

尽管个别 CPU 可能支持英特尔 SGX,但英特尔 SGX 是否可用取决于两个组件:

  • BIOS
  • 英特尔 SGX 平台软件包

下面我们详细介绍这两方面。

BIOS 支持

在系统中启用SGX 并配置 SGX 特性需具备 BIOS 支持。

系统所有者必须选择通过 BIOS 启用英特尔 SGX。 这要求 OEM 提供 BIOS 明确支持英特尔 SGX。 不同 OEM 提供的 BIOS 支持各不相同,而且即使是同一家 OEM,其不同产品线提供的 BIOS 支持也不尽相同。

共有三种 BIOS 设置。

设置

含义

Enabled(启用)

英特尔 SGX 已启用,可用于各应用程序。

Software Controlled(软件控制)

英特尔 SGX 可通过软件应用启用,只有这样才能投入使用(称为“软件选择”)。 通过软件选择启用英特尔 SGX 要求系统重启。

Disabled(禁用)

英特尔 SGX 已明确禁用,无法通过软件应用启用。 该设置只能在 BIOS 设置屏幕中更改。

注: 根据 BIOS 的不同,可能仅包含启用和禁用两个选项。 请咨询您的设备制造商。

如果 BIOS 中英特尔 SGX 设置为 Enabled,英特尔 SGX 将处于启用状态,英特尔 SGX 指令和资源可供应用程序使用。

如果英特尔 SGX 设置为 Software Controlled,英特尔 SGX 最初处于禁用状态,需通过软件应用在 SDK 中进行以下几次调用,才能将其设为启用状态:

  • sgx_enable_device()
  • sgx_cap_enable_device()

这些函数执行软件选择,下文将详细介绍。 英特尔建议 OEM 和 ODM 提供 Software Controlled 模式并将其设为默认设置。

如果英特尔 SGX 设置为 Disabled,英特尔 SGX 将处于禁用状态,无法通过软件启用。 如需启用英特尔 SGX,最终用户必须:

  • 在 BIOS 中将其重新设置为 Enabled 状态,

  • 在 BIOS 中设置为 Software Controlled 状态(此时英特尔 SGX 仍处于禁用状态,可以通过软件应用设置为启用状态)。

Software Controlled 状态有何意义?

英特尔 SGX 保留高达 128 MB 系统 RAM 作为处理器保留内存 (PRM),可用于容纳安全区页面缓存 (EPC)。 尽管其实际大小由 BIOS 设置决定,但必须注意的是,启用英特尔 SGX 会消耗一部分系统资源,进而会妨碍其他应用程序的使用。

BIOS 中的 Software Controlled 设置支持 OEM 发运的系统支持处于就绪状态的英特尔 SGX(可通过软件激活(即软件选择))。 这是在默认完全启用英特尔 SGX 而且可能消耗系统资源(即使系统上未出现英特尔 SGX 软件)与使其完全关闭之间所作出的权衡。 通过软件激活后,最终用户无需将系统重启至 BIOS 设置屏幕并通过该界面手动启用英特尔 SGX(对于非技术用户来说,这可能是一项非常艰巨的任务)。

平台软件包

如要运行英特尔 SGX,系统必须安装英特尔 SGX 平台软件包 (PSW)。 PSW 包括:

  • 运行时库
  • 帮助最终用户支持并维护系统上的可信计算模块的服务
  • 执行并管理关键英特尔 SGX 操作(比如验证)的服务
  • 平台服务(比如 trusted time 和 monotonic counter)界面

软件厂商以应用安装流程的一部分安装 PSW。 软件厂商的应用安装程序决定检测平台是否支持英特尔 SGX,如果支持,运行 PSW 安装程序。

如果系统安装了平台软件,PSW 安装包将升级现有安装(如果现有安装已经过时),或退出(不进行下一步操作)。

Windows* 平台

Windows* 平台的系统目录中安装了两种库:

  • sgx_uae_service.dll
  • sgx_urts.dll

应用必须以这种顺序加载 DLL,并确保能够从系统目录中加载。 调用 LoadLibrary() 之前,建议应用调用 GetSystemDirectory() 以获取系统目录路径,并调用 SetDllDirectory() 设置前往该目录的 DLL 搜索路径。 如果不限制前往系统目录的加载路径,会导致应用容易受到 DLL 预加载攻击。

Linux* 平台

Linux SDK 发布后,本文将立即更新有关 Linux 流程的信息。

CPUID 如何?

CPUID 指令不足以检测平台上英特尔 SGX 的可用性。 它仅报告处理器是否支持英特尔 SGX 指令;英特尔 SGX 的可用性取决于 BIOS 设置和 PSW。 如果应用仅根据 CPUID 枚举来做出决策,可能会在运行时产生 #GP 或 #UD 故障。

另外,VMM(比如 Hyper-V*)会屏蔽 CPUID 结果,因此即使 CPUID 结果报告未设置英特尔 SGX 特性标签,系统也可能支持英特尔 SGX。

英特尔® Software Guard 扩展特性检测流程

开发应用时,英特尔 SGX 检测必须出现在处于运行时的应用和应用安装程序中。 它们有各自的流程。

英特尔® Software Guard 扩展检测: 安装程序

所有英特尔 SGX 应用都要求安装 PSW。 如果系统不支持英特尔 SGX,安装 PSW 将毫无意义。 尝试安装 PSW 之前,应用安装程序必须检查本地系统以确认英特尔 SGX 功能,而且必须

Figure 1. Intel SGX feature detection flowchart for installers.
图 1.适用于安装程序的英特尔 SGX 特性检测。


完成软件选择,以启用英特尔 SGX。 建议实施如图 1 所示的流程。

  1. 调用 sgx_is_capable()。 如果系统支持英特尔 SGX,进入第 2 步。 如果不支持,则不要安装 PSW,也不要尝试软件选择。应用厂商会决定下一步骤,但通常的选项包括:
    • 安装应用(如果支持英特尔 SGX 和非英特尔 SGX 代码路径)。
    • 安装非英特尔 SGX 版应用(如果以单独二进制文件分发)。
    • 完全中止安装(如果要求英特尔 SGX 支持)并告知用户软件不兼容该设备配置。
  2. 运行 PSW 安装程序。 如果安装成功,进入第 3 步。 否则中止安装。
  3. 调用 sgx_cap_enable_device() 以启用英特尔 SGX,然后查看返回结果。
    • 如果结果为英特尔 SGX 已启用,则无需进行下一步。
    • 如果成功启用英特尔 SGX 但需要重启系统,则提示用户需要重启才能运行新安装的应用。
    • 如果成功启用英特尔 SGX 但不需要重启系统,则无需进行下一步。
    • 如果启用英特尔 SGX 失败,则向用户显示错误。

注意,两个函数 sgx_is_capable()sgx_cap_enabled_device() 均需要管理员权限。 应用安装程序通常要求这一级别的许可,因此英特尔 SGX 应用安装程序触发 Windows 中的 UAC 提示窗口不在少数。

因为包含这些函数的安装程序可能在 PSW 安装之前运行,所以它们在用于绑定安装程序的独立 DLL 中提供。

禁用与不支持

无法区分以下三种情况:

  1. CPU 不支持英特尔 SGX
  2. BIOS 不支持英特尔 SGX
  3. BIOS 和 CPU 支持英特尔 SGX,但 BIOS 明确禁用英特尔 SGX

但安装程序的流程应保持不变。 在这三种情况下,sgx_is_capable() 将返回零,表示该平台不支持英特尔 SGX。

英特尔® Software Guard 扩展检测: 应用

检测处于运行时的应用中的英特尔 SGX 不同于检测应用安装程序中的英特尔 SGX。 如果安装了应用,可能会出现以下某种场景:

  1. 安装程序未检测系统是否支持英特尔 SGX,因此没有安装英特尔 SGX 平台软件。
  2. 安装程序检测了系统是否支持英特尔 SGX,因此安装英特尔 SGX 平台软件。 英特尔 SGX 的状态也将变成:
    • Enabled(通过 BIOS 明确启用,或安装程序中的软件选择)。
    • Enabled(在软件选择期间),表示执行英特尔 SGX 指令之前用户需要重启系统。
    • Disabled,表示应用安装后用户会在某个点明确禁用英特尔 SGX。

但是无论处于哪种情况,应用都需要遵循正确的流程,如图 2 所示。

SGX detection procedure for applications
图 2.适用于应用的英特尔 SGX 特性检测流程。

  1. 查看 PSW 是否已安装。 如果已经安装,则进入第 2 步。 如果没有,英特尔 SGX 则无法用于该平台,后续步骤取决于应用中的代码路径。
    • 如果应用支持非英特尔 SGX 代码分支,应执行非英特尔 SGX 代码。
    • 如果应用仅支持英特尔 SGX,则必须退出。
  2. 调用 gx_enable_device() 以确保已进行软件选择并查看返回值。
    • 如果结果是英特尔 SGX 已启用,应用则可以执行英特尔 SGX 代码路径。
    • 如果无法启用英特尔 SGX,应用应返回至非英特尔 SGX 代码路径(如有)或退出(如果没有)。
    • 如果结果显示需要进行重启或其他手动步骤,比如 BIOS 更改,那么应用应通知用户采取哪些步骤。 如果需要的话,应用可以继续执行非英特尔 SGX 代码路径。

动态加载和动态链接

在单个二进制文件中包含英特尔 SGX 和非英特尔 SGX 代码路径的应用必须动态加载英特尔 SGX 库。 动态链接不是一个选项,因为缺乏英特尔 SGX 支持的系统不包含 PSW 软件包以及必要的运行时库。 在没有 PSW 软件包的情况下尝试在系统上运行动态链接的可执行文件会导致出现无可解决的符号错误,使应用无法启动。

请注意,检查上述 PSW 软件是否为动态加载必要的共享库。 该应用只需简单开放这些句柄。

函数

启用流程充分使用了英特尔 SGX SDK 的三个函数:

  • sgx_is_capable()
  • sgx_cap_enable_device()
  • sgx_enable_device()

下面将介绍这些函数。 更多信息请阅读英特尔 Software Guard 扩展 SDK 中的函数参考。

sgx_status_t sgx_is_capable (int *sgx_capable)

该函数确定系统是否能够在当前运行环境下执行英特尔 SGX 指令。 返回值的类型为 sgx_status_t,表示查询成功与否。

返回值

如果返回 SGX_SUCCESS,说明系统成功查询到英特尔 SGX 支持,结果保存在 sgx_capable 中。 返回 SGX_ERROR_NO_PRIVILEGE 表示安装程序运行时没有管理员权限。

其他返回值表示无法确定系统是否支持英特尔 SGX。 在这种情况下,应用安装程序应保守一些,假定系统支持英特尔 SGX。

输出参数

返回值 SGX_SUCCESS 并不表示系统支持英特尔 SGX,只能明确回答该问题。 为确定系统是否支持英特尔 SGX,必须检查 sgx_capable 变量的值:1 表示“支持”,0 表示“不支持”。

备注

因为该函数要求管理员权限才能访问 EFI 变量,所以该函数只能用于应用安装程序。 如果函数报告系统支持英特尔 SGX,安装程序应继续安装 PSW 软件包。 PSW 必须与支持英特尔 SGX 的应用安装程序绑定。

由于管理员要求,将禁止通过应用程序调用该函数。

Windows 应用安装程序必须在安装软件包中包含 DLL sgx_capable.dll

sgx_status_t sgx_cap_enable_device (sgx_device_status_t *sgx_device_status)

该函数尝试针对英特尔 SGX 的软件选择,并在 sgx_device_status 中设置 SGX 的最终状态。 返回值的类型为 sgx_status_t,说明系统是否尝试软件选择。返回值不表示英特尔 SGX 设备是否成功启用。 只有在尝试了软件选择的情况下,才会将相关信息保存在 sgx_device_status 中。

该函数要求管理员权限,因为它必须访问通过 BIOS 处于可用状态的软件控制界面。 它由应用安装程序调用,并在 PSW 安装后开始执行,以启用英特尔 SGX。

返回值

如果函数返回 SGX_SUCCESS,说明已尝试软件选择,尝试成功与否保存在 sgx_device_status 中。

如果返回值为 SGX_ERROR_NO_PRIVILEGE,说明安装程序运行时没有管理员权限。

其他返回值表示该系统或者在当前环境下没有尝试软件选择。 在这种情况下,应用安装程序应保守一些,假定英特尔 SGX 无法通过该系统的软件选择启用。

输出参数

返回值 SGX_SUCCESS 并不表示已成功启用英特尔 SGX,仅表示已尝试软件选择。 接下来必须查看保存在 sgx_device_status 中的值。

SGX_ENABLED 表示英特尔 SGX 已启用。

SGX_DISABLED_REBOOT_REQUIRED 表示软件选择成功,但需要重启系统才能完全启用英特尔 SGX。 运行时尝试检测英特尔 SGX 可用性的应用将被告知只有重启才能使用英特尔 SGX。

其他值表示软件选择失败,用户必须通过 BIOS 设置屏幕手动启用英特尔 SGX。

备注

因为该函数要求管理员权限,所以应用禁止运行该函数。

Windows 应用安装程序必须在安装软件包中包含 DLL sgx_capable.dll

sgx_status_t sgx_enable_device (sgx_device_status_t *sgx_device_status)

该函数与 sgx_cap_enable_device() 类似,但它主要由应用(而非安装程序)运行。

它不要求管理员权限;它与在本地设备中运行的 AE Service 通信,询问该服务是否尝试软件选择。注意该行为会产生 PSW 依赖性:必须在系统上安装。

如果确认系统中显示了 PSW 库,应用将运行 sgx_enable_device(),以确认英特尔 SGX 是否可用。 返回值和英特尔 SGX 设备状态与 sgx_cap_enable_device()几乎完全相同。

由于必须安装 PSW 才能运行该函数,因此安装程序禁止调用该函数。

Windows* 代码示例

提供的两个代码示例以 stub 的形式实施这些流程:一个适用于应用安装程序,一个适用于运行时的应用。 负责检查的函数 is_sgx_supported() 包装在 Windows* 控制台可执行文件中,便于测试和使用。

该函数的原型如下:

int is_sgx_supported(UINT *sgx_support);

如果成功确定系统的英特尔 SGX 支持状态,将返回 1,如果由于错误而无法确定,将返回 0。

英特尔 SGX 支持状态保存在变量 sgx_support 中,以指示器的形式传递至该函数。 它由以下位组成:

#define ST_SGX_UNSUPPORTED            0x0
#define ST_SGX_CAPABLE                0x1
#define ST_SGX_ENABLED                0x2
#define ST_SGX_REBOOT_REQUIRED        0x4
#define ST_SGX_BIOS_ENABLE_REQUIRED   0x8

只有设置 ST_SGX_ENABLED 位,系统才能执行英特尔 SGX 指令。 其他位仅传达关于英特尔 SGX 支持状态的其他信息(如有),以及启用英特尔 SGX 所需的后续步骤。

总结

运行时期间,回答系统是否已启用英特尔 SGX 并非易事。 这取决于 BIOS、PSW 和最终用户的操作,即系统可能支持英特尔 SGX,但英特尔 SGX 无法处于完全启用或就绪状态。 应用必须准确识别英特尔 SGX 支持状态,才能确保执行正确的代码路径,并避免出现误报漏报现象。 我们建议实施上述两种流程:一种适用于应用安装程序,一种适用于应用。

下载 Windows* 代码示例 

有关编译器优化的更完整信息,请参阅优化通知