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 @@
-
+