Skip to content

Commit fa9893f

Browse files
mdrothsean-jc
authored andcommitted
KVM: Introduce KVM_EXIT_SNP_REQ_CERTS for SNP certificate-fetching
For SEV-SNP, the host can optionally provide a certificate table to the guest when it issues an attestation request to firmware (see GHCB 2.0 specification regarding "SNP Extended Guest Requests"). This certificate table can then be used to verify the endorsement key used by firmware to sign the attestation report. While it is possible for guests to obtain the certificates through other means, handling it via the host provides more flexibility in being able to keep the certificate data in sync with the endorsement key throughout host-side operations that might resulting in the endorsement key changing. In the case of KVM, userspace will be responsible for fetching the certificate table and keeping it in sync with any modifications to the endorsement key by other userspace management tools. Define a new KVM_EXIT_SNP_REQ_CERTS event where userspace is provided with the GPA of the buffer the guest has provided as part of the attestation request so that userspace can write the certificate data into it while relying on filesystem-based locking to keep the certificates up-to-date relative to the endorsement keys installed/utilized by firmware at the time the certificates are fetched. [Melody: Update the documentation scheme about how file locking is expected to happen.] Reviewed-by: Liam Merwick <liam.merwick@oracle.com> Tested-by: Liam Merwick <liam.merwick@oracle.com> Tested-by: Dionna Glaze <dionnaglaze@google.com> Signed-off-by: Michael Roth <michael.roth@amd.com> Signed-off-by: Melody Wang <huibo.wang@amd.com> Signed-off-by: Michael Roth <michael.roth@amd.com> Link: https://patch.msgid.link/20260109231732.1160759-2-michael.roth@amd.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 55780d8 commit fa9893f

4 files changed

Lines changed: 110 additions & 6 deletions

File tree

Documentation/virt/kvm/api.rst

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7353,6 +7353,50 @@ Please note that the kernel is allowed to use the kvm_run structure as the
73537353
primary storage for certain register types. Therefore, the kernel may use the
73547354
values in kvm_run even if the corresponding bit in kvm_dirty_regs is not set.
73557355

7356+
::
7357+
7358+
/* KVM_EXIT_SNP_REQ_CERTS */
7359+
struct kvm_exit_snp_req_certs {
7360+
__u64 gpa;
7361+
__u64 npages;
7362+
__u64 ret;
7363+
};
7364+
7365+
KVM_EXIT_SNP_REQ_CERTS indicates an SEV-SNP guest with certificate-fetching
7366+
enabled (see KVM_SEV_SNP_ENABLE_REQ_CERTS) has generated an Extended Guest
7367+
Request NAE #VMGEXIT (SNP_GUEST_REQUEST) with message type MSG_REPORT_REQ,
7368+
i.e. has requested an attestation report from firmware, and would like the
7369+
certificate data corresponding to the attestation report signature to be
7370+
provided by the hypervisor as part of the request.
7371+
7372+
To allow for userspace to provide the certificate, the 'gpa' and 'npages'
7373+
are forwarded verbatim from the guest request (the RAX and RBX GHCB fields
7374+
respectively). 'ret' is not an "output" from KVM, and is always '0' on
7375+
exit. KVM verifies the 'gpa' is 4KiB aligned prior to exiting to userspace,
7376+
but otherwise the information from the guest isn't validated.
7377+
7378+
Upon the next KVM_RUN, e.g. after userspace has serviced the request (or not),
7379+
KVM will complete the #VMGEXIT, using the 'ret' field to determine whether to
7380+
signal success or failure to the guest, and on failure, what reason code will
7381+
be communicated via SW_EXITINFO2. If 'ret' is set to an unsupported value (see
7382+
the table below), KVM_RUN will fail with -EINVAL. For a 'ret' of 'ENOSPC', KVM
7383+
also consumes the 'npages' field, i.e. userspace can use the field to inform
7384+
the guest of the number of pages needed to hold all the certificate data.
7385+
7386+
The supported 'ret' values and their respective SW_EXITINFO2 encodings:
7387+
7388+
====== =============================================================
7389+
0 0x0, i.e. success. KVM will emit an SNP_GUEST_REQUEST command
7390+
to SNP firmware.
7391+
ENOSPC 0x0000000100000000, i.e. not enough guest pages to hold the
7392+
certificate table and certificate data. KVM will also set the
7393+
RBX field in the GHBC to 'npages'.
7394+
EAGAIN 0x0000000200000000, i.e. the host is busy and the guest should
7395+
retry the request.
7396+
EIO 0xffffffff00000000, for all other errors (this return code is
7397+
a KVM-defined hypervisor value, as allowed by the GHCB)
7398+
====== =============================================================
7399+
73567400

73577401
.. _cap_enable:
73587402

arch/x86/kvm/svm/sev.c

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,16 @@
4141

4242
#define GHCB_HV_FT_SUPPORTED (GHCB_HV_FT_SNP | GHCB_HV_FT_SNP_AP_CREATION)
4343

44+
/*
45+
* The GHCB spec essentially states that all non-zero error codes other than
46+
* those explicitly defined above should be treated as an error by the guest.
47+
* Define a generic error to cover that case, and choose a value that is not
48+
* likely to overlap with new explicit error codes should more be added to
49+
* the GHCB spec later. KVM will use this to report generic errors when
50+
* handling SNP guest requests.
51+
*/
52+
#define SNP_GUEST_VMM_ERR_GENERIC (~0U)
53+
4454
/* enable/disable SEV support */
4555
static bool sev_enabled = true;
4656
module_param_named(sev, sev_enabled, bool, 0444);
@@ -4139,6 +4149,36 @@ static int snp_handle_guest_req(struct vcpu_svm *svm, gpa_t req_gpa, gpa_t resp_
41394149
return ret;
41404150
}
41414151

4152+
static int snp_req_certs_err(struct vcpu_svm *svm, u32 vmm_error)
4153+
{
4154+
ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, SNP_GUEST_ERR(vmm_error, 0));
4155+
4156+
return 1; /* resume guest */
4157+
}
4158+
4159+
static int snp_complete_req_certs(struct kvm_vcpu *vcpu)
4160+
{
4161+
struct vcpu_svm *svm = to_svm(vcpu);
4162+
struct vmcb_control_area *control = &svm->vmcb->control;
4163+
4164+
switch (READ_ONCE(vcpu->run->snp_req_certs.ret)) {
4165+
case 0:
4166+
return snp_handle_guest_req(svm, control->exit_info_1,
4167+
control->exit_info_2);
4168+
case ENOSPC:
4169+
vcpu->arch.regs[VCPU_REGS_RBX] = vcpu->run->snp_req_certs.npages;
4170+
return snp_req_certs_err(svm, SNP_GUEST_VMM_ERR_INVALID_LEN);
4171+
case EAGAIN:
4172+
return snp_req_certs_err(svm, SNP_GUEST_VMM_ERR_BUSY);
4173+
case EIO:
4174+
return snp_req_certs_err(svm, SNP_GUEST_VMM_ERR_GENERIC);
4175+
default:
4176+
break;
4177+
}
4178+
4179+
return -EINVAL;
4180+
}
4181+
41424182
static int snp_handle_ext_guest_req(struct vcpu_svm *svm, gpa_t req_gpa, gpa_t resp_gpa)
41434183
{
41444184
struct kvm *kvm = svm->vcpu.kvm;
@@ -4154,14 +4194,15 @@ static int snp_handle_ext_guest_req(struct vcpu_svm *svm, gpa_t req_gpa, gpa_t r
41544194
/*
41554195
* As per GHCB spec, requests of type MSG_REPORT_REQ also allow for
41564196
* additional certificate data to be provided alongside the attestation
4157-
* report via the guest-provided data pages indicated by RAX/RBX. The
4158-
* certificate data is optional and requires additional KVM enablement
4159-
* to provide an interface for userspace to provide it, but KVM still
4160-
* needs to be able to handle extended guest requests either way. So
4161-
* provide a stub implementation that will always return an empty
4162-
* certificate table in the guest-provided data pages.
4197+
* report via the guest-provided data pages indicated by RAX/RBX. If
4198+
* userspace enables KVM_EXIT_SNP_REQ_CERTS, then exit to userspace
4199+
* to give userspace an opportunity to provide the certificate data
4200+
* before issuing/completing the attestation request. Otherwise, return
4201+
* an empty certificate table in the guest-provided data pages and
4202+
* handle the attestation request immediately.
41634203
*/
41644204
if (msg_type == SNP_MSG_REPORT_REQ) {
4205+
struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
41654206
struct kvm_vcpu *vcpu = &svm->vcpu;
41664207
u64 data_npages;
41674208
gpa_t data_gpa;
@@ -4175,6 +4216,15 @@ static int snp_handle_ext_guest_req(struct vcpu_svm *svm, gpa_t req_gpa, gpa_t r
41754216
if (!PAGE_ALIGNED(data_gpa))
41764217
goto request_invalid;
41774218

4219+
if (sev->snp_certs_enabled) {
4220+
vcpu->run->exit_reason = KVM_EXIT_SNP_REQ_CERTS;
4221+
vcpu->run->snp_req_certs.gpa = data_gpa;
4222+
vcpu->run->snp_req_certs.npages = data_npages;
4223+
vcpu->run->snp_req_certs.ret = 0;
4224+
vcpu->arch.complete_userspace_io = snp_complete_req_certs;
4225+
return 0;
4226+
}
4227+
41784228
/*
41794229
* As per GHCB spec (see "SNP Extended Guest Request"), the
41804230
* certificate table is terminated by 24-bytes of zeroes.

arch/x86/kvm/svm/svm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ struct kvm_sev_info {
115115
void *guest_resp_buf; /* Bounce buffer for SNP Guest Request output */
116116
struct mutex guest_req_mutex; /* Must acquire before using bounce buffers */
117117
cpumask_var_t have_run_cpus; /* CPUs that have done VMRUN for this VM. */
118+
bool snp_certs_enabled; /* SNP certificate-fetching support. */
118119
};
119120

120121
struct kvm_svm {

include/uapi/linux/kvm.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,12 @@ struct kvm_xen_exit {
135135
} u;
136136
};
137137

138+
struct kvm_exit_snp_req_certs {
139+
__u64 gpa;
140+
__u64 npages;
141+
__u64 ret;
142+
};
143+
138144
#define KVM_S390_GET_SKEYS_NONE 1
139145
#define KVM_S390_SKEYS_MAX 1048576
140146

@@ -180,6 +186,7 @@ struct kvm_xen_exit {
180186
#define KVM_EXIT_MEMORY_FAULT 39
181187
#define KVM_EXIT_TDX 40
182188
#define KVM_EXIT_ARM_SEA 41
189+
#define KVM_EXIT_SNP_REQ_CERTS 42
183190

184191
/* For KVM_EXIT_INTERNAL_ERROR */
185192
/* Emulate instruction failed. */
@@ -482,6 +489,8 @@ struct kvm_run {
482489
__u64 gva;
483490
__u64 gpa;
484491
} arm_sea;
492+
/* KVM_EXIT_SNP_REQ_CERTS */
493+
struct kvm_exit_snp_req_certs snp_req_certs;
485494
/* Fix the size of the union. */
486495
char padding[256];
487496
};

0 commit comments

Comments
 (0)