Currently KVM implements a stub version of SNP Extended Guest Requests that always supplies NULL certificate data alongside the attestation report. Make use of the newly-defined KVM_EXIT_COCO_REQ_CERTS event to provide a way for userspace to optionally supply this certificate data. Signed-off-by: Michael Roth <michael.roth@xxxxxxx> --- arch/x86/kvm/svm/sev.c | 44 +++++++++++++++++++++++++++++----- include/uapi/linux/sev-guest.h | 8 +++++++ 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 72674b8825c4..4827a8ed4d16 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -4077,6 +4077,30 @@ static int snp_handle_guest_req(struct vcpu_svm *svm, gpa_t req_gpa, gpa_t resp_ return ret; } +static int snp_complete_req_certs(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + struct vmcb_control_area *control = &svm->vmcb->control; + + if (vcpu->run->coco.ret) { + if (vcpu->run->coco.ret == ENOSPC) { + vcpu->arch.regs[VCPU_REGS_RBX] = vcpu->run->coco.req_certs.npages; + ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, + SNP_GUEST_ERR(SNP_GUEST_VMM_ERR_INVALID_LEN, 0)); + } else if (vcpu->run->coco.ret == EAGAIN) { + ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, + SNP_GUEST_ERR(SNP_GUEST_VMM_ERR_BUSY, 0)); + } else { + ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, + SNP_GUEST_ERR(SNP_GUEST_VMM_ERR_GENERIC, 0)); + } + + return 1; /* resume guest */ + } + + return snp_handle_guest_req(svm, control->exit_info_1, control->exit_info_2); +} + static int snp_handle_ext_guest_req(struct vcpu_svm *svm, gpa_t req_gpa, gpa_t resp_gpa) { struct kvm *kvm = svm->vcpu.kvm; @@ -4092,12 +4116,10 @@ static int snp_handle_ext_guest_req(struct vcpu_svm *svm, gpa_t req_gpa, gpa_t r /* * As per GHCB spec, requests of type MSG_REPORT_REQ also allow for * additional certificate data to be provided alongside the attestation - * report via the guest-provided data pages indicated by RAX/RBX. The - * certificate data is optional and requires additional KVM enablement - * to provide an interface for userspace to provide it, but KVM still - * needs to be able to handle extended guest requests either way. So - * provide a stub implementation that will always return an empty - * certificate table in the guest-provided data pages. + * report via the guest-provided data pages indicated by RAX/RBX. If + * userspace enables KVM_EXIT_COCO_REQ_CERTS, then exit to userspace + * to fetch the certificate data. Otherwise, return an empty certificate + * table in the guest-provided data pages. */ if (msg_type == SNP_MSG_REPORT_REQ) { struct kvm_vcpu *vcpu = &svm->vcpu; @@ -4113,6 +4135,16 @@ static int snp_handle_ext_guest_req(struct vcpu_svm *svm, gpa_t req_gpa, gpa_t r if (!PAGE_ALIGNED(data_gpa)) goto request_invalid; + if ((vcpu->kvm->arch.coco_exit_enabled & BIT_ULL(KVM_EXIT_COCO_REQ_CERTS))) { + vcpu->run->exit_reason = KVM_EXIT_COCO; + vcpu->run->coco.nr = KVM_EXIT_COCO_REQ_CERTS; + vcpu->run->coco.req_certs.gfn = gpa_to_gfn(data_gpa); + vcpu->run->coco.req_certs.npages = data_npages; + vcpu->arch.complete_userspace_io = snp_complete_req_certs; + vcpu->run->coco.ret = 0; + return 0; /* fetch certs from userspace */ + } + /* * As per GHCB spec (see "SNP Extended Guest Request"), the * certificate table is terminated by 24-bytes of zeroes. diff --git a/include/uapi/linux/sev-guest.h b/include/uapi/linux/sev-guest.h index fcdfea767fca..4c4ed8bc71d7 100644 --- a/include/uapi/linux/sev-guest.h +++ b/include/uapi/linux/sev-guest.h @@ -95,5 +95,13 @@ struct snp_ext_report_req { #define SNP_GUEST_VMM_ERR_INVALID_LEN 1 #define SNP_GUEST_VMM_ERR_BUSY 2 +/* + * The GHCB spec essentially states that all non-zero error codes other than + * those explicitly defined above should be treated as an error by the guest. + * Define a generic error to cover that case, and choose a value that is not + * likely to overlap with new explicit error codes should more be added to + * the GHCB spec later. + */ +#define SNP_GUEST_VMM_ERR_GENERIC ((u32)~0U) #endif /* __UAPI_LINUX_SEV_GUEST_H_ */ -- 2.25.1