Get a SEV attestation report using the query-sev-attestation-report QMP API. Signed-off-by: Tyler Fanelli <tfanelli@xxxxxxxxxx> --- include/libvirt/libvirt-domain.h | 8 +++ src/driver-hypervisor.h | 4 +- src/qemu/qemu_driver.c | 86 ++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor.c | 11 ++++ src/qemu/qemu_monitor.h | 5 ++ src/qemu/qemu_monitor_json.c | 40 +++++++++++++++ src/qemu/qemu_monitor_json.h | 5 ++ 7 files changed, 157 insertions(+), 2 deletions(-) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index af8991dbd3..3f56da99cc 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -5175,6 +5175,14 @@ int virDomainSetLifecycleAction(virDomainPtr domain, */ # define VIR_DOMAIN_SEV_ATTESTATION_REPORT_MNONCE "mnonce" +/** + * VIR_DOMAIN_SEV_ATTESTATION_REPORT_DATA: + * + * A macro used to represent the returned SEV attestation report (encoded in + * base64). + */ +# define VIR_DOMAIN_SEV_ATTESTATION_REPORT_DATA "sev-attestation-report" + int virDomainGetLaunchSecurityInfo(virDomainPtr domain, virTypedParameterPtr *params, int *nparams, diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h index 568d8c9a26..8912e5d7ef 100644 --- a/src/driver-hypervisor.h +++ b/src/driver-hypervisor.h @@ -1350,8 +1350,8 @@ typedef int typedef int (*virDrvDomainGetSevAttestationReport)(virDomainPtr domain, - virTypedParameterPtr params, - int nparams, + virTypedParameterPtr *params_ptr, + int *nparams, unsigned int flags); typedef virDomainCheckpointPtr diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index b7e83c769a..a96a0b9f84 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -20123,6 +20123,91 @@ qemuDomainSetLaunchSecurityState(virDomainPtr domain, return ret; } +static int +qemuDomainGetSevAttestationReport(virDomainPtr domain, + virTypedParameterPtr *params, + int *nparams, + unsigned int flags) +{ + virQEMUDriver *driver; + virDomainObj *vm; + int ret = -1; + size_t i; + g_autofree char *mnonce = NULL; + g_autofree char *report = NULL; + int maxpar = 2; + g_autoptr(virQEMUCaps) qemucaps = NULL; + + driver = domain->conn->privateData; + + virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1); + if (virTypedParamsValidate(*params, *nparams, + VIR_DOMAIN_SEV_ATTESTATION_REPORT_MNONCE, + VIR_TYPED_PARAM_STRING, + NULL) < 0) + return -1; + + if (!(vm = qemuDomainObjFromDomain(domain))) + goto cleanup; + + if (virDomainGetSevAttestationReportEnsureACL(domain->conn, vm->def) < 0) + goto cleanup; + + /* SEV must be enabled to get an attestation report */ + if (!vm->def->sec || + vm->def->sec->sectype != VIR_DOMAIN_LAUNCH_SECURITY_SEV) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("attestation report is only supported in SEV-enabled domains")); + goto cleanup; + } + + if (!(qemucaps = virQEMUCapsCacheLookupDefault(driver->qemuCapsCache, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL))) + goto cleanup; + + + if (!virQEMUCapsGet(qemucaps, QEMU_CAPS_SEV_GET_ATTESTATION_REPORT)) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("QEMU does not support getting a SEV attestation report")); + goto cleanup; + } + + for (i = 0; i < *nparams; ++i) { + virTypedParameterPtr param = params[i]; + + if (STREQ(param->field, VIR_DOMAIN_SEV_ATTESTATION_REPORT_MNONCE)) + mnonce = g_strdup(param->value.s); + } + + if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0) + goto cleanup; + + if (virDomainObjCheckActive(vm) < 0) + goto endjob; + + qemuDomainObjEnterMonitor(driver, vm); + ret = qemuMonitorGetSevAttestationReport(QEMU_DOMAIN_PRIVATE(vm)->mon, + mnonce, + &report); + qemuDomainObjExitMonitor(vm); + if (ret < 0) + goto endjob; + + if (virTypedParamsAddString(params, nparams, &maxpar, + VIR_DOMAIN_SEV_ATTESTATION_REPORT_DATA, + report) < 0) + goto endjob; + + ret = 0; + +endjob: + qemuDomainObjEndJob(vm); + +cleanup: + virDomainObjEndAPI(&vm); + return ret; +} static const unsigned int qemuDomainGetGuestInfoSupportedTypes = VIR_DOMAIN_GUEST_INFO_USERS | @@ -21028,6 +21113,7 @@ static virHypervisorDriver qemuHypervisorDriver = { .domainGetMessages = qemuDomainGetMessages, /* 7.1.0 */ .domainStartDirtyRateCalc = qemuDomainStartDirtyRateCalc, /* 7.2.0 */ .domainSetLaunchSecurityState = qemuDomainSetLaunchSecurityState, /* 8.0.0 */ + .domainGetSevAttestationReport = qemuDomainGetSevAttestationReport, /* 8.1.0 */ }; diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 316cff5b9b..284e4a0b01 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4330,6 +4330,17 @@ qemuMonitorSetLaunchSecurityState(qemuMonitor *mon, } +int +qemuMonitorGetSevAttestationReport(qemuMonitor *mon, + const char *mnonce, + char **report) +{ + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONGetSevAttestationReport(mon, mnonce, report); +} + + int qemuMonitorGetPRManagerInfo(qemuMonitor *mon, GHashTable **retinfo) diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 5c2a749282..2e6fb8bfe0 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1447,6 +1447,11 @@ qemuMonitorSetLaunchSecurityState(qemuMonitor *mon, unsigned long long setaddr, bool hasSetaddr); +int +qemuMonitorGetSevAttestationReport(qemuMonitor *mon, + const char *mnonce, + char **report); + typedef struct _qemuMonitorPRManagerInfo qemuMonitorPRManagerInfo; struct _qemuMonitorPRManagerInfo { bool connected; diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index d5622bd6d9..45adf7a740 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -8322,6 +8322,46 @@ qemuMonitorJSONSetLaunchSecurityState(qemuMonitor *mon, return 0; } +/** + * Get a SEV attestation report + * + * Example JSON: + * + * {"execute" : "query-sev-attestation-report", + * "data" : { "mnonce": "str" } } + * {"return" : "data" : "mnonceNlSPUDlXPJG5966/8%YZ" } } + */ +int +qemuMonitorJSONGetSevAttestationReport(qemuMonitor *mon, + const char *mnonce, + char **report) +{ + const char *tmp; + g_autoptr(virJSONValue) cmd = NULL; + g_autoptr(virJSONValue) reply = NULL; + virJSONValue *data; + + cmd = qemuMonitorJSONMakeCommand("query-sev-attestation-report", + "s:mnonce", mnonce, + NULL); + if (cmd == NULL) + return -1; + + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + return -1; + + if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_OBJECT) < 0) + return -1; + + data = virJSONValueObjectGetObject(reply, "return"); + + if (!(tmp = virJSONValueObjectGetString(data, "data"))) + return -1; + + *report = g_strdup(tmp); + + return 0; +} /* * Example return data diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 982fbad44e..9a8e4ffd28 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -484,6 +484,11 @@ int qemuMonitorJSONSetLaunchSecurityState(qemuMonitor *mon, unsigned long long setaddr, bool hasSetaddr); +int +qemuMonitorJSONGetSevAttestationReport(qemuMonitor *mon, + const char *mnonce, + char **report); + int qemuMonitorJSONGetMachines(qemuMonitor *mon, qemuMonitorMachineInfo ***machines) -- 2.34.1