The virDomainGetSevVmMeasurement() can be used to retrieve the measurement of encrypted VM launched using AMD SEV feature. The measurement is a signature of the memory contents that can be sent to the guest owner as an attestation that the memory was encrypted correctly by the firmware before booting the guest. Signed-off-by: Xiaogang Chen <Xiaogang.Chen@xxxxxxx> Signed-off-by: Brijesh Singh <brijesh.singh@xxxxxxx> --- include/libvirt/libvirt-domain.h | 4 +++ src/driver-hypervisor.h | 4 +++ src/libvirt-domain.c | 41 +++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + src/qemu/qemu_driver.c | 57 ++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor.c | 8 ++++++ src/qemu/qemu_monitor.h | 3 +++ src/qemu/qemu_monitor_json.c | 33 +++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 2 ++ src/remote/remote_driver.c | 3 ++- src/remote/remote_protocol.x | 17 +++++++++++- 11 files changed, 171 insertions(+), 2 deletions(-) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 4048acf38aaf..c0bcfea4723c 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -4756,4 +4756,8 @@ int virDomainSetLifecycleAction(virDomainPtr domain, unsigned int action, unsigned int flags); +char * +virDomainGetSevVmMeasurement(virDomainPtr domain, + unsigned int flags); + #endif /* __VIR_LIBVIRT_DOMAIN_H__ */ diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h index ce0e2b252552..73edcd8f059f 100644 --- a/src/driver-hypervisor.h +++ b/src/driver-hypervisor.h @@ -1283,6 +1283,9 @@ typedef int unsigned int action, unsigned int flags); +typedef char * +(*virDrvDomainGetSevVmMeasurement)(virDomainPtr dommain, + unsigned int flags); typedef struct _virHypervisorDriver virHypervisorDriver; typedef virHypervisorDriver *virHypervisorDriverPtr; @@ -1528,6 +1531,7 @@ struct _virHypervisorDriver { virDrvDomainSetVcpu domainSetVcpu; virDrvDomainSetBlockThreshold domainSetBlockThreshold; virDrvDomainSetLifecycleAction domainSetLifecycleAction; + virDrvDomainGetSevVmMeasurement domainGetSevVmMeasurement; }; diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index eaec0979ad49..f285a3121548 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -12095,3 +12095,44 @@ int virDomainSetLifecycleAction(virDomainPtr domain, virDispatchError(domain->conn); return -1; } + +/** + * virDomainGetSevVmMeasurement: + * @domain: pointer to domain object + * @flags: currently unused, pass 0 + * + * Get launch measurement of SEV guest VM + * + * Returns a measurement string, or NULL in case of error. + */ +char * +virDomainGetSevVmMeasurement(virDomainPtr domain, + unsigned int flags) +{ + virConnectPtr conn; + VIR_DOMAIN_DEBUG(domain, "flags=0x%x", flags); + + virResetLastError(); + + virCheckDomainReturn(domain, NULL); + conn = domain->conn; + + virCheckReadOnlyGoto(conn->flags, error); + + if (conn->driver->domainGetSevVmMeasurement) { + char *ret; + + ret = conn->driver->domainGetSevVmMeasurement(domain, + flags); + if (!ret) + goto error; + + return ret; + } + + virReportUnsupportedError(); + +error: + virDispatchError(domain->conn); + return NULL; +} diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 95df3a0dbc7b..6e956d965a26 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -783,6 +783,7 @@ LIBVIRT_3.9.0 { LIBVIRT_4.1.0 { global: virStoragePoolLookupByTargetPath; + virDomainGetSevVmMeasurement; } LIBVIRT_3.9.0; # .... define new API here using predicted next version number .... diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 313d730c791f..852d1f0fd2f7 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -21254,6 +21254,62 @@ qemuDomainSetLifecycleAction(virDomainPtr dom, return ret; } +static char * +qemuDomainGetSevVmMeasurement(virDomainPtr dom, + unsigned int flags) +{ + virQEMUDriverPtr driver = dom->conn->privateData; + virDomainObjPtr vm; + char *ret = NULL, *tmp; + + virCheckFlags(0, NULL); + + if (!(vm = qemuDomObjFromDomain(dom))) + goto cleanup; + + if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0) + goto cleanup; + + if (!virDomainObjIsActive(vm)) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("domain is not running")); + goto endjob; + } + + if (virDomainGetSevVmMeasurementEnsureACL(dom->conn, vm->def) < 0){ + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("get sev vm measurement is not allowed")); + goto cleanup; + } + + if (vm->def->sev) { + goto endjob; + virReportError(VIR_ERR_INTERNAL_ERROR, + _("domain is not SEV guest")); + } + + if (qemuDomainObjEnterMonitorAsync(driver, vm, QEMU_ASYNC_JOB_NONE) < 0) + goto endjob; + + VIR_DEBUG("query sev launch measurement"); + if(!(tmp = qemuMonitorGetSevMeasurement(QEMU_DOMAIN_PRIVATE(vm)->mon))){ + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to get measurement")); + goto endjob; + } + + if (qemuDomainObjExitMonitor(driver, vm) < 0) + goto endjob; + + ret = tmp; + + endjob: + qemuDomainObjEndJob(driver, vm); + + cleanup: + virDomainObjEndAPI(&vm); + return ret; +} static virHypervisorDriver qemuHypervisorDriver = { .name = QEMU_DRIVER_NAME, @@ -21474,6 +21530,7 @@ static virHypervisorDriver qemuHypervisorDriver = { .domainSetVcpu = qemuDomainSetVcpu, /* 3.1.0 */ .domainSetBlockThreshold = qemuDomainSetBlockThreshold, /* 3.2.0 */ .domainSetLifecycleAction = qemuDomainSetLifecycleAction, /* 3.9.0 */ + .domainGetSevVmMeasurement = qemuDomainGetSevVmMeasurement, /* 4.2.0 */ }; diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 195248c88ae1..e3dd078e4e73 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4400,3 +4400,11 @@ qemuMonitorSetWatchdogAction(qemuMonitorPtr mon, return qemuMonitorJSONSetWatchdogAction(mon, action); } + +char * +qemuMonitorGetSevMeasurement(qemuMonitorPtr mon) +{ + QEMU_CHECK_MONITOR_NULL(mon); + + return qemuMonitorJSONGetSevMeasurement(mon); +} diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 1b2513650c58..dd0821178c47 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1176,4 +1176,7 @@ virJSONValuePtr qemuMonitorQueryNamedBlockNodes(qemuMonitorPtr mon); int qemuMonitorSetWatchdogAction(qemuMonitorPtr mon, const char *action); +char * +qemuMonitorGetSevMeasurement(qemuMonitorPtr mon); + #endif /* QEMU_MONITOR_H */ diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 4424abfa7148..1d7f0e7c168e 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -7974,3 +7974,36 @@ qemuMonitorJSONSetWatchdogAction(qemuMonitorPtr mon, virJSONValueFree(reply); return ret; } + +char * +qemuMonitorJSONGetSevMeasurement(qemuMonitorPtr mon) +{ + const char *tmp; + char *measurement = NULL; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + virJSONValuePtr data; + + if (!(cmd = qemuMonitorJSONMakeCommand("query-sev-launch-measure", NULL))) + return NULL; + + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + goto cleanup; + + if (qemuMonitorJSONCheckError(cmd, reply) < 0) + goto cleanup; + + data = virJSONValueObjectGetObject(reply, "return"); + + if (!(tmp = virJSONValueObjectGetString(data, "data"))) + goto cleanup; + + if (VIR_STRDUP(measurement, tmp) < 0){ + goto cleanup; + } + +cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + return measurement; +} diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 305f789902e9..b03b35ae0e8b 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -342,6 +342,8 @@ int qemuMonitorJSONGetBlockIoThrottle(qemuMonitorPtr mon, int qemuMonitorJSONSystemWakeup(qemuMonitorPtr mon); +char * qemuMonitorJSONGetSevMeasurement(qemuMonitorPtr mon); + int qemuMonitorJSONGetVersion(qemuMonitorPtr mon, int *major, int *minor, diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 9ea726dc45c0..080d244db156 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -8497,7 +8497,8 @@ static virHypervisorDriver hypervisor_driver = { .domainSetGuestVcpus = remoteDomainSetGuestVcpus, /* 2.0.0 */ .domainSetVcpu = remoteDomainSetVcpu, /* 3.1.0 */ .domainSetBlockThreshold = remoteDomainSetBlockThreshold, /* 3.2.0 */ - .domainSetLifecycleAction = remoteDomainSetLifecycleAction /* 3.9.0 */ + .domainSetLifecycleAction = remoteDomainSetLifecycleAction, /* 3.9.0 */ + .domainGetSevVmMeasurement = remoteDomainGetSevVmMeasurement /* 4.2.0 */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 9dbd497b2fff..227ee8345683 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -3448,6 +3448,15 @@ struct remote_domain_set_lifecycle_action_args { unsigned int flags; }; +struct remote_domain_get_sev_vm_measurement_args { + remote_nonnull_domain dom; + unsigned int flags; +}; + +struct remote_domain_get_sev_vm_measurement_ret { + remote_nonnull_string sev_measurement; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -6135,5 +6144,11 @@ enum remote_procedure { * @priority: high * @acl: storage_pool:getattr */ - REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_TARGET_PATH = 391 + REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_TARGET_PATH = 391, + + /** + * @generate: both + * @acl: domain:read + */ + REMOTE_PROC_DOMAIN_GET_SEV_VM_MEASUREMENT = 392 }; -- 2.14.3 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list