221 lines
7.4 KiB
Diff
221 lines
7.4 KiB
Diff
|
|
From 10f5fa07068f54b23b01bf875259dc1a259d66b4 Mon Sep 17 00:00:00 2001
|
||
|
|
From: hanliyang <hanliyang@hygon.cn>
|
||
|
|
Date: Fri, 2 Aug 2024 01:35:25 +0800
|
||
|
|
Subject: [PATCH] qapi/qom,target/i386: csv-guest: Introduce
|
||
|
|
secret-header-file=str and secret-file=str options
|
||
|
|
|
||
|
|
This feature only applied to Hygon CSV.
|
||
|
|
|
||
|
|
User can utilize the hag to generate secret header file and secret file,
|
||
|
|
and inject these data to guest encrypted secret area automatically.
|
||
|
|
|
||
|
|
Signed-off-by: hanliyang <hanliyang@hygon.cn>
|
||
|
|
---
|
||
|
|
qapi/qom.json | 9 ++++-
|
||
|
|
qemu-options.hx | 8 +++-
|
||
|
|
target/i386/sev.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
|
3 files changed, 115 insertions(+), 2 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/qapi/qom.json b/qapi/qom.json
|
||
|
|
index 51d9daf55a..a74c7a91f9 100644
|
||
|
|
--- a/qapi/qom.json
|
||
|
|
+++ b/qapi/qom.json
|
||
|
|
@@ -869,6 +869,11 @@
|
||
|
|
# @user-id: the user id of the guest owner, only support on Hygon CPUs
|
||
|
|
# (since 8.2)
|
||
|
|
#
|
||
|
|
+# @secret-header-file: the header file of guest owner's secret, only
|
||
|
|
+# support on Hygon CPUs (since 8.2)
|
||
|
|
+# @secret-file: the file guest owner's secret, only support on Hygon
|
||
|
|
+# CPUs (since 8.2)
|
||
|
|
+#
|
||
|
|
# Since: 2.12
|
||
|
|
##
|
||
|
|
{ 'struct': 'SevGuestProperties',
|
||
|
|
@@ -880,7 +885,9 @@
|
||
|
|
'*cbitpos': 'uint32',
|
||
|
|
'reduced-phys-bits': 'uint32',
|
||
|
|
'*kernel-hashes': 'bool',
|
||
|
|
- '*user-id': 'str' } }
|
||
|
|
+ '*user-id': 'str',
|
||
|
|
+ '*secret-header-file': 'str',
|
||
|
|
+ '*secret-file': 'str' } }
|
||
|
|
|
||
|
|
##
|
||
|
|
# @ThreadContextProperties:
|
||
|
|
diff --git a/qemu-options.hx b/qemu-options.hx
|
||
|
|
index 51ba9378b9..8516b73206 100644
|
||
|
|
--- a/qemu-options.hx
|
||
|
|
+++ b/qemu-options.hx
|
||
|
|
@@ -5637,7 +5637,7 @@ SRST
|
||
|
|
-object secret,id=sec0,keyid=secmaster0,format=base64,\\
|
||
|
|
data=$SECRET,iv=$(<iv.b64)
|
||
|
|
|
||
|
|
- ``-object sev-guest,id=id,cbitpos=cbitpos,reduced-phys-bits=val,[sev-device=string,policy=policy,handle=handle,dh-cert-file=file,session-file=file,kernel-hashes=on|off,user-id=id]``
|
||
|
|
+ ``-object sev-guest,id=id,cbitpos=cbitpos,reduced-phys-bits=val,[sev-device=string,policy=policy,handle=handle,dh-cert-file=file,session-file=file,kernel-hashes=on|off,user-id=id,secret-header-file=file,secret-file=file]``
|
||
|
|
Create a Secure Encrypted Virtualization (SEV) guest object,
|
||
|
|
which can be used to provide the guest memory encryption support
|
||
|
|
on AMD processors.
|
||
|
|
@@ -5684,6 +5684,12 @@ SRST
|
||
|
|
The ``user-id`` set the user id of the guest owner, this only
|
||
|
|
support on Hygon CPUs. (Since 8.2)
|
||
|
|
|
||
|
|
+ The ``secret-header-file`` set the header file of the guest owner's
|
||
|
|
+ secret, this only support on Hygon CPUs. (Since 8.2)
|
||
|
|
+
|
||
|
|
+ The ``secret-file`` set the file of the guest owner's secret, this
|
||
|
|
+ only support on Hygon CPUs. (Since 8.2)
|
||
|
|
+
|
||
|
|
e.g to launch a SEV guest
|
||
|
|
|
||
|
|
.. parsed-literal::
|
||
|
|
diff --git a/target/i386/sev.c b/target/i386/sev.c
|
||
|
|
index 5124bf3dee..721eca2150 100644
|
||
|
|
--- a/target/i386/sev.c
|
||
|
|
+++ b/target/i386/sev.c
|
||
|
|
@@ -73,6 +73,8 @@ struct SevGuestState {
|
||
|
|
uint32_t reduced_phys_bits;
|
||
|
|
bool kernel_hashes;
|
||
|
|
char *user_id;
|
||
|
|
+ char *secret_header_file;
|
||
|
|
+ char *secret_file;
|
||
|
|
|
||
|
|
/* runtime state */
|
||
|
|
uint32_t handle;
|
||
|
|
@@ -390,6 +392,38 @@ sev_guest_set_user_id(Object *obj, const char *value, Error **errp)
|
||
|
|
s->user_id = g_strdup(value);
|
||
|
|
}
|
||
|
|
|
||
|
|
+static char *
|
||
|
|
+sev_guest_get_secret_header_file(Object *obj, Error **errp)
|
||
|
|
+{
|
||
|
|
+ SevGuestState *s = SEV_GUEST(obj);
|
||
|
|
+
|
||
|
|
+ return g_strdup(s->secret_header_file);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static void
|
||
|
|
+sev_guest_set_secret_header_file(Object *obj, const char *value, Error **errp)
|
||
|
|
+{
|
||
|
|
+ SevGuestState *s = SEV_GUEST(obj);
|
||
|
|
+
|
||
|
|
+ s->secret_header_file = g_strdup(value);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static char *
|
||
|
|
+sev_guest_get_secret_file(Object *obj, Error **errp)
|
||
|
|
+{
|
||
|
|
+ SevGuestState *s = SEV_GUEST(obj);
|
||
|
|
+
|
||
|
|
+ return g_strdup(s->secret_file);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static void
|
||
|
|
+sev_guest_set_secret_file(Object *obj, const char *value, Error **errp)
|
||
|
|
+{
|
||
|
|
+ SevGuestState *s = SEV_GUEST(obj);
|
||
|
|
+
|
||
|
|
+ s->secret_file = g_strdup(value);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
static char *
|
||
|
|
sev_guest_get_sev_device(Object *obj, Error **errp)
|
||
|
|
{
|
||
|
|
@@ -448,6 +482,16 @@ sev_guest_class_init(ObjectClass *oc, void *data)
|
||
|
|
sev_guest_set_user_id);
|
||
|
|
object_class_property_set_description(oc, "user-id",
|
||
|
|
"user id of the guest owner");
|
||
|
|
+ object_class_property_add_str(oc, "secret-header-file",
|
||
|
|
+ sev_guest_get_secret_header_file,
|
||
|
|
+ sev_guest_set_secret_header_file);
|
||
|
|
+ object_class_property_set_description(oc, "secret-header-file",
|
||
|
|
+ "header file of the guest owner's secret");
|
||
|
|
+ object_class_property_add_str(oc, "secret-file",
|
||
|
|
+ sev_guest_get_secret_file,
|
||
|
|
+ sev_guest_set_secret_file);
|
||
|
|
+ object_class_property_set_description(oc, "secret-file",
|
||
|
|
+ "file of the guest owner's secret");
|
||
|
|
}
|
||
|
|
|
||
|
|
static void
|
||
|
|
@@ -867,6 +911,9 @@ sev_launch_update_vmsa(SevGuestState *sev)
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
+static int
|
||
|
|
+csv_load_launch_secret(const char *secret_header_file, const char *secret_file);
|
||
|
|
+
|
||
|
|
static void
|
||
|
|
sev_launch_get_measure(Notifier *notifier, void *unused)
|
||
|
|
{
|
||
|
|
@@ -917,6 +964,15 @@ 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);
|
||
|
|
+
|
||
|
|
+ /* Hygon CSV will auto load guest owner's secret */
|
||
|
|
+ if (is_hygon_cpu()) {
|
||
|
|
+ if (sev->secret_header_file &&
|
||
|
|
+ strlen(sev->secret_header_file) &&
|
||
|
|
+ sev->secret_file &&
|
||
|
|
+ strlen(sev->secret_file))
|
||
|
|
+ csv_load_launch_secret(sev->secret_header_file, sev->secret_file);
|
||
|
|
+ }
|
||
|
|
}
|
||
|
|
|
||
|
|
static char *sev_get_launch_measurement(void)
|
||
|
|
@@ -2526,6 +2582,50 @@ int csv_load_incoming_cpu_state(QEMUFile *f)
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
+static int
|
||
|
|
+csv_load_launch_secret(const char *secret_header_file, const char *secret_file)
|
||
|
|
+{
|
||
|
|
+ gsize secret_header_size, secret_size;
|
||
|
|
+ gchar *secret_header = NULL, *secret = NULL;
|
||
|
|
+ uint8_t *data;
|
||
|
|
+ struct sev_secret_area *area;
|
||
|
|
+ uint64_t gpa;
|
||
|
|
+ GError *error = NULL;
|
||
|
|
+ Error *local_err = NULL;
|
||
|
|
+ int ret = 0;
|
||
|
|
+
|
||
|
|
+ if (!g_file_get_contents(secret_header_file,
|
||
|
|
+ &secret_header,
|
||
|
|
+ &secret_header_size, &error)) {
|
||
|
|
+ error_report("CSV: Failed to read '%s' (%s)",
|
||
|
|
+ secret_header_file, error->message);
|
||
|
|
+ g_error_free(error);
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!g_file_get_contents(secret_file, &secret, &secret_size, &error)) {
|
||
|
|
+ error_report("CSV: Failed to read '%s' (%s)", secret_file, error->message);
|
||
|
|
+ g_error_free(error);
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!pc_system_ovmf_table_find(SEV_SECRET_GUID, &data, NULL)) {
|
||
|
|
+ error_report("CSV: no secret area found in OVMF, gpa must be"
|
||
|
|
+ " specified.");
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+ area = (struct sev_secret_area *)data;
|
||
|
|
+ gpa = area->base;
|
||
|
|
+
|
||
|
|
+ ret = sev_inject_launch_secret((char *)secret_header,
|
||
|
|
+ (char *)secret, gpa, &local_err);
|
||
|
|
+
|
||
|
|
+ if (local_err) {
|
||
|
|
+ error_report_err(local_err);
|
||
|
|
+ }
|
||
|
|
+ return ret;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
static const QemuUUID sev_hash_table_header_guid = {
|
||
|
|
.data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93,
|
||
|
|
0xd4, 0x11, 0xfd, 0x21)
|
||
|
|
--
|
||
|
|
2.41.0.windows.1
|
||
|
|
|