Set a launch secret in guest memory using the sev-inject-launch-secret QMP API. Only supported for SEV-enabled guests in a paused state. Signed-off-by: Jim Fehlig <jfehlig@xxxxxxxx> --- src/qemu/qemu_driver.c | 88 ++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor.c | 14 ++++++ src/qemu/qemu_monitor.h | 7 +++ src/qemu/qemu_monitor_json.c | 45 ++++++++++++++++++ src/qemu/qemu_monitor_json.h | 6 +++ 5 files changed, 160 insertions(+) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 8093b8f69b..b38a246d37 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -20042,6 +20042,93 @@ qemuDomainGetLaunchSecurityInfo(virDomainPtr domain, return ret; } + +static int +qemuDomainSetLaunchSecurityState(virDomainPtr domain, + virTypedParameterPtr params, + int nparams, + unsigned int flags) +{ + virQEMUDriver *driver = domain->conn->privateData; + virDomainObj *vm; + int ret = -1; + int rc; + size_t i; + g_autofree char *secrethdr = NULL; + g_autofree char *secret = NULL; + unsigned long long setaddr = 0; + bool hasSetaddr = false; + int state; + + virCheckFlags(0, -1); + if (virTypedParamsValidate(params, nparams, + VIR_DOMAIN_LAUNCH_SECURITY_SEV_SECRET_HEADER, + VIR_TYPED_PARAM_STRING, + VIR_DOMAIN_LAUNCH_SECURITY_SEV_SECRET, + VIR_TYPED_PARAM_STRING, + VIR_DOMAIN_LAUNCH_SECURITY_SEV_SECRET_SET_ADDRESS, + VIR_TYPED_PARAM_ULLONG, + NULL) < 0) + return -1; + + if (!(vm = qemuDomainObjFromDomain(domain))) + goto cleanup; + + if (virDomainSetLaunchSecurityStateEnsureACL(domain->conn, vm->def) < 0) + goto cleanup; + + /* Currently only SEV is supported */ + if (!vm->def->sec || + vm->def->sec->sectype != VIR_DOMAIN_LAUNCH_SECURITY_SEV) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("setting a launch secret is only supported in SEV-enabled domains")); + goto cleanup; + } + + for (i = 0; i < nparams; i++) { + virTypedParameterPtr param = ¶ms[i]; + + if (STREQ(param->field, VIR_DOMAIN_LAUNCH_SECURITY_SEV_SECRET_HEADER)) { + secrethdr = g_strdup(param->value.s); + } else if (STREQ(param->field, VIR_DOMAIN_LAUNCH_SECURITY_SEV_SECRET)) { + secret = g_strdup(param->value.s); + } else if (STREQ(param->field, VIR_DOMAIN_LAUNCH_SECURITY_SEV_SECRET_SET_ADDRESS)) { + setaddr = param->value.ul; + hasSetaddr = true; + } + } + + if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0) + goto cleanup; + + if (virDomainObjCheckActive(vm) < 0) + goto endjob; + + state = virDomainObjGetState(vm, NULL); + if (state != VIR_DOMAIN_PAUSED) { + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain must be in a paused state")); + goto endjob; + } + + qemuDomainObjEnterMonitor(driver, vm); + rc = qemuMonitorSetLaunchSecurityState(QEMU_DOMAIN_PRIVATE(vm)->mon, + secrethdr, secret, setaddr, hasSetaddr); + qemuDomainObjExitMonitor(driver, vm); + if (rc < 0) + goto endjob; + + ret = 0; + + endjob: + qemuDomainObjEndJob(driver, vm); + + cleanup: + virDomainObjEndAPI(&vm); + return ret; +} + + static const unsigned int qemuDomainGetGuestInfoSupportedTypes = VIR_DOMAIN_GUEST_INFO_USERS | VIR_DOMAIN_GUEST_INFO_OS | @@ -20915,6 +21002,7 @@ static virHypervisorDriver qemuHypervisorDriver = { .domainAuthorizedSSHKeysSet = qemuDomainAuthorizedSSHKeysSet, /* 6.10.0 */ .domainGetMessages = qemuDomainGetMessages, /* 7.1.0 */ .domainStartDirtyRateCalc = qemuDomainStartDirtyRateCalc, /* 7.2.0 */ + .domainSetLaunchSecurityState = qemuDomainSetLaunchSecurityState, /* 8.0.0 */ }; diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 75e0e4ed92..b1de6383f4 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4366,6 +4366,20 @@ qemuMonitorGetSEVMeasurement(qemuMonitor *mon) } +int +qemuMonitorSetLaunchSecurityState(qemuMonitor *mon, + const char *secrethdr, + const char *secret, + unsigned long long setaddr, + bool hasSetaddr) +{ + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONSetLaunchSecurityState(mon, secrethdr, secret, + setaddr, hasSetaddr); +} + + int qemuMonitorGetPRManagerInfo(qemuMonitor *mon, GHashTable **retinfo) diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index edc2b01a66..621d785d80 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1445,6 +1445,13 @@ int qemuMonitorBlockdevMediumInsert(qemuMonitor *mon, char * qemuMonitorGetSEVMeasurement(qemuMonitor *mon); +int +qemuMonitorSetLaunchSecurityState(qemuMonitor *mon, + const char *secrethdr, + const char *secret, + unsigned long long setaddr, + bool hasSetaddr); + 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 e00d785c20..f3efc3fe79 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -8216,6 +8216,51 @@ qemuMonitorJSONGetSEVMeasurement(qemuMonitor *mon) } +/** + * Set a launch secret in guest memory + * + * Example JSON: + * + * { "execute" : "sev-inject-launch-secret", + * "data": { "packet-header": "str", "secret": "str", "gpa": "uint64" } } + * + * The guest physical address (gpa) parameter is optional + */ +int +qemuMonitorJSONSetLaunchSecurityState(qemuMonitor *mon, + const char *secrethdr, + const char *secret, + unsigned long long setaddr, + bool hasSetaddr) +{ + g_autoptr(virJSONValue) cmd = NULL; + g_autoptr(virJSONValue) reply = NULL; + + if (hasSetaddr) { + cmd = qemuMonitorJSONMakeCommand("sev-inject-launch-secret", + "s:packet-header", secrethdr, + "s:secret", secret, + "U:gpa", setaddr, + NULL); + } else { + cmd = qemuMonitorJSONMakeCommand("sev-inject-launch-secret", + "s:packet-header", secrethdr, + "s:secret", secret, + NULL); + } + if (cmd == NULL) + return -1; + + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + return -1; + + if (qemuMonitorJSONCheckError(cmd, reply) < 0) + return -1; + + return 0; +} + + /* * Example return data * diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 0984717675..8b9d3a2a77 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -369,6 +369,12 @@ int qemuMonitorJSONSystemWakeup(qemuMonitor *mon); char *qemuMonitorJSONGetSEVMeasurement(qemuMonitor *mon); +int qemuMonitorJSONSetLaunchSecurityState(qemuMonitor *mon, + const char *secrethdr, + const char *secret, + unsigned long long setaddr, + bool hasSetaddr); + int qemuMonitorJSONGetVersion(qemuMonitor *mon, int *major, int *minor, -- 2.34.1