Add support for retrieving the SEV-SNP attestation report via the SNP_HV_REPORT_REQ firmware command and expose it through a new KVM ioctl for SNP guests. Signed-off-by: Thomas Courrege --- .../virt/kvm/x86/amd-memory-encryption.rst | 25 ++++++++ arch/x86/include/uapi/asm/kvm.h | 7 +++ arch/x86/kvm/svm/sev.c | 61 +++++++++++++++++++ drivers/crypto/ccp/sev-dev.c | 1 + include/linux/psp-sev.h | 31 ++++++++++ 5 files changed, 125 insertions(+) diff --git a/Documentation/virt/kvm/x86/amd-memory-encryption.rst b/Documentation/virt/kvm/x86/amd-memory-encryption.rst index 1ddb6a86ce7f..b3ee25718938 100644 --- a/Documentation/virt/kvm/x86/amd-memory-encryption.rst +++ b/Documentation/virt/kvm/x86/amd-memory-encryption.rst @@ -572,6 +572,31 @@ Returns: 0 on success, -negative on error See SNP_LAUNCH_FINISH in the SEV-SNP specification [snp-fw-abi]_ for further details on the input parameters in ``struct kvm_sev_snp_launch_finish``. +21. KVM_SEV_SNP_HV_REPORT_REQ +----------------------------- + +The KVM_SEV_SNP_HV_REPORT_REQ command requests the hypervisor-generated +SNP attestation report. This report is produced by the PSP using the +HV-SIGNED key selected by the caller. + +The ``key_sel`` field indicates which key the platform will use to sign the +report: + * ``0``: If VLEK is installed, sign with VLEK. Otherwise, sign with VCEK. + * ``1``: Sign with VCEK. + * ``2``: Sign with VLEK. + * Other values are reserved. + +Parameters (in): struct kvm_sev_snp_hv_report_req + +Returns: 0 on success, -negative on error + +:: + struct kvm_sev_snp_hv_report_req { + __u8 key_sel; + __u64 report_uaddr; + __u64 report_len; + }; + Device attribute API ==================== diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index d420c9c066d4..ff034668cac4 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -742,6 +742,7 @@ enum sev_cmd_id { KVM_SEV_SNP_LAUNCH_START = 100, KVM_SEV_SNP_LAUNCH_UPDATE, KVM_SEV_SNP_LAUNCH_FINISH, + KVM_SEV_SNP_HV_REPORT_REQ, KVM_SEV_NR_MAX, }; @@ -870,6 +871,12 @@ struct kvm_sev_receive_update_data { __u32 pad2; }; +struct kvm_sev_snp_hv_report_req { + __u8 key_sel; + __u64 report_uaddr; + __u64 report_len; +}; + struct kvm_sev_snp_launch_start { __u64 policy; __u8 gosvw[16]; diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 0835c664fbfd..62f17f4eab42 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -2253,6 +2253,64 @@ static int snp_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp) return rc; } +static int sev_snp_hv_report_request(struct kvm *kvm, struct kvm_sev_cmd *argp) +{ + struct sev_data_snp_msg_report_rsp *report_rsp = NULL; + struct sev_data_snp_hv_report_req data; + struct kvm_sev_snp_hv_report_req params; + struct kvm_sev_info *sev = to_kvm_sev_info(kvm); + void __user *u_report; + void __user *u_params = u64_to_user_ptr(argp->data); + int ret; + + if (!sev_snp_guest(kvm)) + return -ENOTTY; + + if (copy_from_user(¶ms, u_params, sizeof(params))) + return -EFAULT; + + if (params.report_len < SEV_SNP_ATTESTATION_REPORT_SIZE) + return -ENOSPC; + + memset(&data, 0, sizeof(data)); + + u_report = u64_to_user_ptr(params.report_uaddr); + if (!u_report) + return -EINVAL; + + report_rsp = snp_alloc_firmware_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO); + if (!report_rsp) + return -ENOMEM; + + data.len = sizeof(data); + data.hv_report_paddr = __psp_pa(report_rsp); + data.key_sel = params.key_sel; + + data.gctx_addr = __psp_pa(sev->snp_context); + ret = sev_issue_cmd(kvm, SEV_CMD_SNP_HV_REPORT_REQ, &data, + &argp->error); + + if (ret) + goto e_free_rsp; + + params.report_len = report_rsp->report_size; + if (copy_to_user(u_params, ¶ms, sizeof(params))) + ret = -EFAULT; + + if (params.report_len < report_rsp->report_size) { + ret = -ENOSPC; + } else if (copy_to_user(u_report, report_rsp + 1, report_rsp->report_size)) { + /* report is located right after rsp */ + ret = -EFAULT; + } + +e_free_rsp: + /* contains sensitive data */ + memzero_explicit(report_rsp, PAGE_SIZE); + snp_free_firmware_page(report_rsp); + return ret; +} + struct sev_gmem_populate_args { __u8 type; int sev_fd; @@ -2664,6 +2722,9 @@ int sev_mem_enc_ioctl(struct kvm *kvm, void __user *argp) case KVM_SEV_SNP_LAUNCH_FINISH: r = snp_launch_finish(kvm, &sev_cmd); break; + case KVM_SEV_SNP_HV_REPORT_REQ: + r = sev_snp_hv_report_request(kvm, &sev_cmd); + break; default: r = -EINVAL; goto out; diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 0d13d47c164b..5236d5ee19ac 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -251,6 +251,7 @@ static int sev_cmd_buffer_len(int cmd) case SEV_CMD_SNP_COMMIT: return sizeof(struct sev_data_snp_commit); case SEV_CMD_SNP_FEATURE_INFO: return sizeof(struct sev_data_snp_feature_info); case SEV_CMD_SNP_VLEK_LOAD: return sizeof(struct sev_user_data_snp_vlek_load); + case SEV_CMD_SNP_HV_REPORT_REQ: return sizeof(struct sev_data_snp_hv_report_req); default: return 0; } diff --git a/include/linux/psp-sev.h b/include/linux/psp-sev.h index e0dbcb4b4fd9..0e635feb7671 100644 --- a/include/linux/psp-sev.h +++ b/include/linux/psp-sev.h @@ -91,6 +91,7 @@ enum sev_cmd { SEV_CMD_SNP_GCTX_CREATE = 0x093, SEV_CMD_SNP_GUEST_REQUEST = 0x094, SEV_CMD_SNP_ACTIVATE_EX = 0x095, + SEV_CMD_SNP_HV_REPORT_REQ = 0x096, SEV_CMD_SNP_LAUNCH_START = 0x0A0, SEV_CMD_SNP_LAUNCH_UPDATE = 0x0A1, SEV_CMD_SNP_LAUNCH_FINISH = 0x0A2, @@ -554,6 +555,36 @@ struct sev_data_attestation_report { u32 len; /* In/Out */ } __packed; +/** + * struct sev_data_snp_hv_report_req - SNP_HV_REPORT_REQ command params + * + * @len: length of the command buffer in bytes + * @key_sel: Selects which key to use for generating the signature. + * @gctx_addr: System physical address of guest context page + * @hv_report_paddr: System physical address where MSG_EXPORT_RSP will be written + */ +struct sev_data_snp_hv_report_req { + u32 len; /* In */ + u32 key_sel:2; /* In */ + u32 rsvd:30; + u64 gctx_addr; /* In */ + u64 hv_report_paddr; /* In */ +} __packed; + +#define SEV_SNP_ATTESTATION_REPORT_SIZE 1184 + +/** + * struct sev_data_snp_msg_export_rsp + * + * @status: Status : 0h: Success. 16h: Invalid parameters. + * @report_size: Size in bytes of the attestation report + */ +struct sev_data_snp_msg_report_rsp { + u32 status; /* Out */ + u32 report_size; /* Out */ + u8 rsvd[24]; +} __packed; + /** * struct sev_data_snp_download_firmware - SNP_DOWNLOAD_FIRMWARE command params * -- 2.52.0