cryptospore / rpms / qemu-kvm

Forked from rpms/qemu-kvm 2 years ago
Clone

Blame SOURCES/kvm-target-i386-sev-add-support-to-query-the-attestation.patch

a83cc2
From ba750c8ed71bc73c79fecefa895192793ef6b7db Mon Sep 17 00:00:00 2001
a83cc2
From: Connor Kuehl <ckuehl@redhat.com>
a83cc2
Date: Wed, 2 Jun 2021 19:39:20 -0400
a83cc2
Subject: [PATCH 05/21] target/i386/sev: add support to query the attestation
a83cc2
 report
a83cc2
MIME-Version: 1.0
a83cc2
Content-Type: text/plain; charset=UTF-8
a83cc2
Content-Transfer-Encoding: 8bit
a83cc2
a83cc2
RH-Author: Miroslav Rezanina <mrezanin@redhat.com>
a83cc2
RH-MergeRequest: 8: Synchronize with RHEL-AV 8.5 release 19 to RHEL 9
a83cc2
RH-Commit: [4/8] de6088cb0cd1db779b85a50be87846e967f8c92c (mrezanin/centos-src-qemu-kvm)
a83cc2
RH-Bugzilla: 1957194
a83cc2
RH-Acked-by: Daniel P. Berrangé <berrange@redhat.com>
a83cc2
RH-Acked-by: Greg Kurz <gkurz@redhat.com>
a83cc2
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
a83cc2
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
a83cc2
a83cc2
From: Brijesh Singh <brijesh.singh@amd.com>
a83cc2
a83cc2
The SEV FW >= 0.23 added a new command that can be used to query the
a83cc2
attestation report containing the SHA-256 digest of the guest memory
a83cc2
and VMSA encrypted with the LAUNCH_UPDATE and sign it with the PEK.
a83cc2
a83cc2
Note, we already have a command (LAUNCH_MEASURE) that can be used to
a83cc2
query the SHA-256 digest of the guest memory encrypted through the
a83cc2
LAUNCH_UPDATE. The main difference between previous and this command
a83cc2
is that the report is signed with the PEK and unlike the LAUNCH_MEASURE
a83cc2
command the ATTESATION_REPORT command can be called while the guest
a83cc2
is running.
a83cc2
a83cc2
Add a QMP interface "query-sev-attestation-report" that can be used
a83cc2
to get the report encoded in base64.
a83cc2
a83cc2
Cc: James Bottomley <jejb@linux.ibm.com>
a83cc2
Cc: Tom Lendacky <Thomas.Lendacky@amd.com>
a83cc2
Cc: Eric Blake <eblake@redhat.com>
a83cc2
Cc: Paolo Bonzini <pbonzini@redhat.com>
a83cc2
Cc: kvm@vger.kernel.org
a83cc2
Reviewed-by: James Bottomley <jejb@linux.ibm.com>
a83cc2
Tested-by: James Bottomley <jejb@linux.ibm.com>
a83cc2
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
a83cc2
Reviewed-by: Connor Kuehl <ckuehl@redhat.com>
a83cc2
Message-Id: <20210429170728.24322-1-brijesh.singh@amd.com>
a83cc2
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
a83cc2
(cherry picked from commit 3ea1a80243d5b5ba23d8c2b7d3a86034ea0ade22)
a83cc2
Signed-off-by: Connor Kuehl <ckuehl@redhat.com>
a83cc2
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
a83cc2
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
a83cc2
---
a83cc2
 linux-headers/linux/kvm.h |  8 +++++
a83cc2
 qapi/misc-target.json     | 38 ++++++++++++++++++++++
a83cc2
 target/i386/monitor.c     |  6 ++++
a83cc2
 target/i386/sev-stub.c    |  7 ++++
a83cc2
 target/i386/sev.c         | 67 +++++++++++++++++++++++++++++++++++++++
a83cc2
 target/i386/sev_i386.h    |  2 ++
a83cc2
 target/i386/trace-events  |  1 +
a83cc2
 7 files changed, 129 insertions(+)
a83cc2
a83cc2
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
a83cc2
index 020b62a619..897f831374 100644
a83cc2
--- a/linux-headers/linux/kvm.h
a83cc2
+++ b/linux-headers/linux/kvm.h
a83cc2
@@ -1591,6 +1591,8 @@ enum sev_cmd_id {
a83cc2
 	KVM_SEV_DBG_ENCRYPT,
a83cc2
 	/* Guest certificates commands */
a83cc2
 	KVM_SEV_CERT_EXPORT,
a83cc2
+	/* Attestation report */
a83cc2
+	KVM_SEV_GET_ATTESTATION_REPORT,
a83cc2
 
a83cc2
 	KVM_SEV_NR_MAX,
a83cc2
 };
a83cc2
@@ -1643,6 +1645,12 @@ struct kvm_sev_dbg {
a83cc2
 	__u32 len;
a83cc2
 };
a83cc2
 
a83cc2
+struct kvm_sev_attestation_report {
a83cc2
+	__u8 mnonce[16];
a83cc2
+	__u64 uaddr;
a83cc2
+	__u32 len;
a83cc2
+};
a83cc2
+
a83cc2
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0)
a83cc2
 #define KVM_DEV_ASSIGN_PCI_2_3		(1 << 1)
a83cc2
 #define KVM_DEV_ASSIGN_MASK_INTX	(1 << 2)
a83cc2
diff --git a/qapi/misc-target.json b/qapi/misc-target.json
a83cc2
index 0c7491cd82..4b62f0ac05 100644
a83cc2
--- a/qapi/misc-target.json
a83cc2
+++ b/qapi/misc-target.json
a83cc2
@@ -285,3 +285,41 @@
a83cc2
 ##
a83cc2
 { 'command': 'query-gic-capabilities', 'returns': ['GICCapability'],
a83cc2
   'if': 'defined(TARGET_ARM)' }
a83cc2
+
a83cc2
+
a83cc2
+##
a83cc2
+# @SevAttestationReport:
a83cc2
+#
a83cc2
+# The struct describes attestation report for a Secure Encrypted Virtualization
a83cc2
+# feature.
a83cc2
+#
a83cc2
+# @data:  guest attestation report (base64 encoded)
a83cc2
+#
a83cc2
+#
a83cc2
+# Since: 6.1
a83cc2
+##
a83cc2
+{ 'struct': 'SevAttestationReport',
a83cc2
+  'data': { 'data': 'str'},
a83cc2
+  'if': 'defined(TARGET_I386)' }
a83cc2
+
a83cc2
+##
a83cc2
+# @query-sev-attestation-report:
a83cc2
+#
a83cc2
+# This command is used to get the SEV attestation report, and is supported on AMD
a83cc2
+# X86 platforms only.
a83cc2
+#
a83cc2
+# @mnonce: a random 16 bytes value encoded in base64 (it will be included in report)
a83cc2
+#
a83cc2
+# Returns: SevAttestationReport objects.
a83cc2
+#
a83cc2
+# Since: 6.1
a83cc2
+#
a83cc2
+# Example:
a83cc2
+#
a83cc2
+# -> { "execute" : "query-sev-attestation-report", "arguments": { "mnonce": "aaaaaaa" } }
a83cc2
+# <- { "return" : { "data": "aaaaaaaabbbddddd"} }
a83cc2
+#
a83cc2
+##
a83cc2
+{ 'command': 'query-sev-attestation-report', 'data': { 'mnonce': 'str' },
a83cc2
+  'returns': 'SevAttestationReport',
a83cc2
+  'if': 'defined(TARGET_I386)' }
a83cc2
diff --git a/target/i386/monitor.c b/target/i386/monitor.c
a83cc2
index 5994408bee..119211f0b0 100644
a83cc2
--- a/target/i386/monitor.c
a83cc2
+++ b/target/i386/monitor.c
a83cc2
@@ -757,3 +757,9 @@ void qmp_sev_inject_launch_secret(const char *packet_hdr,
a83cc2
 
a83cc2
     sev_inject_launch_secret(packet_hdr, secret, gpa, errp);
a83cc2
 }
a83cc2
+
a83cc2
+SevAttestationReport *
a83cc2
+qmp_query_sev_attestation_report(const char *mnonce, Error **errp)
a83cc2
+{
a83cc2
+    return sev_get_attestation_report(mnonce, errp);
a83cc2
+}
a83cc2
diff --git a/target/i386/sev-stub.c b/target/i386/sev-stub.c
a83cc2
index 0207f1c5aa..0227cb5177 100644
a83cc2
--- a/target/i386/sev-stub.c
a83cc2
+++ b/target/i386/sev-stub.c
a83cc2
@@ -74,3 +74,10 @@ int sev_es_save_reset_vector(void *flash_ptr, uint64_t flash_size)
a83cc2
 {
a83cc2
     abort();
a83cc2
 }
a83cc2
+
a83cc2
+SevAttestationReport *
a83cc2
+sev_get_attestation_report(const char *mnonce, Error **errp)
a83cc2
+{
a83cc2
+    error_setg(errp, "SEV is not available in this QEMU");
a83cc2
+    return NULL;
a83cc2
+}
a83cc2
diff --git a/target/i386/sev.c b/target/i386/sev.c
a83cc2
index 72b9e2ab40..740548f213 100644
a83cc2
--- a/target/i386/sev.c
a83cc2
+++ b/target/i386/sev.c
a83cc2
@@ -491,6 +491,73 @@ out:
a83cc2
     return cap;
a83cc2
 }
a83cc2
 
a83cc2
+SevAttestationReport *
a83cc2
+sev_get_attestation_report(const char *mnonce, Error **errp)
a83cc2
+{
a83cc2
+    struct kvm_sev_attestation_report input = {};
a83cc2
+    SevAttestationReport *report = NULL;
a83cc2
+    SevGuestState *sev = sev_guest;
a83cc2
+    guchar *data;
a83cc2
+    guchar *buf;
a83cc2
+    gsize len;
a83cc2
+    int err = 0, ret;
a83cc2
+
a83cc2
+    if (!sev_enabled()) {
a83cc2
+        error_setg(errp, "SEV is not enabled");
a83cc2
+        return NULL;
a83cc2
+    }
a83cc2
+
a83cc2
+    /* lets decode the mnonce string */
a83cc2
+    buf = g_base64_decode(mnonce, &len;;
a83cc2
+    if (!buf) {
a83cc2
+        error_setg(errp, "SEV: failed to decode mnonce input");
a83cc2
+        return NULL;
a83cc2
+    }
a83cc2
+
a83cc2
+    /* verify the input mnonce length */
a83cc2
+    if (len != sizeof(input.mnonce)) {
a83cc2
+        error_setg(errp, "SEV: mnonce must be %zu bytes (got %" G_GSIZE_FORMAT ")",
a83cc2
+                sizeof(input.mnonce), len);
a83cc2
+        g_free(buf);
a83cc2
+        return NULL;
a83cc2
+    }
a83cc2
+
a83cc2
+    /* Query the report length */
a83cc2
+    ret = sev_ioctl(sev->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
a83cc2
+            &input, &err;;
a83cc2
+    if (ret < 0) {
a83cc2
+        if (err != SEV_RET_INVALID_LEN) {
a83cc2
+            error_setg(errp, "failed to query the attestation report length "
a83cc2
+                    "ret=%d fw_err=%d (%s)", ret, err, fw_error_to_str(err));
a83cc2
+            g_free(buf);
a83cc2
+            return NULL;
a83cc2
+        }
a83cc2
+    }
a83cc2
+
a83cc2
+    data = g_malloc(input.len);
a83cc2
+    input.uaddr = (unsigned long)data;
a83cc2
+    memcpy(input.mnonce, buf, sizeof(input.mnonce));
a83cc2
+
a83cc2
+    /* Query the report */
a83cc2
+    ret = sev_ioctl(sev->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
a83cc2
+            &input, &err;;
a83cc2
+    if (ret) {
a83cc2
+        error_setg_errno(errp, errno, "Failed to get attestation report"
a83cc2
+                " ret=%d fw_err=%d (%s)", ret, err, fw_error_to_str(err));
a83cc2
+        goto e_free_data;
a83cc2
+    }
a83cc2
+
a83cc2
+    report = g_new0(SevAttestationReport, 1);
a83cc2
+    report->data = g_base64_encode(data, input.len);
a83cc2
+
a83cc2
+    trace_kvm_sev_attestation_report(mnonce, report->data);
a83cc2
+
a83cc2
+e_free_data:
a83cc2
+    g_free(data);
a83cc2
+    g_free(buf);
a83cc2
+    return report;
a83cc2
+}
a83cc2
+
a83cc2
 static int
a83cc2
 sev_read_file_base64(const char *filename, guchar **data, gsize *len)
a83cc2
 {
a83cc2
diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h
a83cc2
index ae221d4c72..ae6d840478 100644
a83cc2
--- a/target/i386/sev_i386.h
a83cc2
+++ b/target/i386/sev_i386.h
a83cc2
@@ -35,5 +35,7 @@ extern uint32_t sev_get_cbit_position(void);
a83cc2
 extern uint32_t sev_get_reduced_phys_bits(void);
a83cc2
 extern char *sev_get_launch_measurement(void);
a83cc2
 extern SevCapability *sev_get_capabilities(Error **errp);
a83cc2
+extern SevAttestationReport *
a83cc2
+sev_get_attestation_report(const char *mnonce, Error **errp);
a83cc2
 
a83cc2
 #endif
a83cc2
diff --git a/target/i386/trace-events b/target/i386/trace-events
a83cc2
index a22ab24e21..8d6437404d 100644
a83cc2
--- a/target/i386/trace-events
a83cc2
+++ b/target/i386/trace-events
a83cc2
@@ -10,3 +10,4 @@ kvm_sev_launch_update_data(void *addr, uint64_t len) "addr %p len 0x%" PRIx64
a83cc2
 kvm_sev_launch_measurement(const char *value) "data %s"
a83cc2
 kvm_sev_launch_finish(void) ""
a83cc2
 kvm_sev_launch_secret(uint64_t hpa, uint64_t hva, uint64_t secret, int len) "hpa 0x%" PRIx64 " hva 0x%" PRIx64 " data 0x%" PRIx64 " len %d"
a83cc2
+kvm_sev_attestation_report(const char *mnonce, const char *data) "mnonce %s data %s"
a83cc2
-- 
a83cc2
2.27.0
a83cc2