diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 56d94bb1bae288c58fe5b824b9e64632c97b9db1..920b6fae64e3559c785144c7fe1dade9bd4dd5d5 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -8765,6 +8765,11 @@ these security states. For more information see the Learn the architecture - Arm Confidential Compute Architecture software stack: ``__ +Some modern AMD processors support Secure Encrypted Virtualization with Secure +Nested Paging enhancement, also known as SEV-SNP. :since:`Since 10.5.0` To +enable it ```` should be used. It shares some +attributes and elements with ``type='sev'`` but differs in others. Example configuration: + :: @@ -8773,6 +8778,15 @@ Arm Confidential Compute Architecture software stack: sha256 ... + + 47 + 1 + 0x00030000 + ... + ... + ... + .../hostData> + ... @@ -8796,6 +8810,89 @@ The ```` element accepts the following attributes: The optional ``measurement-log`` element provides a way to create an event log in the format defined by the Trusted Computing Group for TPM2. +``kernelHashes`` + The optional ``kernelHashes`` attribute indicates whether the + hashes of the kernel, ramdisk and command line should be included + in the measurement done by the firmware. This is only valid if + using direct kernel boot. + +``authorKey`` + The optional ``authorKey`` attribute indicates whether ```` element + contains the 'AUTHOR_KEY' field defined SEV-SNP firmware ABI. + +``vcek`` + The optional ``vcek`` attribute indicates whether the guest is allowed to + chose between VLEK (Versioned Loaded Endorsement Key) or VCEK (Versioned + Chip Endorsement Key) when requesting attestation reports from firmware. + Set this to ``no`` to disable the use of VCEK. + +Aforementioned SEV-SNP firmware ABI can be found here: +``__ + +The ```` element then accepts the following child elements: + +``cbitpos`` + The required ``cbitpos`` element provides the C-bit (aka encryption bit) + location in guest page table entry. The value of ``cbitpos`` is hypervisor + dependent and can be obtained through the ``sev`` element from the domain + capabilities. +``reducedPhysBits`` + The required ``reducedPhysBits`` element provides the physical address bit + reduction. Similar to ``cbitpos`` the value of ``reduced-phys-bit`` is + hypervisor dependent and can be obtained through the ``sev`` element from the + domain capabilities. +``policy`` + The required ``policy`` element provides the guest policy which must be + maintained by the SEV-SNP firmware. This policy is enforced by the firmware + and restricts what configuration and operational commands can be performed + on this guest by the hypervisor. The guest policy provided during guest + launch is bound to the guest and cannot be changed throughout the lifetime + of the guest. The policy is also transmitted during snapshot and migration + flows and enforced on the destination platform. The guest policy is a 64bit + unsigned number with the fields shown in table (See section `4.3 Guest + Policy` in aforementioned firmware ABI specification): + + ====== ========================================================================================= + Bit(s) Description + ====== ========================================================================================= + 63:25 Reserved. Must be zero. + 24 Ciphertext hiding must be enabled when set, otherwise may be enabled or disabled. + 23 Running Average Power Limit (RAPL) must be disabled when set. + 22 Require AES 256 XTS for memory encryption when set, otherwise AES 128 XEX may be allowed. + 21 CXL can be populated with devices or memory when set. + 20 Guest can be activated only on one socket when set. + 19 Debugging is allowed when set. + 18 Association with a migration agent is allowed when set. + 17 Reserved. Must be set. + 16 SMT is allowed. + 15:8 The minimum ABI major version required for this guest to run. + 7:0 The minimum ABI minor version required for this guest to run. + ====== ========================================================================================= + + The default value is hypervisor dependant and QEMU defaults to value 0x30000 + meaning no minimum ABI major/minor version is required and SMT is allowed. + +``guestVisibleWorkarounds`` + The optional ``guestVisibleWorkarounds`` element is a 16-byte, + base64-encoded blob to report hypervisor-defined workarounds, corresponding + to the 'GOSVW' parameter of the SNP_LAUNCH_START command defined in the + SEV-SNP firmware ABI. + +``idBlock`` + The optional ``idBlock`` element is a 96-byte, base64-encoded blob to + provide the 'ID Block' structure for the SNP_LAUNCH_FINISH command defined + in the SEV-SNP firmware ABI. + +``idAuth`` + The optional ``idAuth`` element is a 4096-byte, base64-encoded blob to + provide the 'ID Authentication Information Structure' for the + SNP_LAUNCH_FINISH command defined in the SEV-SNP firmware ABI. + +``hostData`` + The optional ``hostData`` element is a 32-byte, base64-encoded, user-defined + blob to provide to the guest, as documented for the 'HOST_DATA' parameter of + the SNP_LAUNCH_FINISH command in the SEV-SNP firmware ABI. + Example configs =============== diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index a2549d001cab4282e0574c19d3816076fa3a66f6..2d8ec632c58e0097d48de51d18b3d71aac5e42c4 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -6330,6 +6330,16 @@ int virDomainSetLifecycleAction(virDomainPtr domain, */ # define VIR_DOMAIN_LAUNCH_SECURITY_SEV_POLICY "sev-policy" +/** + * VIR_DOMAIN_LAUNCH_SECURITY_SEV_SNP_POLICY: + * + * Macro represents the policy of the SEV-SNP guest, + * as VIR_TYPED_PARAM_ULLONG. + * + * Since: 10.5.0 + */ +# define VIR_DOMAIN_LAUNCH_SECURITY_SEV_SNP_POLICY "sev-snp-policy" + /** * VIR_DOMAIN_LAUNCH_SECURITY_SEV_SECRET_HEADER: * diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c index 02298e40a310aa0754e65800cdfa9c25a421a76b..aca9be7c835703e2c63fc4345932172252d872e6 100644 --- a/src/conf/capabilities.c +++ b/src/conf/capabilities.c @@ -688,10 +688,8 @@ virCapabilitiesDomainDataLookupInternal(virCaps *caps, if (domaintype > VIR_DOMAIN_VIRT_NONE) virBufferAsprintf(&buf, "domaintype=%s ", virDomainVirtTypeToString(domaintype)); - if (emulator) - virBufferEscapeString(&buf, "emulator=%s ", emulator); - if (machinetype) - virBufferEscapeString(&buf, "machine=%s ", machinetype); + virBufferEscapeString(&buf, "emulator=%s ", emulator); + virBufferEscapeString(&buf, "machine=%s ", machinetype); if (virBufferCurrentContent(&buf) && !virBufferCurrentContent(&buf)[0]) virBufferAsprintf(&buf, "%s", _("any configuration")); diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index e30ec0dca4c788669edf682c284337884a6c7aa1..fcc12e0955180995b232605429bfba93bfd1caf3 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1515,6 +1515,7 @@ VIR_ENUM_IMPL(virDomainLaunchSecurity, VIR_DOMAIN_LAUNCH_SECURITY_LAST, "", "sev", + "sev-snp", "s390-pv", "cvm", "cca", @@ -3827,7 +3828,7 @@ virDomainSecDefFree(virDomainSecDef *def) if (!def) return; - switch ((virDomainLaunchSecurity) def->sectype) { + switch (def->sectype) { case VIR_DOMAIN_LAUNCH_SECURITY_SEV: g_free(def->data.sev.dh_cert); g_free(def->data.sev.session); @@ -3835,6 +3836,12 @@ virDomainSecDefFree(virDomainSecDef *def) g_free(def->data.sev.secret_header); g_free(def->data.sev.secret); break; + case VIR_DOMAIN_LAUNCH_SECURITY_SEV_SNP: + g_free(def->data.sev_snp.guest_visible_workarounds); + g_free(def->data.sev_snp.id_block); + g_free(def->data.sev_snp.id_auth); + g_free(def->data.sev_snp.host_data); + break; case VIR_DOMAIN_LAUNCH_SECURITY_CCA: g_free(def->data.cca.measurement_algo); g_free(def->data.cca.personalization_value); @@ -5384,8 +5391,7 @@ virDomainDeviceInfoFormat(virBuffer *buf, if (rombar) virBufferAsprintf(buf, " bar='%s'", rombar); } - if (info->romfile) - virBufferEscapeString(buf, " file='%s'", info->romfile); + virBufferEscapeString(buf, " file='%s'", info->romfile); virBufferAddLit(buf, "/>\n"); } @@ -13533,8 +13539,8 @@ virDomainMemoryTargetDefParseXML(xmlNodePtr node, static int -virDomainSEVDefParseXML(virDomainSEVDef *def, - xmlXPathContextPtr ctxt) +virDomainSEVCommonDefParseXML(virDomainSEVCommonDef *def, + xmlXPathContextPtr ctxt) { int rc; @@ -13542,12 +13548,6 @@ virDomainSEVDefParseXML(virDomainSEVDef *def, &def->kernel_hashes) < 0) return -1; - if (virXPathUIntBase("string(./policy)", ctxt, 16, &def->policy) < 0) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("failed to get launch security policy")); - return -1; - } - /* the following attributes are platform dependent and if missing, we can * autofill them from domain capabilities later */ @@ -13570,6 +13570,23 @@ virDomainSEVDefParseXML(virDomainSEVDef *def, return -1; } + return 0; +} + + +static int +virDomainSEVDefParseXML(virDomainSEVDef *def, + xmlXPathContextPtr ctxt) +{ + if (virDomainSEVCommonDefParseXML(&def->common, ctxt) < 0) + return -1; + + if (virXPathUIntBase("string(./policy)", ctxt, 16, &def->policy) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("failed to get launch security policy")); + return -1; + } + def->dh_cert = virXPathString("string(./dhCert)", ctxt); def->session = virXPathString("string(./session)", ctxt); def->user_id = virXPathString("string(./userid)", ctxt); @@ -13579,6 +13596,34 @@ virDomainSEVDefParseXML(virDomainSEVDef *def, return 0; } +static int +virDomainSEVSNPDefParseXML(virDomainSEVSNPDef *def, + xmlXPathContextPtr ctxt) +{ + if (virDomainSEVCommonDefParseXML(&def->common, ctxt) < 0) + return -1; + + if (virXMLPropTristateBool(ctxt->node, "authorKey", VIR_XML_PROP_NONE, + &def->author_key) < 0) + return -1; + + if (virXMLPropTristateBool(ctxt->node, "vcek", VIR_XML_PROP_NONE, + &def->vcek) < 0) + return -1; + + if (virXPathULongLongBase("string(./policy)", ctxt, 16, &def->policy) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("failed to get launch security policy")); + return -1; + } + + def->guest_visible_workarounds = virXPathString("string(./guestVisibleWorkarounds)", ctxt); + def->id_block = virXPathString("string(./idBlock)", ctxt); + def->id_auth = virXPathString("string(./idAuth)", ctxt); + def->host_data = virXPathString("string(./hostData)", ctxt); + + return 0; +} static int virDomainCCADefParseXML(virDomainCCADef *def, @@ -13609,11 +13654,15 @@ virDomainSecDefParseXML(xmlNodePtr lsecNode, &sec->sectype) < 0) return NULL; - switch ((virDomainLaunchSecurity) sec->sectype) { + switch (sec->sectype) { case VIR_DOMAIN_LAUNCH_SECURITY_SEV: if (virDomainSEVDefParseXML(&sec->data.sev, ctxt) < 0) return NULL; break; + case VIR_DOMAIN_LAUNCH_SECURITY_SEV_SNP: + if (virDomainSEVSNPDefParseXML(&sec->data.sev_snp, ctxt) < 0) + return NULL; + break; case VIR_DOMAIN_LAUNCH_SECURITY_PV: case VIR_DOMAIN_LAUNCH_SECURITY_CVM: break; @@ -18350,7 +18399,7 @@ virDomainMemorytuneDefParseMemory(xmlXPathContextPtr ctxt, if (virXMLPropUIntDefault(node, "min_bandwidth", 10, VIR_XML_PROP_NONE, &min_bandwidth, UINT_MAX) < 0) return -1; - + if (min_bandwidth != UINT_MAX && virResctrlAllocSetMemoryBandwidth(alloc, VIR_MEMORY_TYPE_MIN_BANDWIDTH, id, min_bandwidth) < 0) return -1; @@ -22293,8 +22342,7 @@ virSecurityDeviceLabelDefFormat(virBuffer *buf, virBufferAddLit(buf, "model) - virBufferEscapeString(buf, " model='%s'", def->model); + virBufferEscapeString(buf, " model='%s'", def->model); if (def->labelskip) virBufferAddLit(buf, " labelskip='yes'"); @@ -22489,8 +22537,7 @@ virDomainDiskSourceFormatNetwork(virBuffer *attrBuf, virBufferAsprintf(childBuf, "\n", src->timeout); if (src->protocol == VIR_STORAGE_NET_PROTOCOL_SSH) { - if (src->ssh_known_hosts_file) - virBufferEscapeString(childBuf, "\n", src->ssh_known_hosts_file); + virBufferEscapeString(childBuf, "\n", src->ssh_known_hosts_file); if (src->ssh_keyfile || src->ssh_agent) { virBufferAddLit(childBuf, "idx); - if (model) - virBufferEscapeString(&attrBuf, " model='%s'", model); + virBufferEscapeString(&attrBuf, " model='%s'", model); switch (def->type) { case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL: @@ -24678,8 +24724,7 @@ virDomainChrTargetDefFormat(virBuffer *buf, case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_XEN: case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO: - if (def->target.name) - virBufferEscapeString(buf, " name='%s'", def->target.name); + virBufferEscapeString(buf, " name='%s'", def->target.name); if (def->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO && def->state != VIR_DOMAIN_CHR_DEVICE_STATE_DEFAULT && @@ -26086,9 +26131,8 @@ virDomainGraphicsDefFormat(virBuffer *buf, break; } - if (def->data.vnc.keymap) - virBufferEscapeString(buf, " keymap='%s'", - def->data.vnc.keymap); + virBufferEscapeString(buf, " keymap='%s'", + def->data.vnc.keymap); if (def->data.vnc.sharePolicy) virBufferAsprintf(buf, " sharePolicy='%s'", @@ -26103,13 +26147,11 @@ virDomainGraphicsDefFormat(virBuffer *buf, break; case VIR_DOMAIN_GRAPHICS_TYPE_SDL: - if (def->data.sdl.display) - virBufferEscapeString(buf, " display='%s'", - def->data.sdl.display); + virBufferEscapeString(buf, " display='%s'", + def->data.sdl.display); - if (def->data.sdl.xauth) - virBufferEscapeString(buf, " xauth='%s'", - def->data.sdl.xauth); + virBufferEscapeString(buf, " xauth='%s'", + def->data.sdl.xauth); if (def->data.sdl.fullscreen) virBufferAddLit(buf, " fullscreen='yes'"); @@ -26148,9 +26190,8 @@ virDomainGraphicsDefFormat(virBuffer *buf, break; case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP: - if (def->data.desktop.display) - virBufferEscapeString(buf, " display='%s'", - def->data.desktop.display); + virBufferEscapeString(buf, " display='%s'", + def->data.desktop.display); if (def->data.desktop.fullscreen) virBufferAddLit(buf, " fullscreen='yes'"); @@ -26203,9 +26244,8 @@ virDomainGraphicsDefFormat(virBuffer *buf, break; } - if (def->data.spice.keymap) - virBufferEscapeString(buf, " keymap='%s'", - def->data.spice.keymap); + virBufferEscapeString(buf, " keymap='%s'", + def->data.spice.keymap); if (def->data.spice.defaultMode != VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY) virBufferAsprintf(buf, " defaultMode='%s'", @@ -26582,11 +26622,9 @@ virDomainResourceDefFormat(virBuffer *buf, if (!def) return; - if (def->partition) - virBufferEscapeString(&childBuf, "%s\n", def->partition); + virBufferEscapeString(&childBuf, "%s\n", def->partition); - if (def->appid) - virBufferEscapeString(&childBuf, "\n", def->appid); + virBufferEscapeString(&childBuf, "\n", def->appid); virXMLFormatElement(buf, "resource", NULL, &childBuf); } @@ -26732,6 +26770,73 @@ virDomainKeyWrapDefFormat(virBuffer *buf, virDomainKeyWrapDef *keywrap) } +static void +virDomainSEVCommonDefFormat(virBuffer *attrBuf, + virBuffer *childBuf, + virDomainSEVCommonDef *def) +{ + if (def->kernel_hashes != VIR_TRISTATE_BOOL_ABSENT) + virBufferAsprintf(attrBuf, " kernelHashes='%s'", + virTristateBoolTypeToString(def->kernel_hashes)); + + if (def->haveCbitpos) + virBufferAsprintf(childBuf, "%d\n", def->cbitpos); + + if (def->haveReducedPhysBits) + virBufferAsprintf(childBuf, "%d\n", + def->reduced_phys_bits); +} + + +static void +virDomainSEVDefFormat(virBuffer *attrBuf, + virBuffer *childBuf, + virDomainSEVDef *def) +{ + virDomainSEVCommonDefFormat(attrBuf, childBuf, &def->common); + + virBufferAsprintf(childBuf, "0x%04x\n", def->policy); + virBufferEscapeString(childBuf, "%s\n", def->dh_cert); + virBufferEscapeString(childBuf, "%s\n", def->session); + if (def->user_id) + virBufferEscapeString(childBuf, "%s\n", def->user_id); + if (def->secret_header) + virBufferEscapeString(childBuf, "%s\n", + def->secret_header); + if (def->secret) + virBufferEscapeString(childBuf, "%s\n", def->secret); + +} + + +static void +virDomainSEVSNPDefFormat(virBuffer *attrBuf, + virBuffer *childBuf, + virDomainSEVSNPDef *def) +{ + virDomainSEVCommonDefFormat(attrBuf, childBuf, &def->common); + + if (def->author_key != VIR_TRISTATE_BOOL_ABSENT) { + virBufferAsprintf(attrBuf, " authorKey='%s'", + virTristateBoolTypeToString(def->author_key)); + } + + if (def->vcek != VIR_TRISTATE_BOOL_ABSENT) { + virBufferAsprintf(attrBuf, " vcek='%s'", + virTristateBoolTypeToString(def->vcek)); + } + + virBufferAsprintf(childBuf, "0x%08llx\n", def->policy); + + virBufferEscapeString(childBuf, + "%s\n", + def->guest_visible_workarounds); + virBufferEscapeString(childBuf, "%s\n", def->id_block); + virBufferEscapeString(childBuf, "%s\n", def->id_auth); + virBufferEscapeString(childBuf, "%s\n", def->host_data); +} + + static void virDomainSecDefFormat(virBuffer *buf, virDomainSecDef *sec) { @@ -26744,36 +26849,14 @@ virDomainSecDefFormat(virBuffer *buf, virDomainSecDef *sec) virBufferAsprintf(&attrBuf, " type='%s'", virDomainLaunchSecurityTypeToString(sec->sectype)); - switch ((virDomainLaunchSecurity) sec->sectype) { - case VIR_DOMAIN_LAUNCH_SECURITY_SEV: { - virDomainSEVDef *sev = &sec->data.sev; - - if (sev->kernel_hashes != VIR_TRISTATE_BOOL_ABSENT) - virBufferAsprintf(&attrBuf, " kernelHashes='%s'", - virTristateBoolTypeToString(sev->kernel_hashes)); - - if (sev->haveCbitpos) - virBufferAsprintf(&childBuf, "%d\n", sev->cbitpos); - - if (sev->haveReducedPhysBits) - virBufferAsprintf(&childBuf, "%d\n", - sev->reduced_phys_bits); - virBufferAsprintf(&childBuf, "0x%04x\n", sev->policy); - if (sev->dh_cert) - virBufferEscapeString(&childBuf, "%s\n", sev->dh_cert); - - if (sev->session) - virBufferEscapeString(&childBuf, "%s\n", sev->session); - - if (sev->user_id) - virBufferEscapeString(&childBuf, "%s\n", sev->user_id); - if (sev->secret_header) - virBufferEscapeString(&childBuf, "%s\n", sev->secret_header); - if (sev->secret) - virBufferEscapeString(&childBuf, "%s\n", sev->secret); + switch (sec->sectype) { + case VIR_DOMAIN_LAUNCH_SECURITY_SEV: + virDomainSEVDefFormat(&attrBuf, &childBuf, &sec->data.sev); + break; + case VIR_DOMAIN_LAUNCH_SECURITY_SEV_SNP: + virDomainSEVSNPDefFormat(&attrBuf, &childBuf, &sec->data.sev_snp); break; - } case VIR_DOMAIN_LAUNCH_SECURITY_PV: case VIR_DOMAIN_LAUNCH_SECURITY_CVM: @@ -28020,9 +28103,8 @@ virDomainDefFormatInternalSetRootName(virDomainDef *def, for (i = 0; def->os.initenv && def->os.initenv[i]; i++) virBufferAsprintf(buf, "%s\n", def->os.initenv[i]->name, def->os.initenv[i]->value); - if (def->os.initdir) - virBufferEscapeString(buf, "%s\n", - def->os.initdir); + virBufferEscapeString(buf, "%s\n", + def->os.initdir); if (def->os.inituser) virBufferAsprintf(buf, "%s\n", def->os.inituser); if (def->os.initgroup) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index cadca3324651092a3ef70101248c5afb272dde4e..7b2c932a18fba84c3d57e1e5ea0435f8f0d7f959 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2859,6 +2859,7 @@ struct _virDomainKeyWrapDef { typedef enum { VIR_DOMAIN_LAUNCH_SECURITY_NONE, VIR_DOMAIN_LAUNCH_SECURITY_SEV, + VIR_DOMAIN_LAUNCH_SECURITY_SEV_SNP, VIR_DOMAIN_LAUNCH_SECURITY_PV, VIR_DOMAIN_LAUNCH_SECURITY_CVM, VIR_DOMAIN_LAUNCH_SECURITY_CCA, @@ -2867,15 +2868,19 @@ typedef enum { } virDomainLaunchSecurity; -struct _virDomainSEVDef { - char *dh_cert; - char *session; - unsigned int policy; +struct _virDomainSEVCommonDef { bool haveCbitpos; unsigned int cbitpos; bool haveReducedPhysBits; unsigned int reduced_phys_bits; virTristateBool kernel_hashes; +}; + +struct _virDomainSEVDef { + virDomainSEVCommonDef common; + char *dh_cert; + char *session; + unsigned int policy; char *user_id; char *secret_header; char *secret; @@ -2887,10 +2892,23 @@ struct _virDomainCCADef { virTristateBool measurement_log; }; +struct _virDomainSEVSNPDef { + virDomainSEVCommonDef common; + unsigned long long policy; + char *guest_visible_workarounds; + char *id_block; + char *id_auth; + char *host_data; + virTristateBool author_key; + virTristateBool vcek; +}; + + struct _virDomainSecDef { virDomainLaunchSecurity sectype; union { virDomainSEVDef sev; + virDomainSEVSNPDef sev_snp; virDomainCCADef cca; } data; }; diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c index d88ef6b9152880717e05e72ac107108ddadaeaca..8f6f009f448a50791f7d722b36af81ca3880394b 100644 --- a/src/conf/domain_validate.c +++ b/src/conf/domain_validate.c @@ -1787,6 +1787,50 @@ virDomainDefValidateIOThreads(const virDomainDef *def) } +#define CHECK_BASE64_LEN(val, elemName, exp_len) \ +{ \ + size_t len; \ + g_autofree unsigned char *tmp = NULL; \ + if (val && (tmp = g_base64_decode(val, &len)) && len != exp_len) { \ + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, \ + _("Unexpected length of '%1$s', expected %2$u got %3$zu"), \ + elemName, exp_len, len); \ + return -1; \ + } \ +} + +static int +virDomainDefLaunchSecurityValidate(const virDomainDef *def) +{ + virDomainSEVSNPDef *sev_snp; + + if (!def->sec) + return 0; + + switch (def->sec->sectype) { + case VIR_DOMAIN_LAUNCH_SECURITY_SEV_SNP: + sev_snp = &def->sec->data.sev_snp; + + CHECK_BASE64_LEN(sev_snp->guest_visible_workarounds, "guestVisibleWorkarounds", 16); + CHECK_BASE64_LEN(sev_snp->id_block, "idBlock", 96); + CHECK_BASE64_LEN(sev_snp->id_auth, "idAuth", 4096); + CHECK_BASE64_LEN(sev_snp->host_data, "hostData", 32); + break; + + case VIR_DOMAIN_LAUNCH_SECURITY_NONE: + case VIR_DOMAIN_LAUNCH_SECURITY_SEV: + case VIR_DOMAIN_LAUNCH_SECURITY_PV: + case VIR_DOMAIN_LAUNCH_SECURITY_CVM: + case VIR_DOMAIN_LAUNCH_SECURITY_CCA: + case VIR_DOMAIN_LAUNCH_SECURITY_LAST: + break; + } + + return 0; +} + +#undef CHECK_BASE64_LEN + static int virDomainDefValidateInternal(const virDomainDef *def, virDomainXMLOption *xmlopt) @@ -1842,6 +1886,9 @@ virDomainDefValidateInternal(const virDomainDef *def, if (virDomainDefValidateIOThreads(def) < 0) return -1; + if (virDomainDefLaunchSecurityValidate(def) < 0) + return -1; + return 0; } diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index 0449b6f07c7325650d336df63e5c0add0928530a..cc8956af538c44e37f23c8ea34e517c9a12a8b85 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -2043,10 +2043,8 @@ virNetworkDNSDefFormat(virBuffer *buf, def->srvs[i].service); virBufferEscapeString(buf, "protocol='%s'", def->srvs[i].protocol); - if (def->srvs[i].domain) - virBufferEscapeString(buf, " domain='%s'", def->srvs[i].domain); - if (def->srvs[i].target) - virBufferEscapeString(buf, " target='%s'", def->srvs[i].target); + virBufferEscapeString(buf, " domain='%s'", def->srvs[i].domain); + virBufferEscapeString(buf, " target='%s'", def->srvs[i].target); if (def->srvs[i].port) virBufferAsprintf(buf, " port='%d'", def->srvs[i].port); if (def->srvs[i].priority) diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index f722ab37c60a60998f62fa5fa0a7f67cbac1e395..6c78c9a263381c27bcae540bf9f84cd2949a8b56 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -176,20 +176,16 @@ virNodeDeviceCapSystemDefFormat(virBuffer *buf, { char uuidstr[VIR_UUID_STRING_BUFLEN]; - if (data->system.product_name) - virBufferEscapeString(buf, "%s\n", - data->system.product_name); + virBufferEscapeString(buf, "%s\n", + data->system.product_name); virBufferAddLit(buf, "\n"); virBufferAdjustIndent(buf, 2); - if (data->system.hardware.vendor_name) - virBufferEscapeString(buf, "%s\n", - data->system.hardware.vendor_name); - if (data->system.hardware.version) - virBufferEscapeString(buf, "%s\n", - data->system.hardware.version); - if (data->system.hardware.serial) - virBufferEscapeString(buf, "%s\n", - data->system.hardware.serial); + virBufferEscapeString(buf, "%s\n", + data->system.hardware.vendor_name); + virBufferEscapeString(buf, "%s\n", + data->system.hardware.version); + virBufferEscapeString(buf, "%s\n", + data->system.hardware.serial); virUUIDFormat(data->system.hardware.uuid, uuidstr); virBufferAsprintf(buf, "%s\n", uuidstr); virBufferAdjustIndent(buf, -2); @@ -197,15 +193,12 @@ virNodeDeviceCapSystemDefFormat(virBuffer *buf, virBufferAddLit(buf, "\n"); virBufferAdjustIndent(buf, 2); - if (data->system.firmware.vendor_name) - virBufferEscapeString(buf, "%s\n", - data->system.firmware.vendor_name); - if (data->system.firmware.version) - virBufferEscapeString(buf, "%s\n", - data->system.firmware.version); - if (data->system.firmware.release_date) - virBufferEscapeString(buf, "%s\n", - data->system.firmware.release_date); + virBufferEscapeString(buf, "%s\n", + data->system.firmware.vendor_name); + virBufferEscapeString(buf, "%s\n", + data->system.firmware.version); + virBufferEscapeString(buf, "%s\n", + data->system.firmware.release_date); virBufferAdjustIndent(buf, -2); virBufferAddLit(buf, "\n"); } @@ -225,9 +218,8 @@ virNodeDeviceCapMdevTypesFormat(virBuffer *buf, virMediatedDeviceType *type = mdev_types[i]; virBufferEscapeString(buf, "\n", type->id); virBufferAdjustIndent(buf, 2); - if (type->name) - virBufferEscapeString(buf, "%s\n", - type->name); + virBufferEscapeString(buf, "%s\n", + type->name); virBufferEscapeString(buf, "%s\n", type->device_api); virBufferAsprintf(buf, @@ -451,10 +443,9 @@ virNodeDeviceCapUSBInterfaceDefFormat(virBuffer *buf, data->usb_if.subclass); virBufferAsprintf(buf, "%d\n", data->usb_if.protocol); - if (data->usb_if.description) - virBufferEscapeString(buf, - "%s\n", - data->usb_if.description); + virBufferEscapeString(buf, + "%s\n", + data->usb_if.description); } @@ -466,9 +457,8 @@ virNodeDeviceCapNetDefFormat(virBuffer *buf, virBufferEscapeString(buf, "%s\n", data->net.ifname); - if (data->net.address) - virBufferEscapeString(buf, "
%s
\n", - data->net.address); + virBufferEscapeString(buf, "
%s
\n", + data->net.address); virInterfaceLinkFormat(buf, &data->net.lnk); if (data->net.features) { for (i = 0; i < VIR_NET_DEV_FEAT_LAST; i++) { @@ -530,9 +520,8 @@ virNodeDeviceCapSCSIDefFormat(virBuffer *buf, virBufferAsprintf(buf, "%d\n", data->scsi.target); virBufferAsprintf(buf, "%d\n", data->scsi.lun); - if (data->scsi.type) - virBufferEscapeString(buf, "%s\n", - data->scsi.type); + virBufferEscapeString(buf, "%s\n", + data->scsi.type); } diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index 78773f744b35127b18cee430ff8e69ede2cd5e1b..8376da100dd7932670c371fc1da5d627551edf4d 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -515,6 +515,9 @@ + + + s390-pv @@ -527,6 +530,19 @@ + + + + + + + + + + + + + sev @@ -537,16 +553,7 @@ - - - - - - - - - - + @@ -574,6 +581,52 @@ + + + sev-snp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +