[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v3 36/49] i386/sev: Add KVM_EXIT_VMGEXIT handling for Extended Gu
From: |
Michael Roth |
Subject: |
[PATCH v3 36/49] i386/sev: Add KVM_EXIT_VMGEXIT handling for Extended Guest Requests |
Date: |
Wed, 20 Mar 2024 03:39:32 -0500 |
The GHCB specification[1] defines a VMGEXIT-based Guest Request
hypercall to allow an SNP guest to issue encrypted requests directly to
SNP firmware to do things like query the attestation report for the
guest. These are generally handled purely in the kernel.
In some some cases, it's useful for the host to be able to additionally
supply the certificate chain for the signing key that SNP firmware uses
to sign these attestation reports. To allow for, the GHCB specification
defines an Extended Guest Request where this certificate data can be
provided in a special format described in the GHCB spec. This
certificate data may be global or guest-specific depending on how the
guest was configured. Rather than providing interfaces to manage these
within the kernel, KVM handles this by forward the Extended Guest
Requests on to userspace so the certificate data can be provided in the
expected format.
Add a certs-path parameter to the sev-snp-guest object so that it can
be used to inject any certificate data into these Extended Guest
Requests.
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
qapi/qom.json | 7 +++-
target/i386/sev.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 91 insertions(+), 1 deletion(-)
diff --git a/qapi/qom.json b/qapi/qom.json
index b25a3043da..7ba778af91 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -957,6 +957,10 @@
# SNP_LAUNCH_FINISH command in the SEV-SNP firmware ABI
# (default: all-zero)
#
+# @certs-path: path to certificate data that can be passed to guests via
+# SNP Extended Guest Requests. File should be in the format
+# described in the GHCB specification. (default: none)
+#
# Since: 7.2
##
{ 'struct': 'SevSnpGuestProperties',
@@ -967,7 +971,8 @@
'*id-block': 'str',
'*id-auth': 'str',
'*auth-key-enabled': 'bool',
- '*host-data': 'str' } }
+ '*host-data': 'str',
+ '*certs-path': 'str' } }
##
# @ThreadContextProperties:
diff --git a/target/i386/sev.c b/target/i386/sev.c
index b54422b28e..3b4dbc63b1 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -96,6 +96,7 @@ struct SevSnpGuestState {
char *id_block;
char *id_auth;
char *host_data;
+ char *certs_path;
struct kvm_sev_snp_launch_start kvm_start_conf;
struct kvm_sev_snp_launch_finish kvm_finish_conf;
@@ -1572,6 +1573,63 @@ static int kvm_handle_vmgexit_psc_msr_protocol(__u64
gpa, __u8 op, __u32 *psc_re
return ret;
}
+#define SNP_EXT_REQ_ERROR_INVALID_LEN 1
+#define SNP_EXT_REQ_ERROR_BUSY 2
+#define SNP_EXT_REQ_ERROR_GENERIC (1 << 31)
+
+static int kvm_handle_vmgexit_ext_req(__u64 gpa, __u64 *npages, __u32 *vmm_ret)
+{
+ SevSnpGuestState *sev_snp_guest;
+ MemTxAttrs attrs = { 0 };
+ void *guest_buf;
+ hwaddr buf_sz;
+ gsize sz;
+ g_autofree gchar *contents = NULL;
+ GError *error = NULL;
+
+ *vmm_ret = SNP_EXT_REQ_ERROR_GENERIC;
+
+ if (!sev_snp_enabled()) {
+ return 0;
+ }
+
+ sev_snp_guest = SEV_SNP_GUEST(MACHINE(qdev_get_machine())->cgs);
+
+ if (!sev_snp_guest->certs_path) {
+ *vmm_ret = 0;
+ return 0;
+ }
+
+ if (!g_file_get_contents(sev_snp_guest->certs_path, &contents, &sz,
&error)) {
+ error_report("SEV: Failed to read '%s' (%s)",
sev_snp_guest->certs_path, error->message);
+ g_error_free(error);
+ return 0;
+ }
+
+ buf_sz = *npages * TARGET_PAGE_SIZE;
+
+ if (buf_sz < sz) {
+ *vmm_ret = SNP_EXT_REQ_ERROR_INVALID_LEN;
+ *npages = (sz + TARGET_PAGE_SIZE) / TARGET_PAGE_SIZE;
+ return 0;
+ }
+
+ guest_buf = address_space_map(&address_space_memory, gpa, &buf_sz, true,
attrs);
+ if (buf_sz < sz) {
+ g_warning("unable to map entire shared buffer, mapped size %ld
(expected %d)",
+ buf_sz, GHCB_SHARED_BUF_SIZE);
+ goto out_unmap;
+ }
+
+ memcpy(guest_buf, contents, buf_sz);
+ *vmm_ret = 0;
+
+out_unmap:
+ address_space_unmap(&address_space_memory, guest_buf, buf_sz, true,
buf_sz);
+
+ return 0;
+}
+
int kvm_handle_vmgexit(struct kvm_run *run)
{
int ret;
@@ -1583,6 +1641,10 @@ int kvm_handle_vmgexit(struct kvm_run *run)
ret = kvm_handle_vmgexit_psc_msr_protocol(run->vmgexit.psc_msr.gpa,
run->vmgexit.psc_msr.op,
&run->vmgexit.psc_msr.ret);
+ } else if (run->vmgexit.type == KVM_USER_VMGEXIT_EXT_GUEST_REQ) {
+ ret = kvm_handle_vmgexit_ext_req(run->vmgexit.ext_guest_req.data_gpa,
+
&run->vmgexit.ext_guest_req.data_npages,
+ &run->vmgexit.ext_guest_req.ret);
} else {
warn_report("KVM: unknown vmgexit type: %d", run->vmgexit.type);
ret = -1;
@@ -1914,6 +1976,26 @@ sev_snp_guest_set_host_data(Object *obj, const char
*value, Error **errp)
memcpy(finish->host_data, blob, len);
}
+static char *
+sev_snp_guest_get_certs_path(Object *obj, Error **errp)
+{
+ SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
+
+ return g_strdup(sev_snp_guest->certs_path);
+}
+
+static void
+sev_snp_guest_set_certs_path(Object *obj, const char *value, Error **errp)
+{
+ SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
+
+ if (sev_snp_guest->host_data) {
+ g_free(sev_snp_guest->host_data);
+ }
+
+ sev_snp_guest->certs_path = value ? g_strdup(value) : NULL;
+}
+
static void
sev_snp_guest_class_init(ObjectClass *oc, void *data)
{
@@ -1935,6 +2017,9 @@ sev_snp_guest_class_init(ObjectClass *oc, void *data)
object_class_property_add_str(oc, "host-data",
sev_snp_guest_get_host_data,
sev_snp_guest_set_host_data);
+ object_class_property_add_str(oc, "certs-path",
+ sev_snp_guest_get_certs_path,
+ sev_snp_guest_set_certs_path);
}
static void
--
2.25.1
- Re: [PATCH v3 02/49] scripts/update-linux-headers: Add setup_data.h to import list, (continued)
- [PATCH v3 31/49] i386/sev: Update query-sev QAPI format to handle SEV-SNP, Michael Roth, 2024/03/20
- [PATCH v3 32/49] i386/sev: Don't return launch measurements for SEV-SNP guests, Michael Roth, 2024/03/20
- [PATCH v3 33/49] kvm: Make kvm_convert_memory() non-static, Michael Roth, 2024/03/20
- [PATCH v3 34/49] i386/sev: Add KVM_EXIT_VMGEXIT handling for Page State Changes, Michael Roth, 2024/03/20
- [PATCH v3 35/49] i386/sev: Add KVM_EXIT_VMGEXIT handling for Page State Changes (MSR-based), Michael Roth, 2024/03/20
- [PATCH v3 36/49] i386/sev: Add KVM_EXIT_VMGEXIT handling for Extended Guest Requests,
Michael Roth <=
- [PATCH v3 37/49] i386/sev: Add the SNP launch start context, Michael Roth, 2024/03/20
- [PATCH v3 38/49] i386/sev: Add handling to encrypt/finalize guest launch data, Michael Roth, 2024/03/20
- [PATCH v3 39/49] i386/sev: Set CPU state to protected once SNP guest payload is finalized, Michael Roth, 2024/03/20
- [PATCH v3 40/49] hw/i386/sev: Add function to get SEV metadata from OVMF header, Michael Roth, 2024/03/20
- [PATCH v3 03/49] scripts/update-linux-headers: Add bits.h to file imports, Michael Roth, 2024/03/20