]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu: Implement the virDomainSetLaunchSecurityState API
authorJim Fehlig <jfehlig@suse.com>
Wed, 17 Nov 2021 01:21:19 +0000 (18:21 -0700)
committerJim Fehlig <jfehlig@suse.com>
Tue, 4 Jan 2022 17:56:00 +0000 (10:56 -0700)
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>
src/qemu/qemu_driver.c
src/qemu/qemu_monitor.c
src/qemu/qemu_monitor.h
src/qemu/qemu_monitor_json.c
src/qemu/qemu_monitor_json.h
tests/qemumonitorjsontest.c

index b8537a42603d1655d9b7a46d1c788e5505052564..7e8bd5f251f1a31f57107700134970ac4c87ed5f 100644 (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 */
 };
 
 
index dda6ae979693fd22a01a74588aeabe5bf134a176..5272d49c2ed432ea0658ccb9166b09ddaccb0a77 100644 (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)
index 850e01f02629cefdb19befa10da3f7d298831b5b..9b2e4e142148acb9a5d62a662a93a59c84596c12 100644 (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;
index e45b43eb5a31705d3f35aceb93b57051eaf01511..5bbd82e02299a326117134993ab40c04b15f24b8 100644 (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
  *
index e88dfc9d509d0a429d12df19125d579beb0f3855..64d9ebdaa3520799f5228af436abc515f10f92f3 100644 (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)
index 1b0bd0870df6850a4515fa40b77eb64a6888c1cc..48e2a457ab1fa19ab8976a0c23371b6c229368cd 100644 (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);