From: Akio Kakuno <fj3333bs@fujitsu.com> - Add ARM CCA support in domain capabilies XML schema. [Capability example] - Execution results of 'virsh domcapability" on qemu <domaincapabilities> ... <features> ... </sgx> <cca supported='yes'> <enum name='measurement-algo'> <value>sha256</value> <value>sha512</value> </enum> </cca> <hyperv supported='yes'> ... </features> </domaincapabilities> Signed-off-by: Kazuhiro Abe <fj1078ii@aa.jp.fujitsu.com> --- docs/formatdomaincaps.rst | 27 +++++++- src/conf/domain_capabilities.c | 48 ++++++++++++++ src/conf/domain_capabilities.h | 6 ++ src/libvirt_private.syms | 1 + src/qemu/qemu_capabilities.c | 29 +++++++++ src/qemu/qemu_monitor.c | 10 +++ src/qemu/qemu_monitor.h | 3 + src/qemu/qemu_monitor_json.c | 111 +++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 4 ++ 9 files changed, 238 insertions(+), 1 deletion(-) diff --git a/docs/formatdomaincaps.rst b/docs/formatdomaincaps.rst index 8b4f0ecff3..6d4f3a0092 100644 --- a/docs/formatdomaincaps.rst +++ b/docs/formatdomaincaps.rst @@ -735,6 +735,12 @@ capabilities. All features occur as children of the main ``features`` element. <section node='1' size='262144' unit='KiB'/> </sections> </sgx> + <cca supported='yes'> + <enum name='measurement-algo'> + <value>sha256</value> + <value>sha512</value> + </enum> + </cca> <hyperv supported='yes'> <enum name='features'> <value>relaxed</value> @@ -862,6 +868,24 @@ document store. In order to use SGX with libvirt have a look at `SGX in domain X ``sections`` The sections of the SGX enclave page cache (called EPC). +CCA capabilities +^^^^^^^^^^^^^^^^ + +Arm Confidential Compute Architecture (CCA) capabilities are exposed under the +``cca`` element. + +Arm CCA is a system solution comprised of hardware and software components that +maximizes the security of data on devices and in the cloud. +CCA enhances the virtualization capabilities of the platform by separating the +management of resources from access to those resources. + +For more details on the CCA feature, please follow resources in the CCA developer's +document store. In order to use CCA with libvirt have a look at `CCA in domain +XML <formatdomain.html#launch-security>`__ + +``measurement-algo`` + Options for the ``measurement-algo`` used to describe blob hashes. + Hyper-V Enlightenments ^^^^^^^^^^^^^^^^^^^^^^ @@ -882,4 +906,5 @@ The ``sectype`` enum corresponds to ``type`` attribute of ``<launchSecurity/>`` element as documented in `Launch Security <formatdomain.html#launch-security>`__. :since:`(Since 10.5.0)` For additional information on individual types, see sections above: `s390-pv capability`_ for -S390 PV, `SEV capabilities`_ for AMD SEV and/or AMD SEV-SNP. +S390 PV, `SEV capabilities`_ for AMD SEV and/or AMD SEV-SNP, `CCA capabilities`_ +for Arm CCA. diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c index f843124695..9af3bf544c 100644 --- a/src/conf/domain_capabilities.c +++ b/src/conf/domain_capabilities.c @@ -118,6 +118,25 @@ virDomainCapsFeatureHypervCopy(virDomainCapsFeatureHyperv *cap) } +void +virCCACapabilitiesFree(virCCACapability *cap) +{ + size_t i; + + if (!cap) + return; + + if (cap->nCcaMeasurementAlgo) + for (i = 0; i < cap->nCcaMeasurementAlgo; i++) + g_free(cap->ccaMeasurementAlgo[i]); + + if (cap->ccaMeasurementAlgo) + g_free(cap->ccaMeasurementAlgo); + + g_free(cap); +} + + static void virDomainCapsDispose(void *obj) { @@ -131,6 +150,7 @@ virDomainCapsDispose(void *obj) virCPUDefFree(caps->cpu.hostModel); virSEVCapabilitiesFree(caps->sev); virSGXCapabilitiesFree(caps->sgx); + virCCACapabilitiesFree(caps->cca); virDomainCapsFeatureHypervFree(caps->hyperv); values = &caps->os.loader.values; @@ -823,6 +843,33 @@ virDomainCapsFeatureSGXFormat(virBuffer *buf, virBufferAddLit(buf, "</sgx>\n"); } +static void +virDomainCapsFeatureCCAFormat(virBuffer *buf, + const virCCACapability *cca) +{ + size_t i; + + if (!cca) { + virBufferAddLit(buf, "<cca supported='no'/>\n"); + return; + } + + virBufferAddLit(buf, "<cca supported='yes'>\n"); + virBufferAdjustIndent(buf, 2); + + virBufferAddLit(buf, "<enum name='measurement-algo'>\n"); + virBufferAdjustIndent(buf, 2); + for (i = 0; i < cca->nCcaMeasurementAlgo; i++) { + virBufferAsprintf(buf, "<value>%s</value>\n", + cca->ccaMeasurementAlgo[i]); + } + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</enum>\n"); + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</cca>\n"); +} + static void virDomainCapsFeatureHypervFormat(virBuffer *buf, const virDomainCapsFeatureHyperv *hyperv) @@ -900,6 +947,7 @@ virDomainCapsFormatFeatures(const virDomainCaps *caps, virDomainCapsFeatureSEVFormat(&childBuf, caps->sev); virDomainCapsFeatureSGXFormat(&childBuf, caps->sgx); + virDomainCapsFeatureCCAFormat(&childBuf, caps->cca); virDomainCapsFeatureHypervFormat(&childBuf, caps->hyperv); virDomainCapsLaunchSecurityFormat(&childBuf, &caps->launchSecurity); diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h index 0ce68b44ef..ed73164f82 100644 --- a/src/conf/domain_capabilities.h +++ b/src/conf/domain_capabilities.h @@ -329,6 +329,7 @@ struct _virDomainCaps { virDomainCapsFeatureGIC gic; virSEVCapability *sev; virSGXCapability *sgx; + virCCACapability *cca; virDomainCapsFeatureHyperv *hyperv; virDomainCapsLaunchSecurity launchSecurity; /* add new domain features here */ @@ -395,3 +396,8 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainCapsFeatureHyperv, virDomainCapsFeatureHy virDomainCapsFeatureHyperv * virDomainCapsFeatureHypervCopy(virDomainCapsFeatureHyperv *cap); + +void +virCCACapabilitiesFree(virCCACapability *capabilities); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCCACapability, virCCACapabilitiesFree); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 4e57e4a8f6..e9250dfbbb 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -208,6 +208,7 @@ virDomainAuditVcpu; # conf/domain_capabilities.h +virCCACapabilitiesFree; virDomainCapsCPUModelsAdd; virDomainCapsCPUModelsCopy; virDomainCapsCPUModelsGet; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 9a2eadb673..e152523850 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -3765,6 +3765,32 @@ virQEMUCapsProbeQMPSGXCapabilities(virQEMUCaps *qemuCaps, } +static int +virQEMUCapsProbeQMPCCACapabilities(virQEMUCaps *qemuCaps, + qemuMonitor *mon) +{ + int rc = -1; + virCCACapability *caps = NULL; + + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CCA_GUEST)) + return 0; + + if ((rc = qemuMonitorGetCCACapabilities(mon, &caps)) < 0) + return -1; + + /* CCA isn't actually supported */ + if (rc == 0) { + virQEMUCapsClear(qemuCaps, QEMU_CAPS_CCA_GUEST); + return 0; + } + + virCCACapabilitiesFree(qemuCaps->ccaCapabilities); + qemuCaps->ccaCapabilities = caps; + return 0; +} + + + /* * Filter for features which should never be passed to QEMU. Either because * QEMU never supported them or they were dropped as they never did anything @@ -5964,6 +5990,9 @@ virQEMUCapsInitQMPMonitor(virQEMUCaps *qemuCaps, return -1; if (virQEMUCapsProbeQMPSGXCapabilities(qemuCaps, mon) < 0) return -1; + if (virQEMUCapsProbeQMPCCACapabilities(qemuCaps, mon) < 0) + return -1; + virQEMUCapsProbeTDXCapabilities(qemuCaps); virQEMUCapsInitProcessCaps(qemuCaps); diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 504500c864..2da0b38b17 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -3571,6 +3571,16 @@ qemuMonitorGetSGXCapabilities(qemuMonitor *mon, } +int +qemuMonitorGetCCACapabilities(qemuMonitor *mon, + virCCACapability **capabilities) +{ + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONGetCCACapabilities(mon, capabilities); +} + + int qemuMonitorNBDServerStart(qemuMonitor *mon, const virStorageNetHostDef *server, diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index d096f474c1..5fb25b776f 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -969,6 +969,9 @@ int qemuMonitorSetMigrationParams(qemuMonitor *mon, virJSONValue **params); +int qemuMonitorGetCCACapabilities(qemuMonitor *mon, + virCCACapability **capabilities); + typedef enum { QEMU_MONITOR_MIGRATION_STATUS_INACTIVE, QEMU_MONITOR_MIGRATION_STATUS_SETUP, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index a602b1e65b..96fb83e738 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -6541,6 +6541,117 @@ qemuMonitorJSONGetSGXCapabilities(qemuMonitor *mon, } +static int +qemuMonitorJSONGetCCAMeasurementAlgo(qemuMonitor *mon, + size_t *numalgo, + char ***malgo) +{ + g_autoptr(virJSONValue) cmd = NULL; + g_autoptr(virJSONValue) reply = NULL; + virJSONValue *caps; + virJSONValue *section = NULL; + virJSONValue *malgolist = NULL; + g_auto(GStrv) list = NULL; + size_t i; + size_t n = 0; + + if (!(cmd = qemuMonitorJSONMakeCommand("query-rme-guest-capabilities", + NULL))) + return -1; + + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + return -1; + + /* If the 'query-rme-guest-capabilities' QMP command was not available + * we simply successfully return zero capabilities. + * This the case for QEMU < (CCA support version) and all non-ARM architectures. + * TODO: Replace (CCA support version) with the actual CCA support version upon merge. */ + if (qemuMonitorJSONHasError(reply, "CommandNotFound")) + return 0; + + if (qemuMonitorJSONHasError(reply, "GenericError")) + return 0; + + if (qemuMonitorJSONCheckError(cmd, reply) < 0) + return -1; + + if (!(caps = qemuMonitorJSONGetReply(cmd, reply, VIR_JSON_TYPE_OBJECT))) + return -1; + + if (!(section = virJSONValueObjectGetObject(caps, "section"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-rme-guest-capabilities reply was missing 'section' object")); + return -1; + } + + if (!(malgolist = virJSONValueObjectGetArray(section, "measurement-algorithms"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-rme-guest-capabilities reply was missing 'measurement-algorithms' array")); + return -1; + } + + n = virJSONValueArraySize(malgolist); + + /* If the received 'measurement-algorithms' array is empty, an error is returned. */ + if (n == 0) + return -1; + + list = g_new0(char *, n + 1); + + for (i = 0; i < n; i++) { + virJSONValue *algo = virJSONValueArrayGet(malgolist, i); + const char *measurement_algo = NULL; + + if (!algo || virJSONValueGetType(algo) != VIR_JSON_TYPE_STRING) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("measurement-algorithms entry was not in expected format")); + return -1; + } + + if (!(measurement_algo = virJSONValueGetString(algo))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to get measurement-algorithms string")); + return -1; + } + + list[i] = g_strdup(measurement_algo); + } + + *numalgo = n; + *malgo = g_steal_pointer(&list); + return 1; +} + + +/** + * qemuMonitorJSONGetCCACapabilities: + * @mon: qemu monitor object + * @capabilities: pointer to pointer to a CCA capability structure to be filled + * + * Returns -1 on error, 0 if CCA is not supported, and 1 if CCA is supported on + * the platform. + */ +int +qemuMonitorJSONGetCCACapabilities(qemuMonitor *mon, + virCCACapability **capabilities) +{ + g_autoptr(virCCACapability) capability = NULL; + int ret = 0; + + *capabilities = NULL; + capability = g_new0(virCCACapability, 1); + + ret = qemuMonitorJSONGetCCAMeasurementAlgo(mon, + &capability->nCcaMeasurementAlgo, + &capability->ccaMeasurementAlgo); + + if (ret > 0) + *capabilities = g_steal_pointer(&capability); + + return ret; +} + + static virJSONValue * qemuMonitorJSONBuildInetSocketAddress(const char *host, const char *port) diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index db9160eb68..6cf3778368 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -162,6 +162,10 @@ int qemuMonitorJSONGetSEVCapabilities(qemuMonitor *mon, virSEVCapability **capabilities); +int +qemuMonitorJSONGetCCACapabilities(qemuMonitor *mon, + virCCACapability **capabilities); + int qemuMonitorJSONMigrate(qemuMonitor *mon, unsigned int flags, -- 2.43.0