diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index b8a0f59ad3..f0b79d5f8d 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -8135,7 +8135,7 @@ Example: usage of the TPM Emulator - + @@ -8233,12 +8233,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 bec44eece1..295707ec1f 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); @@ -10925,10 +10926,7 @@ 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; - } + def->data.emulator.profile.name = virXMLPropString(profile, "name"); if (virXMLPropEnum(profile, "removeDisabled", virDomainTPMProfileRemoveDisabledTypeFromString, VIR_XML_PROP_NONZERO, @@ -25139,16 +25137,23 @@ 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) { + if (def->data.emulator.profile.source || + def->data.emulator.profile.name) { g_auto(virBuffer) profileAttrBuf = VIR_BUFFER_INITIALIZER; - virBufferAsprintf(&profileAttrBuf, " source='%s'", - def->data.emulator.profile.source); + if (def->data.emulator.profile.source) { + virBufferAsprintf(&profileAttrBuf, " source='%s'", + def->data.emulator.profile.source); + } if (def->data.emulator.profile.removeDisabled) { virBufferAsprintf(&profileAttrBuf, " removeDisabled='%s'", virDomainTPMProfileRemoveDisabledTypeToString(def->data.emulator.profile.removeDisabled)); } + if (def->data.emulator.profile.name) { + virBufferAsprintf(&profileAttrBuf, " name='%s'", + def->data.emulator.profile.name); + } virXMLFormatElement(&backendChildBuf, "profile", &profileAttrBuf, NULL); } break; diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 5959e82262..a187ab4083 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1494,6 +1494,7 @@ struct _virDomainTPMEmulatorDef { virBitmap *activePcrBanks; struct { char *source; /* 'source' profile was created from */ + char *name; /* name read from active profile */ virDomainTPMProfileRemoveDisabled removeDisabled; } profile; }; diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index 91711470f1..bfd0044805 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -6061,9 +6061,11 @@ - - - + + + + + @@ -6072,6 +6074,11 @@ + + + + + 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 6d56a845a4..f223dcb9ae 100644 --- a/src/qemu/qemu_tpm.c +++ b/src/qemu/qemu_tpm.c @@ -628,15 +628,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"), + swtpm, exitstatus, stderr_buf); + return -1; + } + + if (!(object = virJSONValueFromString(stdout_buf))) + return -1; + + if (!(active_profile = virJSONValueObjectGetObject(object, "ActiveProfile"))) + return -1; + + profile_name = virJSONValueObjectGetString(active_profile, "Name"); + + 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; +} + /* * qemuTPMEmulatorBuildCommand: * * @tpm: TPM definition + * @persistentTPMDef: TPM definition from the persistent domain definition * @vmname: The name of the VM * @vmuuid: The UUID of the VM * @privileged: whether we are running in privileged mode * @cfg: virQEMUDriverConfig * @incomingMigration: whether we have an incoming migration + * @saveDef: whether caller should save the persistent domain def * * Create the virCommand use for starting the emulator * Do some initializations on the way, such as creation of storage @@ -644,11 +718,13 @@ qemuTPMVirCommandSwtpmAddTPMState(virCommand *cmd, */ static virCommand * qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm, + virDomainTPMDef *persistentTPMDef, const char *vmname, const unsigned char *vmuuid, bool privileged, const virQEMUDriverConfig *cfg, - bool incomingMigration) + bool incomingMigration, + bool *saveDef) { g_autoptr(virCommand) cmd = NULL; bool created = false; @@ -697,6 +773,11 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm, incomingMigration) < 0) goto error; + if (run_setup && !incomingMigration && + qemuTPMEmulatorUpdateProfileName(&tpm->data.emulator, persistentTPMDef, + cfg, saveDef) < 0) + goto error; + if (!incomingMigration && qemuTPMEmulatorReconfigure(&tpm->data.emulator, cfg, secretuuid) < 0) goto error; @@ -996,6 +1077,7 @@ qemuExtTPMEmulatorSetupCgroup(const char *swtpmStateDir, * @driver: QEMU driver * @vm: the domain object * @tpm: TPM definition + * @persistentTPMDef: TPM definition from persistent domain definition * @shortName: short and unique name of the domain * @incomingMigration: whether we have an incoming migration * @@ -1008,6 +1090,7 @@ qemuTPMEmulatorStart(virQEMUDriver *driver, virDomainObj *vm, const char *shortName, virDomainTPMDef *tpm, + virDomainTPMDef *persistentTPMDef, bool incomingMigration) { g_autoptr(virCommand) cmd = NULL; @@ -1016,6 +1099,7 @@ qemuTPMEmulatorStart(virQEMUDriver *driver, g_autofree char *pidfile = NULL; virTimeBackOffVar timebackoff; const unsigned long long timeout = 1000; /* ms */ + bool saveDef = false; pid_t pid = -1; bool lockMetadataException = false; @@ -1024,12 +1108,18 @@ qemuTPMEmulatorStart(virQEMUDriver *driver, /* stop any left-over TPM emulator for this VM */ qemuTPMEmulatorStop(cfg->swtpmStateDir, shortName); - if (!(cmd = qemuTPMEmulatorBuildCommand(tpm, vm->def->name, vm->def->uuid, + if (!(cmd = qemuTPMEmulatorBuildCommand(tpm, persistentTPMDef, + vm->def->name, vm->def->uuid, driver->privileged, cfg, - incomingMigration))) + incomingMigration, + &saveDef))) return -1; + if (saveDef && + virDomainDefSave(vm->newDef, driver->xmlopt, cfg->configDir) < 0) + goto error; + if (qemuExtDeviceLogCommand(driver, vm, cmd, "TPM Emulator") < 0) return -1; @@ -1213,6 +1303,7 @@ int qemuExtTPMStart(virQEMUDriver *driver, virDomainObj *vm, virDomainTPMDef *tpm, + virDomainTPMDef *persistentTPMDef, bool incomingMigration) { g_autofree char *shortName = virDomainDefGetShortName(vm->def); @@ -1220,7 +1311,8 @@ qemuExtTPMStart(virQEMUDriver *driver, if (!shortName) return -1; - return qemuTPMEmulatorStart(driver, vm, shortName, tpm, incomingMigration); + return qemuTPMEmulatorStart(driver, vm, shortName, tpm, persistentTPMDef, + incomingMigration); } diff --git a/src/qemu/qemu_tpm.h b/src/qemu/qemu_tpm.h index 3071dc3f71..7096060a2a 100644 --- a/src/qemu/qemu_tpm.h +++ b/src/qemu/qemu_tpm.h @@ -44,9 +44,10 @@ void qemuExtTPMCleanupHost(virQEMUDriver *driver, int qemuExtTPMStart(virQEMUDriver *driver, virDomainObj *vm, virDomainTPMDef *def, + virDomainTPMDef *persistentDefTPM, bool incomingMigration) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) - ATTRIBUTE_NONNULL(3) + ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4) G_GNUC_WARN_UNUSED_RESULT; void qemuExtTPMStop(virQEMUDriver *driver, diff --git a/src/util/virtpm.c b/src/util/virtpm.c index 1c736b0229..4016ad8fc4 100644 --- a/src/util/virtpm.c +++ b/src/util/virtpm.c @@ -42,6 +42,7 @@ VIR_ENUM_IMPL(virTPMSwtpmFeature, "cmdarg-migration", "nvram-backend-dir", "nvram-backend-file", + "cmdarg-print-info", ); VIR_ENUM_IMPL(virTPMSwtpmSetupFeature, diff --git a/src/util/virtpm.h b/src/util/virtpm.h index 9ca09c2d80..03fb92629a 100644 --- a/src/util/virtpm.h +++ b/src/util/virtpm.h @@ -33,6 +33,7 @@ typedef enum { VIR_TPM_SWTPM_FEATURE_CMDARG_MIGRATION, VIR_TPM_SWTPM_FEATURE_NVRAM_BACKEND_DIR, VIR_TPM_SWTPM_FEATURE_NVRAM_BACKEND_FILE, + VIR_TPM_SWTPM_FEATURE_CMDARG_PRINT_INFO, VIR_TPM_SWTPM_FEATURE_LAST } virTPMSwtpmFeature; diff --git a/tests/qemuxmlconfdata/tpm-emulator-crb-profile.xml b/tests/qemuxmlconfdata/tpm-emulator-crb-profile.xml index b8473cd894..40224f43a7 100644 --- a/tests/qemuxmlconfdata/tpm-emulator-crb-profile.xml +++ b/tests/qemuxmlconfdata/tpm-emulator-crb-profile.xml @@ -29,7 +29,7 @@ - +