Set a launch secret in guest memory using the sev-inject-launch-secret QMP API. Only supported for SEV-enabled guests. Signed-off-by: Jim Fehlig <jfehlig@xxxxxxxx> --- src/qemu/qemu_driver.c | 78 ++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor.c | 12 ++++++ src/qemu/qemu_monitor.h | 6 +++ src/qemu/qemu_monitor_json.c | 34 ++++++++++++++++ src/qemu/qemu_monitor_json.h | 5 +++ 5 files changed, 135 insertions(+) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 4e680bc0a7..b6ee41b29e 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -20056,6 +20056,83 @@ 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; + size_t i; + g_autofree char *secrethdr = NULL; + g_autofree char *secret = NULL; + long long setaddr = -1; + + 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_LLONG, + 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.l; + } + + if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0) + goto cleanup; + + if (virDomainObjCheckActive(vm) < 0) + goto endjob; + + qemuDomainObjEnterMonitor(driver, vm); + + if (qemuMonitorSetLaunchSecurityState(QEMU_DOMAIN_PRIVATE(vm)->mon, + secrethdr, secret, setaddr) < 0) + goto endjob; + + if (qemuDomainObjExitMonitor(driver, vm) < 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 | @@ -20930,6 +21007,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 26b59801b8..7f31a53231 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4372,6 +4372,18 @@ qemuMonitorGetSEVMeasurement(qemuMonitor *mon) } +int +qemuMonitorSetLaunchSecurityState(qemuMonitor *mon, + const char *secrethdr, + const char *secret, + long long injectaddr) +{ + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONSetLaunchSecurityState(mon, secrethdr, secret, injectaddr); +} + + int qemuMonitorGetPRManagerInfo(qemuMonitor *mon, GHashTable **retinfo) diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 99ecebc648..c485e403fd 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1444,6 +1444,12 @@ int qemuMonitorBlockdevMediumInsert(qemuMonitor *mon, char * qemuMonitorGetSEVMeasurement(qemuMonitor *mon); +int +qemuMonitorSetLaunchSecurityState(qemuMonitor *mon, + const char *secrethdr, + const char *secret, + long long injectaddr); + 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 56f0b22b2a..35aea34b5f 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -8174,6 +8174,40 @@ qemuMonitorJSONGetSEVMeasurement(qemuMonitor *mon) } +/** + * The function is used to inject a launch secret in an SEV guest. + * + * Example JSON: + * + * { "execute" : "sev-inject-launch-secret", + * "data": { "packet-header": "str", "secret": "str", "gpa": "uint64" } } + */ +int +qemuMonitorJSONSetLaunchSecurityState(qemuMonitor *mon, + const char *secrethdr, + const char *secret, + long long injectaddr) +{ + g_autoptr(virJSONValue) cmd = NULL; + g_autoptr(virJSONValue) reply = NULL; + + if (!(cmd = qemuMonitorJSONMakeCommand("sev-inject-launch-secret", + "s:packet-header", secrethdr, + "s:secret", secret, + "U:gpa", injectaddr, + 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 f7fb13f56c..4d2d73c661 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -368,6 +368,11 @@ int qemuMonitorJSONSystemWakeup(qemuMonitor *mon); char *qemuMonitorJSONGetSEVMeasurement(qemuMonitor *mon); +int qemuMonitorJSONSetLaunchSecurityState(qemuMonitor *mon, + const char *secrethdr, + const char *secret, + long long injectaddr); + int qemuMonitorJSONGetVersion(qemuMonitor *mon, int *major, int *minor, -- 2.33.0