From 10f5fa07068f54b23b01bf875259dc1a259d66b4 Mon Sep 17 00:00:00 2001 From: hanliyang 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 --- 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=$(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