qemu: tpm: Add support for storing private TPM-related data

Add support for storing private TPM-related data. The first private data
will be related to the capability of the started swtpm indicating whether
it is capable of migration with a shared storage setup since that requires
support for certain command line flags that were only becoming available
in v0.8.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
Stefan Berger 2022-10-24 06:28:45 -04:00 committed by Michal Privoznik
parent 68103e9daf
commit 5597476e40
4 changed files with 154 additions and 5 deletions

View File

@ -3276,6 +3276,22 @@ void virDomainHostdevDefClear(virDomainHostdevDef *def)
}
}
static virDomainTPMDef *
virDomainTPMDefNew(virDomainXMLOption *xmlopt)
{
virDomainTPMDef *def;
def = g_new0(virDomainTPMDef, 1);
if (xmlopt && xmlopt->privateData.tpmNew &&
!(def->privateData = xmlopt->privateData.tpmNew())) {
VIR_FREE(def);
return NULL;
}
return def;
}
void virDomainTPMDefFree(virDomainTPMDef *def)
{
if (!def)
@ -3296,6 +3312,7 @@ void virDomainTPMDefFree(virDomainTPMDef *def)
}
virDomainDeviceInfoClear(&def->info);
virObjectUnref(def->privateData);
g_free(def);
}
@ -10240,7 +10257,8 @@ virDomainTPMDefParseXML(virDomainXMLOption *xmlopt,
g_autofree xmlNodePtr *nodes = NULL;
int bank;
def = g_new0(virDomainTPMDef, 1);
if (!(def = virDomainTPMDefNew(xmlopt)))
return NULL;
if (virXMLPropEnum(node, "model",
virDomainTPMModelTypeFromString,
@ -10331,6 +10349,14 @@ virDomainTPMDefParseXML(virDomainXMLOption *xmlopt,
if (virDomainDeviceInfoParseXML(xmlopt, node, ctxt, &def->info, flags) < 0)
goto error;
if (flags & VIR_DOMAIN_DEF_PARSE_STATUS &&
xmlopt && xmlopt->privateData.tpmParse) {
if ((ctxt->node = virXPathNode("./privateData", ctxt))) {
if (xmlopt->privateData.tpmParse(ctxt, def) < 0)
goto error;
}
}
return def;
error:
@ -23921,10 +23947,32 @@ virDomainSoundCodecDefFormat(virBuffer *buf,
return 0;
}
static void
static int
virDomainTPMDefFormatPrivateData(virBuffer *buf,
const virDomainTPMDef *tpm,
unsigned int flags,
virDomainXMLOption *xmlopt)
{
g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);
if (!(flags & VIR_DOMAIN_DEF_FORMAT_STATUS) ||
!xmlopt ||
!xmlopt->privateData.tpmFormat)
return 0;
if (xmlopt->privateData.tpmFormat(tpm, &childBuf) < 0)
return -1;
virXMLFormatElement(buf, "privateData", NULL, &childBuf);
return 0;
}
static int
virDomainTPMDefFormat(virBuffer *buf,
const virDomainTPMDef *def,
unsigned int flags)
unsigned int flags,
virDomainXMLOption *xmlopt)
{
g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);
@ -23973,8 +24021,12 @@ virDomainTPMDefFormat(virBuffer *buf,
virXMLFormatElement(&childBuf, "backend", &backendAttrBuf, &backendChildBuf);
virDomainDeviceInfoFormat(&childBuf, &def->info, flags);
if (virDomainTPMDefFormatPrivateData(&childBuf, def, flags, xmlopt) < 0)
return -1;
virXMLFormatElement(buf, "tpm", &attrBuf, &childBuf);
return 0;
}
@ -27060,7 +27112,8 @@ virDomainDefFormatInternalSetRootName(virDomainDef *def,
}
for (n = 0; n < def->ntpms; n++) {
virDomainTPMDefFormat(buf, def->tpms[n], flags);
if (virDomainTPMDefFormat(buf, def->tpms[n], flags, xmlopt) < 0)
return -1;
}
for (n = 0; n < def->ngraphics; n++) {
@ -28326,7 +28379,7 @@ virDomainDeviceDefCopy(virDomainDeviceDef *src,
rc = virDomainChrDefFormat(&buf, src->data.chr, flags);
break;
case VIR_DOMAIN_DEVICE_TPM:
virDomainTPMDefFormat(&buf, src->data.tpm, flags);
virDomainTPMDefFormat(&buf, src->data.tpm, flags, xmlopt);
rc = 0;
break;
case VIR_DOMAIN_DEVICE_PANIC:

View File

@ -1445,6 +1445,8 @@ typedef enum {
#define VIR_DOMAIN_TPM_DEFAULT_DEVICE "/dev/tpm0"
struct _virDomainTPMDef {
virObject *privateData;
virDomainTPMModel model;
virDomainTPMBackendType type;
virDomainDeviceInfo info;
@ -3248,6 +3250,10 @@ typedef int (*virDomainXMLPrivateDataStorageSourceParseFunc)(xmlXPathContextPtr
typedef int (*virDomainXMLPrivateDataStorageSourceFormatFunc)(virStorageSource *src,
virBuffer *buf);
typedef int (*virDomainXMLPrivateDataTPMParseFunc)(xmlXPathContextPtr ctxt,
virDomainTPMDef *disk);
typedef int (*virDomainXMLPrivateDataTPMFormatFunc)(const virDomainTPMDef *tpm,
virBuffer *buf);
struct _virDomainXMLPrivateDataCallbacks {
virDomainXMLPrivateDataAllocFunc alloc;
@ -3264,6 +3270,9 @@ struct _virDomainXMLPrivateDataCallbacks {
virDomainXMLPrivateDataNewFunc networkNew;
virDomainXMLPrivateDataNewFunc videoNew;
virDomainXMLPrivateDataNewFunc fsNew;
virDomainXMLPrivateDataTPMParseFunc tpmParse;
virDomainXMLPrivateDataTPMFormatFunc tpmFormat;
virDomainXMLPrivateDataNewFunc tpmNew;
virDomainXMLPrivateDataFormatFunc format;
virDomainXMLPrivateDataParseFunc parse;
/* following function shall return a pointer which will be used as the

View File

@ -1138,6 +1138,76 @@ qemuDomainVideoPrivateDispose(void *obj)
}
static virClass *qemuDomainTPMPrivateClass;
static void qemuDomainTPMPrivateDispose(void *obj);
static int
qemuDomainTPMPrivateOnceInit(void)
{
if (!VIR_CLASS_NEW(qemuDomainTPMPrivate, virClassForObject()))
return -1;
return 0;
}
VIR_ONCE_GLOBAL_INIT(qemuDomainTPMPrivate);
static virObject *
qemuDomainTPMPrivateNew(void)
{
qemuDomainTPMPrivate *priv;
if (qemuDomainTPMPrivateInitialize() < 0)
return NULL;
if (!(priv = virObjectNew(qemuDomainTPMPrivateClass)))
return NULL;
return (virObject *) priv;
}
static void
qemuDomainTPMPrivateDispose(void *obj G_GNUC_UNUSED)
{
}
static int
qemuDomainTPMPrivateParse(xmlXPathContextPtr ctxt,
virDomainTPMDef *tpm)
{
qemuDomainTPMPrivate *priv = QEMU_DOMAIN_TPM_PRIVATE(tpm);
priv->swtpm.can_migrate_shared_storage =
virXPathBoolean("string(./swtpm/@can_migrate_shared_storage)", ctxt);
return 0;
}
static int
qemuDomainTPMPrivateFormat(const virDomainTPMDef *tpm,
virBuffer *buf)
{
qemuDomainTPMPrivate *priv = QEMU_DOMAIN_TPM_PRIVATE(tpm);
switch (tpm->type) {
case VIR_DOMAIN_TPM_TYPE_EMULATOR:
if (priv->swtpm.can_migrate_shared_storage)
virBufferAddLit(buf, "<swtpm can_migrate_shared_storage='yes'/>\n");
break;
case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
case VIR_DOMAIN_TPM_TYPE_LAST:
}
return 0;
}
/* qemuDomainSecretInfoSetup:
* @priv: pointer to domain private object
* @alias: alias of the secret
@ -3212,6 +3282,9 @@ virDomainXMLPrivateDataCallbacks virQEMUDriverPrivateDataCallbacks = {
.graphicsNew = qemuDomainGraphicsPrivateNew,
.networkNew = qemuDomainNetworkPrivateNew,
.videoNew = qemuDomainVideoPrivateNew,
.tpmNew = qemuDomainTPMPrivateNew,
.tpmParse = qemuDomainTPMPrivateParse,
.tpmFormat = qemuDomainTPMPrivateFormat,
.parse = qemuDomainObjPrivateXMLParse,
.format = qemuDomainObjPrivateXMLFormat,
.getParseOpaque = qemuDomainObjPrivateXMLGetParseOpaque,

View File

@ -414,6 +414,20 @@ struct _qemuDomainNetworkPrivate {
qemuFDPass *vdpafd;
};
#define QEMU_DOMAIN_TPM_PRIVATE(dev) \
((qemuDomainTPMPrivate *) (dev)->privateData)
typedef struct _qemuDomainTPMPrivate qemuDomainTPMPrivate;
struct _qemuDomainTPMPrivate {
virObject parent;
struct {
bool can_migrate_shared_storage;
} swtpm;
};
void
qemuDomainNetworkPrivateClearFDs(qemuDomainNetworkPrivate *priv);