On 11/13/24 18:39, Stefan Berger wrote: > Get the JSON profile that the swtpm instance was created with from the > output of 'swtpm socket --tpm2 --print-info 0x20 --tpmstate ...'. Get the > name of the profile from the JSON and set it in the current and persistent > emulator descriptions as 'name' attribute and have the persistent > description stored with this update. The user should avoid setting this > 'name' attribute since it is meant to be read-only. The following is > an example of how the XML could look like: > > <profile source='local:restricted' name='custom:restricted'/> > > If the user provided no profile node, and therefore swtpm_setup picked its > default profile, the XML may now shows the 'name' attribute with the name > of the profile. This makes the 'source' attribute now optional. > > <profile name='default-v1'/> > > Signed-off-by: Stefan Berger <stefanb@xxxxxxxxxxxxx> > --- > docs/formatdomain.rst | 16 ++--- > src/conf/domain_conf.c | 18 +++--- > src/conf/domain_conf.h | 1 + > src/conf/schemas/domaincommon.rng | 13 +++- > src/qemu/qemu_extdevice.c | 5 +- > src/qemu/qemu_tpm.c | 100 ++++++++++++++++++++++++++++-- > src/qemu/qemu_tpm.h | 3 +- > src/util/virtpm.c | 1 + > src/util/virtpm.h | 1 + > 9 files changed, 135 insertions(+), 23 deletions(-) > > diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst > index 6539f620fa..20c86087ef 100644 > --- a/docs/formatdomain.rst > +++ b/docs/formatdomain.rst > @@ -8131,7 +8131,7 @@ Example: usage of the TPM Emulator > <active_pcr_banks> > <sha256/> > </active_pcr_banks> > - <profile source='local:restricted' remove_disabled='check'/> > + <profile source='local:restricted' remove_disabled='check' name='custom:restricted'/> > </backend> > </tpm> > </devices> > @@ -8229,12 +8229,14 @@ Example: usage of the TPM Emulator > ``profile`` > The ``profile`` node is used to set a profile for a TPM 2.0 given in the > source attribute. This profile will be set when the TPM is initially > - created and after that cannot be changed anymore. If no profile is provided, > - then swtpm will use the latest built-in 'default' profile or the default > - profile set in swtpm_setup.conf. Otherwise swtpm_setup will search for a > - profile with the given name with appended .json suffix in a configurable > - local and then in a distro directory. If none could be found in either, it > - will fall back trying to use a built-in one. > + created and after that cannot be changed anymore. Once a profile has been > + set the name attribute will be updated with the name of the profile that > + is running. If no profile is provided, then swtpm will use the latest > + built-in 'default' profile or the default profile set in swtpm_setup.conf. > + Otherwise swtpm_setup will search for a profile with the given name with > + appended .json suffix in a configurable local and then in a distro > + directory. If none could be found in either, it will fall back trying to > + use a built-in one. > > The built-in 'null' profile provides backwards compatibility with > libtpms v0.9 but also restricts the user to use only TPM features that were > diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c > index 7d91e3e958..6f6898014b 100644 > --- a/src/conf/domain_conf.c > +++ b/src/conf/domain_conf.c > @@ -3479,6 +3479,7 @@ void virDomainTPMDefFree(virDomainTPMDef *def) > g_free(def->data.emulator.logfile); > virBitmapFree(def->data.emulator.activePcrBanks); > g_free(def->data.emulator.profile_source); > + g_free(def->data.emulator.profile_name); > break; > case VIR_DOMAIN_TPM_TYPE_EXTERNAL: > virObjectUnref(def->data.external.source); > @@ -10926,10 +10927,6 @@ virDomainTPMDefParseXML(virDomainXMLOption *xmlopt, > > if ((profile = virXPathNode("./backend/profile[1]", ctxt))) { > def->data.emulator.profile_source = virXMLPropString(profile, "source"); > - if (!def->data.emulator.profile_source) { > - virReportError(VIR_ERR_XML_ERROR, "%s", _("missing profile source")); > - goto error; > - } > if (virXMLPropEnum(profile, "remove_disabled", > virDomainTPMProfileRemoveDisabledTypeFromString, > VIR_XML_PROP_NONZERO, > @@ -10938,6 +10935,7 @@ virDomainTPMDefParseXML(virDomainXMLOption *xmlopt, > if (profile_remove_disabled != VIR_DOMAIN_TPM_PROFILE_REMOVE_DISABLED_NONE) > def->data.emulator.profile_remove_disabled = > virDomainTPMProfileRemoveDisabledTypeToString(profile_remove_disabled); > + def->data.emulator.profile_name = virXMLPropString(profile, "name"); > } > break; > case VIR_DOMAIN_TPM_TYPE_EXTERNAL: > @@ -25134,12 +25132,18 @@ virDomainTPMDefFormat(virBuffer *buf, > virDomainTPMSourceTypeTypeToString(def->data.emulator.source_type)); > virBufferEscapeString(&backendChildBuf, " path='%s'/>\n", def->data.emulator.source_path); > } > - if (def->data.emulator.profile_source) { > - virBufferAsprintf(&backendChildBuf, "<profile source='%s'", > - def->data.emulator.profile_source); > + if (def->data.emulator.profile_source || > + def->data.emulator.profile_name) { > + virBufferAddLit(&backendChildBuf, "<profile"); > + if (def->data.emulator.profile_source) > + virBufferAsprintf(&backendChildBuf, " source='%s'", > + def->data.emulator.profile_source); > if (def->data.emulator.profile_remove_disabled) > virBufferAsprintf(&backendChildBuf, " remove_disabled='%s'", > def->data.emulator.profile_remove_disabled); > + if (def->data.emulator.profile_name) > + virBufferAsprintf(&backendChildBuf, " name='%s'", > + def->data.emulator.profile_name); > virBufferAddLit(&backendChildBuf, "/>\n"); > } > break; > diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h > index bd2740af26..45421d4772 100644 > --- a/src/conf/domain_conf.h > +++ b/src/conf/domain_conf.h > @@ -1493,6 +1493,7 @@ struct _virDomainTPMEmulatorDef { > bool persistent_state; > virBitmap *activePcrBanks; > char *profile_source; /* 'source' profile was created from */ > + char *profile_name; /* name read from active profile */ > const char *profile_remove_disabled; > }; > > diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng > index d94ff9b4c3..e26e65fd7c 100644 > --- a/src/conf/schemas/domaincommon.rng > +++ b/src/conf/schemas/domaincommon.rng > @@ -6056,9 +6056,11 @@ > <define name="tpm-backend-emulator-profile"> > <optional> > <element name="profile"> > - <attribute name="source"> > - <ref name="profileName"/> > - </attribute> > + <optional> > + <attribute name="source"> > + <ref name="profileName"/> > + </attribute> > + </optional> > <optional> > <attribute name="remove_disabled"> > <choice> > @@ -6067,6 +6069,11 @@ > </choice> > </attribute> > </optional> > + <optional> > + <attribute name="name"> > + <ref name="profileName"/> > + </attribute> > + </optional> > </element> > </optional> > </define> > diff --git a/src/qemu/qemu_extdevice.c b/src/qemu/qemu_extdevice.c > index dc1bb56237..a6f31f9773 100644 > --- a/src/qemu/qemu_extdevice.c > +++ b/src/qemu/qemu_extdevice.c > @@ -175,6 +175,7 @@ qemuExtDevicesStart(virQEMUDriver *driver, > virDomainObj *vm, > bool incomingMigration) > { > + virDomainDef *persistentDef = vm->newDef; > virDomainDef *def = vm->def; > size_t i; > > @@ -189,9 +190,11 @@ qemuExtDevicesStart(virQEMUDriver *driver, > > for (i = 0; i < def->ntpms; i++) { > virDomainTPMDef *tpm = def->tpms[i]; > + virDomainTPMDef *persistentTPMDef = persistentDef->tpms[i]; > > if (tpm->type == VIR_DOMAIN_TPM_TYPE_EMULATOR && > - qemuExtTPMStart(driver, vm, tpm, incomingMigration) < 0) > + qemuExtTPMStart(driver, vm, tpm, persistentTPMDef, > + incomingMigration) < 0) > return -1; > } > > diff --git a/src/qemu/qemu_tpm.c b/src/qemu/qemu_tpm.c > index a7eee501bf..2fb3796910 100644 > --- a/src/qemu/qemu_tpm.c > +++ b/src/qemu/qemu_tpm.c > @@ -627,15 +627,89 @@ qemuTPMVirCommandSwtpmAddTPMState(virCommand *cmd, > } > } > > +/* qemuTPMEmulatorUpdateProfileName: > + * > + * @emulator: TPM emulator definition > + * @persistentTPMDef: TPM definition from the persistent domain definition > + * @cfg: virQEMUDriverConfig > + * @saveDef: whether caller should save the persistent domain def > + */ > +static int > +qemuTPMEmulatorUpdateProfileName(virDomainTPMEmulatorDef *emulator, > + virDomainTPMDef *persistentTPMDef, > + const virQEMUDriverConfig *cfg, > + bool *saveDef) > +{ > + g_autoptr(virJSONValue) object = NULL; > + g_autofree char *stderr_buf = NULL; > + g_autofree char *stdout_buf = NULL; > + g_autoptr(virCommand) cmd = NULL; > + g_autofree char *swtpm = NULL; > + virJSONValue *active_profile; > + const char *profile_name; > + int exitstatus; > + > + if (emulator->version != VIR_DOMAIN_TPM_VERSION_2_0 || > + !virTPMSwtpmCapsGet(VIR_TPM_SWTPM_FEATURE_CMDARG_PRINT_INFO)) > + return 0; > + > + swtpm = virTPMGetSwtpm(); > + if (!swtpm) > + return -1; > + > + cmd = virCommandNew(swtpm); > + > + virCommandSetUID(cmd, cfg->swtpm_user); /* should be uid of 'tss' or 'root' */ > + virCommandSetGID(cmd, cfg->swtpm_group); > + > + virCommandAddArgList(cmd, "socket", "--print-info", "0x20", "--tpm2", NULL); > + > + qemuTPMVirCommandSwtpmAddTPMState(cmd, emulator); > + > + if (qemuTPMVirCommandSwtpmAddEncryption(cmd, emulator, swtpm) < 0) > + return -1; > + > + virCommandClearCaps(cmd); > + > + virCommandSetOutputBuffer(cmd, &stdout_buf); > + virCommandSetErrorBuffer(cmd, &stderr_buf); > + > + if (virCommandRun(cmd, &exitstatus) < 0 || exitstatus != 0) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Could not run '%1$s --print-info'. exitstatus: %2$d; stderr: %3$s\n"), We don't really put newlines at the end of messages. > + swtpm, exitstatus, stderr_buf); > + return -1; > + } > + > + if (!(object = virJSONValueFromString(stdout_buf))) > + return -1; > + > + if (!(active_profile = virJSONValueObjectGetObject(object, "ActiveProfile"))) > + return -1; > + > + profile_name = g_strdup(virJSONValueObjectGetString(active_profile, "Name")); This g_strdup() looks suspicios and surely must lead to a memleak. > + > + g_free(emulator->profile_name); > + emulator->profile_name = g_strdup(profile_name); > + > + *saveDef = true; > + g_free(persistentTPMDef->data.emulator.profile_name); > + persistentTPMDef->data.emulator.profile_name = g_strdup(profile_name); > + > + return 0; > +} > + Michal