mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-26 14:03:49 +03:00
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:
parent
a26d99c2b1
commit
00f324bc3c
@ -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 = ¶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 |
|
||||
@ -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 */
|
||||
};
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user