This commit changes the _qemuDomainStorageSourcePrivate struct to support multiple secrets (instead of a single one before this commit). This will useful for storage encryption requiring more than a single secret. Signed-off-by: Or Ozeri <oro@xxxxxxxxxx> --- src/qemu/qemu_block.c | 22 +++++++----- src/qemu/qemu_command.c | 20 ++++++----- src/qemu/qemu_domain.c | 75 ++++++++++++++++++++++++++++++++--------- src/qemu/qemu_domain.h | 3 +- tests/qemublocktest.c | 7 ++-- 5 files changed, 91 insertions(+), 36 deletions(-) diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c index 2e3e0f6572..f6d21d2040 100644 --- a/src/qemu/qemu_block.c +++ b/src/qemu/qemu_block.c @@ -581,7 +581,7 @@ qemuBlockStorageSourceGetRBDProps(virStorageSource *src, if (virJSONValueObjectAdd(&encrypt, "s:format", encformat, - "s:key-secret", srcPriv->encinfo->alias, + "s:key-secret", srcPriv->encinfo[0]->alias, NULL) < 0) return NULL; } @@ -978,7 +978,7 @@ qemuBlockStorageSourceGetFormatLUKSProps(virStorageSource *src, { qemuDomainStorageSourcePrivate *srcPriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(src); - if (!srcPriv || !srcPriv->encinfo || !srcPriv->encinfo->alias) { + if (!srcPriv || !srcPriv->encinfo || !srcPriv->encinfo[0]->alias) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing secret info for 'luks' driver")); return -1; @@ -986,7 +986,7 @@ qemuBlockStorageSourceGetFormatLUKSProps(virStorageSource *src, if (virJSONValueObjectAdd(&props, "s:driver", "luks", - "s:key-secret", srcPriv->encinfo->alias, + "s:key-secret", srcPriv->encinfo[0]->alias, NULL) < 0) return -1; @@ -1054,7 +1054,7 @@ qemuBlockStorageSourceGetCryptoProps(virStorageSource *src, return virJSONValueObjectAdd(encprops, "s:format", encformat, - "s:key-secret", srcpriv->encinfo->alias, + "s:key-secret", srcpriv->encinfo[0]->alias, NULL); } @@ -1616,13 +1616,17 @@ qemuBlockStorageSourceDetachPrepare(virStorageSource *src) data->authsecretAlias = g_strdup(srcpriv->secinfo->alias); if (srcpriv->encinfo) { + size_t i; + if (!data->encryptsecretAlias) { - data->encryptsecretCount = 1; - data->encryptsecretProps = g_new0(virJSONValue *, 1); - data->encryptsecretAlias = g_new0(char *, 1); + data->encryptsecretCount = srcpriv->enccount; + data->encryptsecretProps = g_new0(virJSONValue *, srcpriv->enccount); + data->encryptsecretAlias = g_new0(char *, srcpriv->enccount); } - data->encryptsecretAlias[0] = g_strdup(srcpriv->encinfo->alias); + for (i = 0; i < srcpriv->enccount; ++i) { + data->encryptsecretAlias[i] = g_strdup(srcpriv->encinfo[i]->alias); + } } if (srcpriv->httpcookie) @@ -1987,7 +1991,7 @@ qemuBlockStorageSourceCreateGetEncryptionLUKS(virStorageSource *src, if (srcpriv && srcpriv->encinfo) - keysecret = srcpriv->encinfo->alias; + keysecret = srcpriv->encinfo[0]->alias; if (virJSONValueObjectAdd(&props, "s:key-secret", keysecret, diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index f5dcb46e42..69f0d74b92 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1603,7 +1603,7 @@ qemuBuildDriveSourceStr(virDomainDiskDef *disk, { virStorageType actualType = virStorageSourceGetActualType(disk->src); qemuDomainStorageSourcePrivate *srcpriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(disk->src); - qemuDomainSecretInfo *encinfo = NULL; + qemuDomainSecretInfo **encinfo = NULL; g_autoptr(virJSONValue) srcprops = NULL; bool rawluks = false; @@ -1647,12 +1647,12 @@ qemuBuildDriveSourceStr(virDomainDiskDef *disk, if (encinfo) { if (disk->src->format == VIR_STORAGE_FILE_RAW) { - virBufferAsprintf(buf, "key-secret=%s,", encinfo->alias); + virBufferAsprintf(buf, "key-secret=%s,", encinfo[0]->alias); rawluks = true; } else if (disk->src->format == VIR_STORAGE_FILE_QCOW2 && disk->src->encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS) { virBufferAddLit(buf, "encrypt.format=luks,"); - virBufferAsprintf(buf, "encrypt.key-secret=%s,", encinfo->alias); + virBufferAsprintf(buf, "encrypt.key-secret=%s,", encinfo[0]->alias); } } @@ -10644,14 +10644,18 @@ qemuBuildStorageSourceAttachPrepareCommon(virStorageSource *src, return -1; if (srcpriv->encinfo) { + size_t i; + if (!data->encryptsecretProps) { - data->encryptsecretCount = 1; - data->encryptsecretProps = g_new0(virJSONValue *, 1); - data->encryptsecretAlias = g_new0(char *, 1); + data->encryptsecretCount = srcpriv->enccount; + data->encryptsecretProps = g_new0(virJSONValue *, srcpriv->enccount); + data->encryptsecretAlias = g_new0(char *, srcpriv->enccount); } - if (qemuBuildSecretInfoProps(srcpriv->encinfo, &data->encryptsecretProps[0]) < 0) - return -1; + for (i = 0; i < srcpriv->enccount; ++i) { + if (qemuBuildSecretInfoProps(srcpriv->encinfo[i], &data->encryptsecretProps[i]) < 0) + return -1; + } } if (srcpriv->httpcookie && diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 80c9852dae..a3b9b57cfa 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -872,7 +872,13 @@ qemuDomainStorageSourcePrivateDispose(void *obj) qemuDomainStorageSourcePrivate *priv = obj; g_clear_pointer(&priv->secinfo, qemuDomainSecretInfoFree); - g_clear_pointer(&priv->encinfo, qemuDomainSecretInfoFree); + if (priv->encinfo) { + size_t i; + for (i = 0; i < priv->enccount; ++i) { + g_clear_pointer(&priv->encinfo[i], qemuDomainSecretInfoFree); + } + priv->encinfo = NULL; + } g_clear_pointer(&priv->httpcookie, qemuDomainSecretInfoFree); g_clear_pointer(&priv->tlsKeySecret, qemuDomainSecretInfoFree); g_clear_pointer(&priv->fdpass, qemuFDPassFree); @@ -1401,7 +1407,13 @@ qemuDomainSecretDiskDestroy(virDomainDiskDef *disk) for (n = disk->src; virStorageSourceIsBacking(n); n = n->backingStore) { if ((srcPriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(n))) { qemuDomainSecretInfoDestroy(srcPriv->secinfo); - qemuDomainSecretInfoDestroy(srcPriv->encinfo); + if (srcPriv->encinfo) { + size_t i; + + for (i = 0; i < srcPriv->enccount; ++i) { + qemuDomainSecretInfoDestroy(srcPriv->encinfo[i]); + } + } qemuDomainSecretInfoDestroy(srcPriv->tlsKeySecret); } } @@ -1470,12 +1482,14 @@ qemuDomainSecretStorageSourcePrepare(qemuDomainObjPrivate *priv, } if (hasEnc) { - if (!(srcPriv->encinfo = qemuDomainSecretInfoSetupFromSecret(priv, aliasformat, - "encryption", 0, - VIR_SECRET_USAGE_TYPE_VOLUME, - NULL, - &src->encryption->secrets[0]->seclookupdef))) - return -1; + srcPriv->enccount = 1; + srcPriv->encinfo = g_new0(qemuDomainSecretInfo *, 1); + if (!(srcPriv->encinfo[0] = qemuDomainSecretInfoSetupFromSecret(priv, aliasformat, + "encryption", 0, + VIR_SECRET_USAGE_TYPE_VOLUME, + NULL, + &src->encryption->secrets[0]->seclookupdef))) + return -1; } if (src->ncookies && @@ -1964,13 +1978,14 @@ qemuStorageSourcePrivateDataParse(xmlXPathContextPtr ctxt, virStorageSource *src) { qemuDomainStorageSourcePrivate *priv; + g_autofree xmlNodePtr *encnodes = NULL; g_autofree char *authalias = NULL; - g_autofree char *encalias = NULL; g_autofree char *httpcookiealias = NULL; g_autofree char *tlskeyalias = NULL; g_autofree char *thresholdEventWithIndex = NULL; bool fdsetPresent = false; unsigned int fdSetID; + int enccount; src->nodestorage = virXPathString("string(./nodenames/nodename[@type='storage']/@name)", ctxt); src->nodeformat = virXPathString("string(./nodenames/nodename[@type='format']/@name)", ctxt); @@ -1983,13 +1998,16 @@ qemuStorageSourcePrivateDataParse(xmlXPathContextPtr ctxt, src->pr->mgralias = virXPathString("string(./reservations/@mgralias)", ctxt); authalias = virXPathString("string(./objects/secret[@type='auth']/@alias)", ctxt); - encalias = virXPathString("string(./objects/secret[@type='encryption']/@alias)", ctxt); + if ((enccount = virXPathNodeSet("./objects/secret[@type='encryption']", ctxt, &encnodes)) < 0) + return -1; httpcookiealias = virXPathString("string(./objects/secret[@type='httpcookie']/@alias)", ctxt); tlskeyalias = virXPathString("string(./objects/secret[@type='tlskey']/@alias)", ctxt); fdsetPresent = virXPathUInt("string(./fdsets/fdset[@type='storage']/@id)", ctxt, &fdSetID) == 0; - if (authalias || encalias || httpcookiealias || tlskeyalias || fdsetPresent) { + if (authalias || (enccount > 0) || httpcookiealias || tlskeyalias || fdsetPresent) { + size_t i; + if (!src->privateData && !(src->privateData = qemuDomainStorageSourcePrivateNew())) return -1; @@ -1999,8 +2017,27 @@ qemuStorageSourcePrivateDataParse(xmlXPathContextPtr ctxt, if (qemuStorageSourcePrivateDataAssignSecinfo(&priv->secinfo, &authalias) < 0) return -1; - if (qemuStorageSourcePrivateDataAssignSecinfo(&priv->encinfo, &encalias) < 0) - return -1; + if (enccount > 0) { + xmlNodePtr tmp = ctxt->node; + + priv->enccount = enccount; + priv->encinfo = g_new0(qemuDomainSecretInfo *, enccount); + for (i = 0; i < enccount; ++i) { + g_autofree char *encalias = NULL; + + ctxt->node = encnodes[i]; + if (!(encalias = virXMLPropString(encnodes[i], "alias"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("missing alias on encryption secret #%lu"), i); + return -1; + } + + if (qemuStorageSourcePrivateDataAssignSecinfo(&priv->encinfo[i], &encalias) < 0) + return -1; + } + + ctxt->node = tmp; + } if (qemuStorageSourcePrivateDataAssignSecinfo(&priv->httpcookie, &httpcookiealias) < 0) return -1; @@ -2061,10 +2098,13 @@ qemuStorageSourcePrivateDataFormat(virStorageSource *src, return -1; if (srcPriv) { + size_t i; unsigned int fdSetID; qemuStorageSourcePrivateDataFormatSecinfo(&objectsChildBuf, srcPriv->secinfo, "auth"); - qemuStorageSourcePrivateDataFormatSecinfo(&objectsChildBuf, srcPriv->encinfo, "encryption"); + for (i = 0; i < srcPriv->enccount; ++i) { + qemuStorageSourcePrivateDataFormatSecinfo(&objectsChildBuf, srcPriv->encinfo[i], "encryption"); + } qemuStorageSourcePrivateDataFormatSecinfo(&objectsChildBuf, srcPriv->httpcookie, "httpcookie"); qemuStorageSourcePrivateDataFormatSecinfo(&objectsChildBuf, srcPriv->tlsKeySecret, "tlskey"); @@ -5631,9 +5671,14 @@ qemuDomainDeviceDiskDefPostParseRestoreSecAlias(virDomainDiskDef *disk, } if (restoreEncSecret) { + if (!priv->encinfo) { + priv->enccount = 1; + priv->encinfo = g_new0(qemuDomainSecretInfo *, 1); + } + encalias = g_strdup_printf("%s-luks-secret0", disk->info.alias); - if (qemuStorageSourcePrivateDataAssignSecinfo(&priv->encinfo, &encalias) < 0) + if (qemuStorageSourcePrivateDataAssignSecinfo(&priv->encinfo[0], &encalias) < 0) return -1; } diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 550397ee50..dda92b5da3 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -295,7 +295,8 @@ struct _qemuDomainStorageSourcePrivate { qemuDomainSecretInfo *secinfo; /* data required for decryption of encrypted storage source */ - qemuDomainSecretInfo *encinfo; + size_t enccount; + qemuDomainSecretInfo **encinfo; /* secure passthrough of the http cookie */ qemuDomainSecretInfo *httpcookie; diff --git a/tests/qemublocktest.c b/tests/qemublocktest.c index 010b52f4b3..2d790e2b2e 100644 --- a/tests/qemublocktest.c +++ b/tests/qemublocktest.c @@ -237,10 +237,11 @@ testQemuDiskXMLToJSONFakeSecrets(virStorageSource *src) } if (src->encryption) { - srcpriv->encinfo = g_new0(qemuDomainSecretInfo, 1); + srcpriv->encinfo = g_new0(qemuDomainSecretInfo *, 1); + srcpriv->encinfo[0] = g_new0(qemuDomainSecretInfo, 1); - srcpriv->encinfo->alias = g_strdup_printf("%s-encalias", - NULLSTR(src->nodeformat)); + srcpriv->encinfo[0]->alias = g_strdup_printf("%s-encalias", + NULLSTR(src->nodeformat)); } return 0; -- 2.25.1