qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] qapi, i386/sev: Add debug-launch-digest to launch-measure respon


From: Dov Murik
Subject: [PATCH] qapi, i386/sev: Add debug-launch-digest to launch-measure response
Date: Mon, 31 Jan 2022 11:15:39 +0000

Currently the responses of QMP commands query-sev-launch-measure and
query-sev-attestation-report return just the signed measurement. In
order to validate it, the Guest Owner must know the exact guest launch
digest, besides other host and guest properties which are included in
the measurement.

The other host and guest details (SEV API major, SEV API minor, SEV
build, and guest policy) are all available via query-sev QMP command.
However, the launch digest is not available.  This makes checking the
measurement harder for the Guest Owner, as it has to iterate through all
allowed launch digests and compute the expected measurement.

Add a new field debug-launch-digest to the response of
query-sev-launch-measure and query-sev-attestation-report which includes
the guest launch digest, which is the SHA256 of all initial memory added
to the guest via sev_launch_update_data().

Note that the value of debug-launch-digest should not be used for
verifying the measurement, because it is not signed.  Hence the choice
of the 'debug-' prefix for the field's name.

Suggested-by: Tobin Feldman-Fitzthum <tobin@linux.ibm.com>
Signed-off-by: Dov Murik <dovmurik@linux.ibm.com>

---

Implementation note: I keep a buffer (sev->launch_memory) with the
content of all the memory added using sev_launch_update_data().  The
buffer is freed when the measurement is calculated (at which point no
more memory can be added by sev_launch_update_data()).  Ideally
it would be enough to keep just a SHA256 context struct, but I found no
such abstraction in crypto/hash.h -- only functions for calculating
finalized hashes of given buffers.
---
 qapi/misc-target.json    | 18 ++++++++++++++----
 target/i386/sev.c        | 40 ++++++++++++++++++++++++++++++++++++++--
 target/i386/trace-events |  2 +-
 3 files changed, 53 insertions(+), 7 deletions(-)

diff --git a/qapi/misc-target.json b/qapi/misc-target.json
index 4bc45d2474..43e659a7d2 100644
--- a/qapi/misc-target.json
+++ b/qapi/misc-target.json
@@ -142,10 +142,15 @@
 #
 # @data: the measurement value encoded in base64
 #
+# @debug-launch-digest: SHA256 of launch memory (base64 encoded) (since: 6.3)
+#
 # Since: 2.12
 #
 ##
-{ 'struct': 'SevLaunchMeasureInfo', 'data': {'data': 'str'},
+{ 'struct': 'SevLaunchMeasureInfo',
+  'data': { 'data': 'str',
+            'debug-launch-digest': 'str'
+          },
   'if': 'TARGET_I386' }
 
 ##
@@ -160,7 +165,8 @@
 # Example:
 #
 # -> { "execute": "query-sev-launch-measure" }
-# <- { "return": { "data": "4l8LXeNlSPUDlXPJG5966/8%YZ" } }
+# <- { "return": { "data": "4l8LXeNlSPUDlXPJG5966/8%YZ",
+#                  "debug-launch-digest": "abcdef1234567890" } }
 #
 ##
 { 'command': 'query-sev-launch-measure', 'returns': 'SevLaunchMeasureInfo',
@@ -237,11 +243,14 @@
 #
 # @data:  guest attestation report (base64 encoded)
 #
+# @debug-launch-digest: SHA256 of launch memory (base64 encoded) (since: 6.3)
 #
 # Since: 6.1
 ##
 { 'struct': 'SevAttestationReport',
-  'data': { 'data': 'str'},
+  'data': { 'data': 'str',
+            'debug-launch-digest': 'str'
+          },
   'if': 'TARGET_I386' }
 
 ##
@@ -261,7 +270,8 @@
 #
 # -> { "execute" : "query-sev-attestation-report",
 #                  "arguments": { "mnonce": "aaaaaaa" } }
-# <- { "return" : { "data": "aaaaaaaabbbddddd"} }
+# <- { "return" : { "data": "aaaaaaaabbbddddd",
+#                   "debug-launch-digest": "abcdef1234567890" } }
 #
 ##
 { 'command': 'query-sev-attestation-report',
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 025ff7a6f8..1c8d8a9966 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -21,6 +21,7 @@
 #include "qapi/error.h"
 #include "qom/object_interfaces.h"
 #include "qemu/base64.h"
+#include "qemu/buffer.h"
 #include "qemu/module.h"
 #include "qemu/uuid.h"
 #include "crypto/hash.h"
@@ -73,6 +74,8 @@ struct SevGuestState {
     int sev_fd;
     SevState state;
     gchar *measurement;
+    gchar *debug_launch_digest;
+    Buffer launch_memory;
 
     uint32_t reset_cs;
     uint32_t reset_ip;
@@ -643,6 +646,7 @@ static SevAttestationReport 
*sev_get_attestation_report(const char *mnonce,
 
     report = g_new0(SevAttestationReport, 1);
     report->data = g_base64_encode(data, input.len);
+    report->debug_launch_digest = g_strdup(sev->debug_launch_digest);
 
     trace_kvm_sev_attestation_report(mnonce, report->data);
 
@@ -709,6 +713,7 @@ sev_launch_start(SevGuestState *sev)
 
     sev_set_guest_state(sev, SEV_STATE_LAUNCH_UPDATE);
     sev->handle = start.handle;
+    buffer_init(&sev->launch_memory, "sev-guest-launch-memory");
     ret = 0;
 
 out:
@@ -727,6 +732,9 @@ sev_launch_update_data(SevGuestState *sev, uint8_t *addr, 
uint64_t len)
         return 1;
     }
 
+    buffer_reserve(&sev->launch_memory, len);
+    buffer_append(&sev->launch_memory, addr, len);
+
     update.uaddr = (__u64)(unsigned long)addr;
     update.len = len;
     trace_kvm_sev_launch_update_data(addr, len);
@@ -799,7 +807,17 @@ sev_launch_get_measure(Notifier *notifier, void *unused)
 
     /* encode the measurement value and emit the event */
     sev->measurement = g_base64_encode(data, measurement.len);
-    trace_kvm_sev_launch_measurement(sev->measurement);
+    if (qcrypto_hash_base64(QCRYPTO_HASH_ALG_SHA256,
+                            (const char *)sev->launch_memory.buffer,
+                            sev->launch_memory.offset,
+                            &sev->debug_launch_digest,
+                            NULL) < 0) {
+        error_report("%s: failed hashing launch memory", __func__);
+        return;
+    }
+    buffer_free(&sev->launch_memory);
+
+    trace_kvm_sev_launch_measurement(sev->measurement, 
sev->debug_launch_digest);
 }
 
 static char *sev_get_launch_measurement(void)
@@ -812,9 +830,19 @@ static char *sev_get_launch_measurement(void)
     return NULL;
 }
 
+static char *sev_get_debug_launch_digest(void)
+{
+    if (sev_guest &&
+        sev_guest->state >= SEV_STATE_LAUNCH_SECRET) {
+        return g_strdup(sev_guest->debug_launch_digest);
+    }
+
+    return NULL;
+}
+
 SevLaunchMeasureInfo *qmp_query_sev_launch_measure(Error **errp)
 {
-    char *data;
+    char *data, *debug_launch_digest;
     SevLaunchMeasureInfo *info;
 
     data = sev_get_launch_measurement();
@@ -823,8 +851,16 @@ SevLaunchMeasureInfo *qmp_query_sev_launch_measure(Error 
**errp)
         return NULL;
     }
 
+    debug_launch_digest = sev_get_debug_launch_digest();
+    if (!debug_launch_digest) {
+        error_setg(errp, "SEV launch digest is not available");
+        return NULL;
+    }
+
+
     info = g_malloc0(sizeof(*info));
     info->data = data;
+    info->debug_launch_digest = debug_launch_digest;
 
     return info;
 }
diff --git a/target/i386/trace-events b/target/i386/trace-events
index 2cd8726eeb..6a24bb00f0 100644
--- a/target/i386/trace-events
+++ b/target/i386/trace-events
@@ -7,7 +7,7 @@ kvm_memcrypt_unregister_region(void *addr, size_t len) "addr %p 
len 0x%zx"
 kvm_sev_change_state(const char *old, const char *new) "%s -> %s"
 kvm_sev_launch_start(int policy, void *session, void *pdh) "policy 0x%x 
session %p pdh %p"
 kvm_sev_launch_update_data(void *addr, uint64_t len) "addr %p len 0x%" PRIx64
-kvm_sev_launch_measurement(const char *value) "data %s"
+kvm_sev_launch_measurement(const char *value, const char *debug_launch_digest) 
"data %s debug_launch_digest %s"
 kvm_sev_launch_finish(void) ""
 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"
 kvm_sev_attestation_report(const char *mnonce, const char *data) "mnonce %s 
data %s"
-- 
2.25.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]