diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index eb1612b9d7..068c721d9f 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -19036,10 +19036,7 @@ qemuDomainGetSEVInfo(virDomainObj *vm, int ret = -1; int rv; g_autofree char *tmp = NULL; - unsigned int apiMajor = 0; - unsigned int apiMinor = 0; - unsigned int buildID = 0; - unsigned int policy = 0; + qemuMonitorSEVInfo info = { }; int maxpar = 0; virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1); @@ -19054,14 +19051,12 @@ qemuDomainGetSEVInfo(virDomainObj *vm, qemuDomainObjEnterMonitor(vm); tmp = qemuMonitorGetSEVMeasurement(QEMU_DOMAIN_PRIVATE(vm)->mon); - if (!tmp) { qemuDomainObjExitMonitor(vm); goto endjob; } - rv = qemuMonitorGetSEVInfo(QEMU_DOMAIN_PRIVATE(vm)->mon, - &apiMajor, &apiMinor, &buildID, &policy); + rv = qemuMonitorGetSEVInfo(QEMU_DOMAIN_PRIVATE(vm)->mon, &info); qemuDomainObjExitMonitor(vm); if (rv < 0) @@ -19073,21 +19068,30 @@ qemuDomainGetSEVInfo(virDomainObj *vm, goto endjob; if (virTypedParamsAddUInt(params, nparams, &maxpar, VIR_DOMAIN_LAUNCH_SECURITY_SEV_API_MAJOR, - apiMajor) < 0) + info.apiMajor) < 0) goto endjob; if (virTypedParamsAddUInt(params, nparams, &maxpar, VIR_DOMAIN_LAUNCH_SECURITY_SEV_API_MINOR, - apiMinor) < 0) + info.apiMinor) < 0) goto endjob; if (virTypedParamsAddUInt(params, nparams, &maxpar, VIR_DOMAIN_LAUNCH_SECURITY_SEV_BUILD_ID, - buildID) < 0) - goto endjob; - if (virTypedParamsAddUInt(params, nparams, &maxpar, - VIR_DOMAIN_LAUNCH_SECURITY_SEV_POLICY, - policy) < 0) + info.buildID) < 0) goto endjob; + switch (info.type) { + case QEMU_MONITOR_SEV_GUEST_TYPE_SEV: + if (virTypedParamsAddUInt(params, nparams, &maxpar, + VIR_DOMAIN_LAUNCH_SECURITY_SEV_POLICY, + info.data.sev.policy) < 0) + goto endjob; + break; + + case QEMU_MONITOR_SEV_GUEST_TYPE_SEV_SNP: + case QEMU_MONITOR_SEV_GUEST_TYPE_LAST: + break; + } + ret = 0; endjob: diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 34e2ccab97..b1c0c6a064 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4043,14 +4043,11 @@ qemuMonitorGetSEVMeasurement(qemuMonitor *mon) int qemuMonitorGetSEVInfo(qemuMonitor *mon, - unsigned int *apiMajor, - unsigned int *apiMinor, - unsigned int *buildID, - unsigned int *policy) + qemuMonitorSEVInfo *info) { QEMU_CHECK_MONITOR(mon); - return qemuMonitorJSONGetSEVInfo(mon, apiMajor, apiMinor, buildID, policy); + return qemuMonitorJSONGetSEVInfo(mon, info); } diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index b78f539c85..8dde3f9fff 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1334,14 +1334,43 @@ int qemuMonitorBlockdevMediumInsert(qemuMonitor *mon, char * qemuMonitorGetSEVMeasurement(qemuMonitor *mon); +typedef struct _qemuMonitorSEVGuestInfo qemuMonitorSEVGuestInfo; +struct _qemuMonitorSEVGuestInfo { + unsigned int policy; + unsigned int handle; +}; + +typedef struct _qemuMonitorSEVSNPGuestInfo qemuMonitorSEVSNPGuestInfo; +struct _qemuMonitorSEVSNPGuestInfo { + unsigned long long snp_policy; +}; + + +typedef enum { + QEMU_MONITOR_SEV_GUEST_TYPE_SEV, + QEMU_MONITOR_SEV_GUEST_TYPE_SEV_SNP, + + QEMU_MONITOR_SEV_GUEST_TYPE_LAST +} qemuMonitorSEVGuestType; + +VIR_ENUM_DECL(qemuMonitorSEVGuest); + +typedef struct _qemuMonitorSEVInfo qemuMonitorSEVInfo; +struct _qemuMonitorSEVInfo { + unsigned int apiMajor; + unsigned int apiMinor; + unsigned int buildID; + qemuMonitorSEVGuestType type; + union { + qemuMonitorSEVGuestInfo sev; + qemuMonitorSEVSNPGuestInfo sev_snp; + } data; +}; + int qemuMonitorGetSEVInfo(qemuMonitor *mon, - unsigned int *apiMajor, - unsigned int *apiMinor, - unsigned int *buildID, - unsigned int *policy) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) - ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5); + qemuMonitorSEVInfo *info) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); int qemuMonitorSetLaunchSecurityState(qemuMonitor *mon, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 8f8f3c95f0..89ea33a3ab 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -7971,6 +7971,10 @@ qemuMonitorJSONGetSEVMeasurement(qemuMonitor *mon) } +VIR_ENUM_IMPL(qemuMonitorSEVGuest, + QEMU_MONITOR_SEV_GUEST_TYPE_LAST, + "sev", "sev-snp"); + /** * Retrieve info about the SEV setup, returning those fields that * are required to do a launch attestation, as per @@ -7984,13 +7988,15 @@ qemuMonitorJSONGetSEVMeasurement(qemuMonitor *mon) * { "return": { "enabled": true, "api-major" : 0, "api-minor" : 0, * "build-id" : 0, "policy" : 0, "state" : "running", * "handle" : 1 } } + * + * Or newer (as of QEMU v9.0.0-1155-g59d3740cb4): + * + * {"return": {"enabled": true, "api-minor": 55, "handle": 1, "state": "launch-secret", + * "api-major": 1, "sev-type": "sev", "build-id": 21, "policy": 1}} */ int qemuMonitorJSONGetSEVInfo(qemuMonitor *mon, - unsigned int *apiMajor, - unsigned int *apiMinor, - unsigned int *buildID, - unsigned int *policy) + qemuMonitorSEVInfo *info) { g_autoptr(virJSONValue) cmd = NULL; g_autoptr(virJSONValue) reply = NULL; @@ -8005,16 +8011,51 @@ qemuMonitorJSONGetSEVInfo(qemuMonitor *mon, if (!(data = qemuMonitorJSONGetReply(cmd, reply, VIR_JSON_TYPE_OBJECT))) return -1; - if (virJSONValueObjectGetNumberUint(data, "api-major", apiMajor) < 0 || - virJSONValueObjectGetNumberUint(data, "api-minor", apiMinor) < 0 || - virJSONValueObjectGetNumberUint(data, "build-id", buildID) < 0 || - virJSONValueObjectGetNumberUint(data, "policy", policy) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("query-sev reply was missing some data")); - return -1; + if (virJSONValueObjectGetNumberUint(data, "api-major", &info->apiMajor) < 0 || + virJSONValueObjectGetNumberUint(data, "api-minor", &info->apiMinor) < 0 || + virJSONValueObjectGetNumberUint(data, "build-id", &info->buildID) < 0) { + goto error; + } + + if (virJSONValueObjectHasKey(data, "sev-type")) { + const char *sevTypeStr = virJSONValueObjectGetString(data, "sev-type"); + int sevType; + + if ((sevType = qemuMonitorSEVGuestTypeFromString(sevTypeStr)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown SEV type '%1$s'"), + sevTypeStr); + return -1; + } + + info->type = sevType; + } else { + info->type = QEMU_MONITOR_SEV_GUEST_TYPE_SEV; + } + + switch (info->type) { + case QEMU_MONITOR_SEV_GUEST_TYPE_SEV: + if (virJSONValueObjectGetNumberUint(data, "policy", &info->data.sev.policy) < 0 || + virJSONValueObjectGetNumberUint(data, "handle", &info->data.sev.handle) < 0) { + goto error; + } + break; + + case QEMU_MONITOR_SEV_GUEST_TYPE_SEV_SNP: + if (virJSONValueObjectGetNumberUlong(data, "snp-policy", &info->data.sev_snp.snp_policy) < 0) + goto error; + break; + + case QEMU_MONITOR_SEV_GUEST_TYPE_LAST: + break; } return 0; + + error: + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-sev reply was missing some data")); + return -1; } diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 9684660d86..921dd34ed2 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -417,12 +417,8 @@ qemuMonitorJSONGetSEVMeasurement(qemuMonitor *mon); int qemuMonitorJSONGetSEVInfo(qemuMonitor *mon, - unsigned int *apiMajor, - unsigned int *apiMinor, - unsigned int *buildID, - unsigned int *policy) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) - ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5); + qemuMonitorSEVInfo *info) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); int qemuMonitorJSONGetVersion(qemuMonitor *mon, diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c index 45cee23798..66d0c127ca 100644 --- a/tests/qemumonitorjsontest.c +++ b/tests/qemumonitorjsontest.c @@ -2730,10 +2730,7 @@ testQemuMonitorJSONGetSEVInfo(const void *opaque) const testGenericData *data = opaque; virDomainXMLOption *xmlopt = data->xmlopt; g_autoptr(qemuMonitorTest) test = NULL; - unsigned int apiMajor = 0; - unsigned int apiMinor = 0; - unsigned int buildID = 0; - unsigned int policy = 0; + qemuMonitorSEVInfo info = { }; if (!(test = qemuMonitorTestNewSchema(xmlopt, data->schema))) return -1; @@ -2753,16 +2750,70 @@ testQemuMonitorJSONGetSEVInfo(const void *opaque) "}") < 0) return -1; - if (qemuMonitorGetSEVInfo(qemuMonitorTestGetMonitor(test), - &apiMajor, &apiMinor, &buildID, &policy) < 0) + if (qemuMonitorGetSEVInfo(qemuMonitorTestGetMonitor(test), &info) < 0) return -1; - if (apiMajor != 1 || apiMinor != 8 || buildID != 834 || policy != 3) { + if (info.apiMajor != 1 || info.apiMinor != 8 || info.buildID != 834 || + info.type != QEMU_MONITOR_SEV_GUEST_TYPE_SEV || + info.data.sev.policy != 3 || info.data.sev.handle != 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", "Unexpected SEV info values"); return -1; } + if (qemuMonitorTestAddItem(test, "query-sev", + "{" + " \"return\": {" + " \"enabled\": true," + " \"api-minor\": 55," + " \"handle\": 1," + " \"state\": \"running\"," + " \"api-major\": 1," + " \"sev-type\": \"sev\"," + " \"build-id\": 21," + " \"policy\": 1" + " }," + " \"id\": \"libvirt-16\"" + "}") < 0) + return -1; + + if (qemuMonitorGetSEVInfo(qemuMonitorTestGetMonitor(test), &info) < 0) + return -1; + + if (info.apiMajor != 1 || info.apiMinor != 55 || info.buildID != 21 || + info.type != QEMU_MONITOR_SEV_GUEST_TYPE_SEV || + info.data.sev.policy != 1 || info.data.sev.handle != 1) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + "Unexpected SEV info values"); + return -1; + } + + if (qemuMonitorTestAddItem(test, "query-sev", + "{" + " \"return\": {" + " \"enabled\": true," + " \"api-minor\": 55," + " \"state\": \"running\"," + " \"api-major\": 1," + " \"sev-type\": \"sev-snp\"," + " \"build-id\": 21," + " \"snp-policy\": 196608" + " }," + " \"id\": \"libvirt-16\"" + "}") < 0) + return -1; + + if (qemuMonitorGetSEVInfo(qemuMonitorTestGetMonitor(test), &info) < 0) + return -1; + + if (info.apiMajor != 1 || info.apiMinor != 55 || info.buildID != 21 || + info.type != QEMU_MONITOR_SEV_GUEST_TYPE_SEV_SNP || + info.data.sev_snp.snp_policy != 0x30000) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + "Unexpected SEV SNP info values"); + return -1; + } + return 0; }