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@amd.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
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@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
On Mon, Feb 26, 2018 at 11:53:36AM -0600, Brijesh Singh wrote: > 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@amd.com> > Signed-off-by: Brijesh Singh <brijesh.singh@amd.com> > --- > 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); I'm a little concerned with introducing an API like this that is tied to the specific implementation that we have in AMD chips today, as it is unlikely to be usable when other vendors provide equivalent functionality. At the same time it is hard (impossible) to predict what information future impelementations will need to provide. So I wonder if we would be better making the API generic by using the virTypedParameters design. eg virDomaniGetLaunchSecurityInfo(virDOmaniPtr domain, virTypedParametersPtr *params, unsigned int *nparams, unsigned int flags); And then to start with we could just define a single named parameter #define VIR_DOMAIN_LAUNCH_SECURITY_SEV_MEASUREMENT "sev-measurement" > 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; Since we're in freeze for 4.1.0, it is going to be 4.2.0 at the earliest now. > 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")); Hehe, unreachable code due to inverted order :-) > + } > + > + 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; > +} Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :| -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
On 02/27/2018 05:07 AM, Daniel P. Berrangé wrote: > On Mon, Feb 26, 2018 at 11:53:36AM -0600, Brijesh Singh wrote: >> 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@amd.com> >> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com> >> --- >> 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); > > I'm a little concerned with introducing an API like this that is tied to the > specific implementation that we have in AMD chips today, as it is unlikely > to be usable when other vendors provide equivalent functionality. > > At the same time it is hard (impossible) to predict what information future > impelementations will need to provide. So I wonder if we would be better > making the API generic by using the virTypedParameters design. eg > > virDomaniGetLaunchSecurityInfo(virDOmaniPtr domain, > virTypedParametersPtr *params, > unsigned int *nparams, > unsigned int flags); > > And then to start with we could just define a single named parameter > > #define VIR_DOMAIN_LAUNCH_SECURITY_SEV_MEASUREMENT "sev-measurement" > > Sure, I am all for making it generic. Will take your suggestions. thanks >> 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; > > Since we're in freeze for 4.1.0, it is going to be 4.2.0 at the earliest now. > Understood >> 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")); > > Hehe, unreachable code due to inverted order :-) Damn... will fix in next rev. > >> + } >> + >> + 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; >> +} > > Regards, > Daniel > -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
© 2016 - 2025 Red Hat, Inc.