qemu: Implement the virDomainSetLaunchSecurityState API

Set a launch secret in guest memory using the sev-inject-launch-secret
QMP API. Only supported with qemu >= 6.0.0 and SEV-enabled guests in a
paused state.

Signed-off-by: Jim Fehlig <jfehlig@suse.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
Jim Fehlig 2021-11-16 18:21:19 -07:00
parent a26d99c2b1
commit 00f324bc3c
6 changed files with 175 additions and 0 deletions

View File

@ -20083,6 +20083,105 @@ 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_autoptr(virQEMUCaps) qemucaps = NULL;
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;
}
if (!(qemucaps = virQEMUCapsCacheLookupDefault(driver->qemuCapsCache,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL)))
goto cleanup;
if (!virQEMUCapsGet(qemucaps, QEMU_CAPS_SEV_INJECT_LAUNCH_SECRET)) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
_("QEMU does not support setting a launch secret"));
goto cleanup;
}
for (i = 0; i < nparams; i++) {
virTypedParameterPtr param = &params[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 |
@ -20956,6 +21055,7 @@ static virHypervisorDriver qemuHypervisorDriver = {
.domainAuthorizedSSHKeysSet = qemuDomainAuthorizedSSHKeysSet, /* 6.10.0 */
.domainGetMessages = qemuDomainGetMessages, /* 7.1.0 */
.domainStartDirtyRateCalc = qemuDomainStartDirtyRateCalc, /* 7.2.0 */
.domainSetLaunchSecurityState = qemuDomainSetLaunchSecurityState, /* 8.0.0 */
};

View File

@ -4379,6 +4379,20 @@ qemuMonitorGetSEVInfo(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)

View File

@ -1457,6 +1457,13 @@ qemuMonitorGetSEVInfo(qemuMonitor *mon,
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5);
int
qemuMonitorSetLaunchSecurityState(qemuMonitor *mon,
const char *secrethdr,
const char *secret,
unsigned long long setaddr,
bool hasSetaddr);
typedef struct _qemuMonitorPRManagerInfo qemuMonitorPRManagerInfo;
struct _qemuMonitorPRManagerInfo {
bool connected;

View File

@ -8266,6 +8266,51 @@ qemuMonitorJSONGetSEVInfo(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
*

View File

@ -476,6 +476,12 @@ qemuMonitorJSONGetVersion(qemuMonitor *mon,
char **package)
ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4);
int qemuMonitorJSONSetLaunchSecurityState(qemuMonitor *mon,
const char *secrethdr,
const char *secret,
unsigned long long setaddr,
bool hasSetaddr);
int
qemuMonitorJSONGetMachines(qemuMonitor *mon,
qemuMonitorMachineInfo ***machines)

View File

@ -1196,6 +1196,8 @@ GEN_TEST_FUNC(qemuMonitorJSONSetAction,
QEMU_MONITOR_ACTION_REBOOT_RESET,
QEMU_MONITOR_ACTION_WATCHDOG_SHUTDOWN,
QEMU_MONITOR_ACTION_PANIC_SHUTDOWN)
GEN_TEST_FUNC(qemuMonitorJSONSetLaunchSecurityState, "sev_secret_header",
"sev_secret", 0, true)
static int
testQemuMonitorJSONqemuMonitorJSONNBDServerStart(const void *opaque)
@ -3067,6 +3069,7 @@ mymain(void)
DO_TEST_GEN(qemuMonitorJSONJobComplete);
DO_TEST_GEN(qemuMonitorJSONBlockJobCancel);
DO_TEST_GEN(qemuMonitorJSONSetAction);
DO_TEST_GEN(qemuMonitorJSONSetLaunchSecurityState);
DO_TEST(qemuMonitorJSONGetBalloonInfo);
DO_TEST(qemuMonitorJSONGetBlockInfo);
DO_TEST(qemuMonitorJSONGetAllBlockStatsInfo);