SEV Guest API 权威文档

1. 概述

SEV API 是一组 ioctl,供访客或虚拟机管理程序使用,以获取或设置 SEV 虚拟机的特定方面。 ioctl 属于以下几类:

  • 虚拟机管理程序 ioctl:这些查询和设置影响整个 SEV 固件的全局属性。 这些 ioctl 由平台配置工具使用。

  • 访客 ioctl:这些查询和设置 SEV 虚拟机的属性。

2. API 描述

本节介绍用于从 SEV 固件查询 SEV 访客报告的 ioctl。 对于每个 ioctl,都会提供以下信息以及描述:

技术

哪个 SEV 技术提供此 ioctl。 SEV、SEV-ES、SEV-SNP 或全部。

类型

虚拟机管理程序或访客。 ioctl 可以在访客或虚拟机管理程序内部使用。

参数

ioctl 接受哪些参数。

返回值

返回值。 未详细说明常规错误编号(-ENOMEM、-EINVAL),但具有特定含义的错误除外。

访客 ioctl 应在 /dev/sev-guest 设备的文件描述符上发出。 ioctl 接受 struct snp_user_guest_request。 输入和输出结构分别通过 req_data 和 resp_data 字段指定。 如果 ioctl 由于固件错误而执行失败,则将设置 fw_error 代码,否则 fw_error 将设置为 -1。

固件检查消息序列计数器是否比访客的消息序列计数器大 1。 如果访客驱动程序无法递增消息计数器(例如,计数器溢出),则将返回 -EIO。

struct snp_guest_request_ioctl {
        /* Message version number */
        __u32 msg_version;

        /* Request and response structure address */
        __u64 req_data;
        __u64 resp_data;

        /* bits[63:32]: VMM error code, bits[31:0] firmware error code (see psp-sev.h) */
        union {
                __u64 exitinfo2;
                struct {
                        __u32 fw_error;
                        __u32 vmm_error;
                };
        };
};

主机 ioctl 将发送到 /dev/sev 设备的文件描述符。 ioctl 接受下面记录的命令 ID/输入结构。

struct sev_issue_cmd {
        /* Command ID */
        __u32 cmd;

        /* Command request structure */
        __u64 data;

        /* Firmware error code on failure (see psp-sev.h) */
        __u32 error;
};

2.1 SNP_GET_REPORT

技术:

sev-snp

类型:

访客 ioctl

输入参数:

struct snp_report_req

返回值(输出):

成功时为 struct snp_report_resp,错误时为 -negative

SNP_GET_REPORT ioctl 可用于从 SEV-SNP 固件查询证明报告。 ioctl 使用 SEV-SNP 固件提供的 SNP_GUEST_REQUEST (MSG_REPORT_REQ) 命令来查询证明报告。

成功后,snp_report_resp.data 将包含报告。 该报告包含 SEV-SNP 规范中描述的格式。 有关更多详细信息,请参阅 SEV-SNP 规范。

2.2 SNP_GET_DERIVED_KEY

技术:

sev-snp

类型:

访客 ioctl

输入参数:

struct snp_derived_key_req

返回值(输出):

成功时为 struct snp_derived_key_resp,错误时为 -negative

SNP_GET_DERIVED_KEY ioctl 可用于获取从根密钥派生的密钥。 派生的密钥可供访客用于任何目的,例如密封密钥或与外部实体通信。

ioctl 使用 SEV-SNP 固件提供的 SNP_GUEST_REQUEST (MSG_KEY_REQ) 命令来派生密钥。 有关密钥派生请求中传递的各种字段的更多详细信息,请参阅 SEV-SNP 规范。

成功后,snp_derived_key_resp.data 包含派生的密钥值。 有关更多详细信息,请参阅 SEV-SNP 规范。

2.3 SNP_GET_EXT_REPORT

技术:

sev-snp

类型:

访客 ioctl

参数(输入/输出):

struct snp_ext_report_req

返回值(输出):

成功时为 struct snp_report_resp,错误时为 -negative

SNP_GET_EXT_REPORT ioctl 类似于 SNP_GET_REPORT。 区别在于随报告返回的附加证书数据。 返回的证书数据由虚拟机管理程序通过 SNP_SET_EXT_CONFIG 提供。

ioctl 使用 SEV-SNP 固件提供的 SNP_GUEST_REQUEST (MSG_REPORT_REQ) 命令来获取证明报告。

成功后,snp_ext_report_resp.data 将包含证明报告,snp_ext_report_req.certs_address 将包含证书 Blob。 如果 Blob 的长度小于预期,则 snp_ext_report_req.certs_len 将更新为预期值。

有关如何解析证书 Blob 的更多详细信息,请参阅 GHCB 规范。

2.4 SNP_PLATFORM_STATUS

技术:

sev-snp

类型:

虚拟机管理程序 ioctl cmd

参数(输出):

struct sev_user_data_snp_status

返回值(输出):

成功时为 0,错误时为 -negative

SNP_PLATFORM_STATUS 命令用于查询 SNP 平台状态。 该状态包括 API 主要版本、次要版本等。 有关更多详细信息,请参阅 SEV-SNP 规范。

2.5 SNP_COMMIT

技术:

sev-snp

类型:

虚拟机管理程序 ioctl cmd

返回值(输出):

成功时为 0,错误时为 -negative

SNP_COMMIT 用于使用 SEV-SNP 固件 SNP_COMMIT 命令提交当前安装的固件。 这样可以防止回滚到先前提交的固件版本。 这还将更新报告的 TCB 以匹配当前安装的固件的 TCB。

2.6 SNP_SET_CONFIG

技术:

sev-snp

类型:

虚拟机管理程序 ioctl cmd

输入参数:

struct sev_user_data_snp_config

返回值(输出):

成功时为 0,错误时为 -negative

SNP_SET_CONFIG 用于设置系统范围的配置,例如证明报告中报告的 TCB 版本。 该命令类似于 SEV-SNP 规范中定义的 SNP_CONFIG 命令。 受此命令影响的固件参数的当前值可以通过 SNP_PLATFORM_STATUS 查询。

2.7 SNP_VLEK_LOAD

技术:

sev-snp

类型:

虚拟机管理程序 ioctl cmd

输入参数:

struct sev_user_data_snp_vlek_load

返回值(输出):

成功时为 0,错误时为 -negative

在请求证明报告时,访客可以指定是否希望 SNP 固件使用版本化芯片背书密钥 (VCEK)(该密钥是从芯片唯一密钥派生的)或版本化加载背书密钥 (VLEK)(该密钥是从 AMD 密钥派生服务 (KDS) 获取的,并且是从分配给注册云服务提供商的种子派生的)来签署报告。

对于 VLEK 密钥,SNP_VLEK_LOAD SNP 命令用于在从 KDS 获取密钥后将它们加载到系统中,并且与 SEV-SNP 规范中指定的 SNP_VLEK_LOAD 固件命令密切对应。

3. SEV-SNP CPUID 强制执行

SEV-SNP 访客可以访问一个特殊页面,其中包含 PSP 作为 SNP_LAUNCH_UPDATE 固件命令的一部分验证的 CPUID 值表。 它提供以下关于 CPUID 值有效性的保证:

  • 其地址通过引导加载程序/固件(通过 CC Blob)获取,并且这些二进制文件将作为 SEV-SNP 证明报告的一部分进行度量。

  • 其初始状态将被加密/pvalidated,因此在运行时尝试修改它会导致写入垃圾,或者如果虚拟机管理程序尝试交换后备页面,则由于验证状态的更改而生成 #VC 异常。

  • 虚拟机管理程序尝试通过使用普通页面或非 CPUID 加密页面来绕过 PSP 检查将更改 SEV-SNP 证明报告提供的度量。

  • CPUID 页面内容被度量,但在访客初始化过程中尝试修改 CPUID 页面的预期内容将受到在 SNP_LAUNCH_UPDATE 期间对页面执行的 PSP CPUID 强制策略检查的限制,如果访客所有者实现了他们自己对 CPUID 值的检查,则稍后会注意到。

重要的是要注意,只有当内核已注意在启动的所有阶段使用 SEV-SNP CPUID 时,最后一个保证才有用。 否则,访客所有者证明不能保证内核在启动过程中的某个时刻未被馈送不正确的值。

4. SEV 访客驱动程序通信密钥

SEV 访客和 AMD 安全处理器(ASP,又名 PSP)中的 SEV 固件之间的通信受 VM 平台通信密钥 (VMPCK) 保护。 默认情况下,sev-guest 驱动程序使用与访客运行的 VM 特权级别 (VMPL) 关联的 VMPCK。 如果此密钥被 sev-guest 驱动程序擦除(有关 VMPCK 为何被擦除的原因,请参阅驱动程序),则可以通过重新加载 sev-guest 驱动程序并使用 vmpck_id 模块参数指定所需的密钥来使用不同的密钥。

参考

SEV-SNP 和 GHCB 规范:developer.amd.com/sev

该驱动程序基于 SEV-SNP 固件规范 0.9 和 GHCB 规范版本 2.0。