- 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: Akio Kakuno <fj3333bs@xxxxxxxxxxx> --- 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 | 28 ++++++++++ src/qemu/qemu_monitor.c | 10 ++++ src/qemu/qemu_monitor.h | 3 ++ src/qemu/qemu_monitor_json.c | 98 ++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 4 ++ 9 files changed, 224 insertions(+), 1 deletion(-) diff --git a/docs/formatdomaincaps.rst b/docs/formatdomaincaps.rst index ed95af4fee..fbf7db12e6 100644 --- a/docs/formatdomaincaps.rst +++ b/docs/formatdomaincaps.rst @@ -734,6 +734,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> @@ -861,6 +867,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 ab715b19d8..cae6730061 100644 --- a/src/conf/domain_capabilities.c +++ b/src/conf/domain_capabilities.c @@ -90,6 +90,25 @@ virSGXCapabilitiesFree(virSGXCapability *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) { @@ -103,6 +122,7 @@ virDomainCapsDispose(void *obj) virCPUDefFree(caps->cpu.hostModel); virSEVCapabilitiesFree(caps->sev); virSGXCapabilitiesFree(caps->sgx); + virCCACapabilitiesFree(caps->cca); g_free(caps->hyperv); values = &caps->os.loader.values; @@ -774,6 +794,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) @@ -821,6 +868,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 93e2cc2931..b55f860e7b 100644 --- a/src/conf/domain_capabilities.h +++ b/src/conf/domain_capabilities.h @@ -315,6 +315,7 @@ struct _virDomainCaps { virDomainCapsFeatureGIC gic; virSEVCapability *sev; virSGXCapability *sgx; + virCCACapability *cca; virDomainCapsFeatureHyperv *hyperv; virDomainCapsLaunchSecurity launchSecurity; /* add new domain features here */ @@ -375,3 +376,8 @@ void virSGXCapabilitiesFree(virSGXCapability *capabilities); G_DEFINE_AUTOPTR_CLEANUP_FUNC(virSGXCapability, virSGXCapabilitiesFree); + +void +virCCACapabilitiesFree(virCCACapability *capabilities); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCCACapability, virCCACapabilitiesFree); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 33b93cbd3e..bf525c50d9 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 b0283c0119..4534f18a24 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -3651,6 +3651,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 @@ -5757,6 +5783,8 @@ virQEMUCapsInitQMPMonitor(virQEMUCaps *qemuCaps, return -1; if (virQEMUCapsProbeQMPSGXCapabilities(qemuCaps, mon) < 0) return -1; + if (virQEMUCapsProbeQMPCCACapabilities(qemuCaps, mon) < 0) + return -1; virQEMUCapsInitProcessCaps(qemuCaps); diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index ec2f166785..53908d8bf8 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -3483,6 +3483,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 c74892c4dc..8a37376f97 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -846,6 +846,9 @@ int qemuMonitorGetSEVCapabilities(qemuMonitor *mon, int qemuMonitorGetSGXCapabilities(qemuMonitor *mon, virSGXCapability **capabilities); +int qemuMonitorGetCCACapabilities(qemuMonitor *mon, + virCCACapability **capabilities); + typedef enum { QEMU_MONITOR_MIGRATE_RESUME = 1 << 0, /* resume failed post-copy migration */ QEMU_MONITOR_MIGRATION_FLAGS_LAST diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 9f417d27c6..ebe5f87d36 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -6213,6 +6213,104 @@ 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 *malgolist = NULL; + g_auto(GStrv) list = NULL; + size_t i; + size_t n = 0; + + if (!(cmd = qemuMonitorJSONMakeCommand("query-cca-capabilities", + NULL))) + return -1; + + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + return -1; + + /* If the 'query-cca-capabilities' QMP command was not available + * we simply successfully return zero capabilities. + * This is the current QEMU (=9.1.91) and all non-ARM architectures */ + if (qemuMonitorJSONHasError(reply, "CommandNotFound")) + return 0; + + if (qemuMonitorJSONCheckError(cmd, reply) < 0) + return -1; + + caps = virJSONValueObjectGetObject(reply, "return"); + + if (!(caps = qemuMonitorJSONGetReply(cmd, reply, VIR_JSON_TYPE_OBJECT))) + return -1; + + if ((malgolist = virJSONValueObjectGetArray(caps, "sections"))) { + n = virJSONValueArraySize(malgolist); + + /* If the received 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 *cap = virJSONValueArrayGet(malgolist, i); + const char *measurement_algo = NULL; + + if (!cap || virJSONValueGetType(cap) != VIR_JSON_TYPE_OBJECT) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing entry in CCA capabilities list")); + return -1; + } + + if (!(measurement_algo = virJSONValueObjectGetString(cap, "measurement-algo"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-cca-capabilities reply was missing 'measurement-algo' field")); + 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 2f5a021f56..d422e84e88 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -168,6 +168,10 @@ int qemuMonitorJSONGetSEVCapabilities(qemuMonitor *mon, virSEVCapability **capabilities); +int +qemuMonitorJSONGetCCACapabilities(qemuMonitor *mon, + virCCACapability **capabilities); + int qemuMonitorJSONMigrate(qemuMonitor *mon, unsigned int flags, -- 2.34.1