From: Tony Krowiak <akrowiak@xxxxxxxxxxxxxxxxxx> Parse the domain configuration XML elements that enable/disable access to the protected key management operations for a guest: <domain> ... <keywrap> <cipher name='aes|dea' state='on|off'/> </keywrap> ... </domain> Signed-off-by: Tony Krowiak <akrowiak@xxxxxxxxxxxxxxxxxx> Signed-off-by: Viktor Mihajlovski <mihajlov@xxxxxxxxxxxxxxxxxx> Signed-off-by: Daniel Hansel <daniel.hansel@xxxxxxxxxxxxxxxxxx> Reviewed-by: Boris Fiuczynski <fiuczy@xxxxxxxxxxxxxxxxxx> Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx> --- src/conf/domain_conf.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 17 ++++++ src/libvirt_private.syms | 2 + 3 files changed, 175 insertions(+) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index f3b706e..ee8b474 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -477,6 +477,11 @@ VIR_ENUM_IMPL(virDomainSoundModel, VIR_DOMAIN_SOUND_MODEL_LAST, "ich9", "usb") +VIR_ENUM_IMPL(virDomainKeyWrapCipherName, + VIR_DOMAIN_KEY_WRAP_CIPHER_NAME_LAST, + "aes", + "dea") + VIR_ENUM_IMPL(virDomainMemballoonModel, VIR_DOMAIN_MEMBALLOON_MODEL_LAST, "virtio", "xen", @@ -834,6 +839,131 @@ virDomainXMLOptionClassDispose(void *obj) (xmlopt->config.privFree)(xmlopt->config.priv); } +/** + * virDomainKeyWrapCipherDefParseXML: + * + * @def Domain definition + * @node An XML cipher node + * @ctxt The XML context + * + * Parse the attributes from the cipher node and store the state + * attribute in @def. + * + * A cipher node has the form of + * + * <cipher name='aes|dea' state='on|off'/> + * + * Returns: 0 if the parse succeeded + * -1 otherwise + */ +static int +virDomainKeyWrapCipherDefParseXML(virDomainKeyWrapDefPtr keywrap, + xmlNodePtr node, + xmlXPathContextPtr ctxt) +{ + + char *name = NULL; + char *state = NULL; + int state_type; + int name_type; + int ret = -1; + xmlNodePtr oldnode = ctxt->node; + + ctxt->node = node; + if (!(name = virXPathString("string(./@name)", ctxt))) { + virReportError(VIR_ERR_CONF_SYNTAX, "%s", + _("missing name for cipher")); + goto cleanup; + } + + if ((name_type = virDomainKeyWrapCipherNameTypeFromString(name)) < 0) { + virReportError(VIR_ERR_CONF_SYNTAX, + _("%s is not a supported cipher name"), name); + goto cleanup; + } + + if (!(state = virXPathString("string(./@state)", ctxt))) { + virReportError(VIR_ERR_CONF_SYNTAX, + _("missing state for cipher named %s"), name); + goto cleanup; + } + + if ((state_type = virTristateSwitchTypeFromString(state)) < 0) { + virReportError(VIR_ERR_CONF_SYNTAX, + _("%s is not a supported cipher state"), state); + goto cleanup; + } + + switch ((virDomainKeyWrapCipherName) name_type) { + case VIR_DOMAIN_KEY_WRAP_CIPHER_NAME_AES: + if (keywrap->aes != VIR_TRISTATE_SWITCH_ABSENT) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("A domain definition can have no more than " + "one cipher node with name %s"), + virDomainKeyWrapCipherNameTypeToString(name_type)); + + goto cleanup; + } + keywrap->aes = state_type; + break; + + case VIR_DOMAIN_KEY_WRAP_CIPHER_NAME_DEA: + if (keywrap->dea != VIR_TRISTATE_SWITCH_ABSENT) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("A domain definition can have no more than " + "one cipher node with name %s"), + virDomainKeyWrapCipherNameTypeToString(name_type)); + + goto cleanup; + } + keywrap->dea = state_type; + break; + + case VIR_DOMAIN_KEY_WRAP_CIPHER_NAME_LAST: + break; + } + + ret = 0; + + cleanup: + VIR_FREE(name); + VIR_FREE(state); + ctxt->node = oldnode; + return ret; +} + +static int +virDomainKeyWrapDefParseXML(virDomainDefPtr def, xmlXPathContextPtr ctxt) +{ + size_t i; + int ret = -1; + xmlNodePtr *nodes = NULL; + int n; + + if (!(n = virXPathNodeSet("./keywrap/cipher", ctxt, &nodes))) + return 0; + + if (VIR_ALLOC(def->keywrap) < 0) + goto cleanup; + + for (i = 0; i < n; i++) { + if (virDomainKeyWrapCipherDefParseXML(def->keywrap, nodes[i], ctxt) < 0) + goto cleanup; + } + + if (!def->keywrap->aes && + !def->keywrap->dea) + VIR_FREE(def->keywrap); + + ret = 0; + + cleanup: + if (ret < 0) + VIR_FREE(def->keywrap); + VIR_FREE(nodes); + return ret; +} + /** * virDomainXMLOptionNew: @@ -2361,6 +2491,8 @@ void virDomainDefFree(virDomainDefPtr def) virDomainShmemDefFree(def->shmems[i]); VIR_FREE(def->shmems); + VIR_FREE(def->keywrap); + if (def->namespaceData && def->ns.free) (def->ns.free)(def->namespaceData); @@ -15535,6 +15667,9 @@ virDomainDefParseXML(xmlDocPtr xml, VIR_FREE(tmp); } + if (virDomainKeyWrapDefParseXML(def, ctxt) < 0) + goto error; + /* Extract custom metadata */ if ((node = virXPathNode("./metadata[1]", ctxt)) != NULL) def->metadata = xmlCopyNode(node, 1); @@ -20588,6 +20723,24 @@ virDomainLoaderDefFormat(virBufferPtr buf, } } +static void +virDomainKeyWrapDefFormat(virBufferPtr buf, virDomainKeyWrapDefPtr keywrap) +{ + virBufferAddLit(buf, "<keywrap>\n"); + virBufferAdjustIndent(buf, 2); + + if (keywrap->aes) + virBufferAsprintf(buf, "<cipher name='aes' state='%s'/>\n", + virTristateSwitchTypeToString(keywrap->aes)); + + if (keywrap->dea) + virBufferAsprintf(buf, "<cipher name='dea' state='%s'/>\n", + virTristateSwitchTypeToString(keywrap->dea)); + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</keywrap>\n"); +} + static bool virDomainDefHasCapabilitiesFeatures(virDomainDefPtr def) { @@ -21490,6 +21643,9 @@ virDomainDefFormatInternal(virDomainDefPtr def, goto error; } + if (def->keywrap) + virDomainKeyWrapDefFormat(buf, def->keywrap); + virBufferAdjustIndent(buf, -2); virBufferAddLit(buf, "</domain>\n"); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 8312c20..7b29008 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2119,6 +2119,13 @@ struct _virDomainPowerManagement { int s4; }; +typedef struct _virDomainKeyWrapDef virDomainKeyWrapDef; +typedef virDomainKeyWrapDef *virDomainKeyWrapDefPtr; +struct _virDomainKeyWrapDef { + int aes; /* enum virTristateSwitch */ + int dea; /* enum virTristateSwitch */ +}; + /* * Guest VM main configuration * @@ -2255,6 +2262,8 @@ struct _virDomainDef { void *namespaceData; virDomainXMLNamespace ns; + virDomainKeyWrapDefPtr keywrap; + /* Application-specific custom metadata */ xmlNodePtr metadata; }; @@ -2264,6 +2273,13 @@ void virDomainDefSetMemoryInitial(virDomainDefPtr def, unsigned long long size); unsigned long long virDomainDefGetMemoryActual(virDomainDefPtr def); typedef enum { + VIR_DOMAIN_KEY_WRAP_CIPHER_NAME_AES, + VIR_DOMAIN_KEY_WRAP_CIPHER_NAME_DEA, + + VIR_DOMAIN_KEY_WRAP_CIPHER_NAME_LAST +} virDomainKeyWrapCipherName; + +typedef enum { VIR_DOMAIN_TAINT_CUSTOM_ARGV, /* Custom ARGV passthrough from XML */ VIR_DOMAIN_TAINT_CUSTOM_MONITOR, /* Custom monitor commands issued */ VIR_DOMAIN_TAINT_HIGH_PRIVILEGES, /* Running with undesirably high privileges */ @@ -2951,6 +2967,7 @@ VIR_ENUM_DECL(virDomainChrTcpProtocol) VIR_ENUM_DECL(virDomainChrSpicevmc) VIR_ENUM_DECL(virDomainSoundCodec) VIR_ENUM_DECL(virDomainSoundModel) +VIR_ENUM_DECL(virDomainKeyWrapCipherName) VIR_ENUM_DECL(virDomainMemballoonModel) VIR_ENUM_DECL(virDomainSmbiosMode) VIR_ENUM_DECL(virDomainWatchdogModel) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index f80fc70..afd0cb6 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -329,6 +329,8 @@ virDomainIOThreadIDDefFree; virDomainIOThreadIDDel; virDomainIOThreadIDFind; virDomainIOThreadSchedDelId; +virDomainKeyWrapCipherNameTypeFromString; +virDomainKeyWrapCipherNameTypeToString; virDomainLeaseDefFree; virDomainLeaseIndex; virDomainLeaseInsert; -- 2.3.6 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list