<tpm model='tpm-tis'>
<backend type='emulator' version='2.0' active_pcr_banks='sha256,sha384'/>
</tpm>
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2016599
Signed-off-by: Stefan Berger <stefanb@xxxxxxxxxxxxx>
---
docs/formatdomain.rst | 12 ++-
docs/schemas/basictypes.rng | 6 ++
docs/schemas/domaincommon.rng | 5 ++
src/conf/domain_conf.c | 21 ++++-
src/conf/domain_conf.h | 1 +
src/qemu/qemu_tpm.c | 80 +++++++++++++++++++
src/util/virtpm.c | 1 +
src/util/virtpm.h | 1 +
tests/qemuxml2argvdata/tpm-emulator-tpm2.xml | 2 +-
.../tpm-emulator-tpm2.x86_64-latest.xml | 2 +-
10 files changed, 127 insertions(+), 4 deletions(-)
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index 0651975c88..8785a7a682 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -7537,7 +7537,7 @@ Example: usage of the TPM Emulator
...
<devices>
<tpm model='tpm-tis'>
- <backend type='emulator' version='2.0'>
+ <backend type='emulator' version='2.0' active_pcr_banks='sha256'>
<encryption secret='6dd3e4a5-1d76-44ce-961f-f119f5aad935'/>
</backend>
</tpm>
@@ -7598,6 +7598,16 @@ Example: usage of the TPM Emulator
This attribute only works with the ``emulator`` backend. The accepted values
are ``yes`` and ``no``. :since:`Since 7.0.0`
+``active_pcr_banks``
+ The ``active_pcr_banks`` attribute indicates the names of the PCR banks
+ of a TPM 2.0 to activate. A comma separated list of PCR banks' names
+ must be provided. Valid names are for example sha1, sha256, sha384, and
+ sha512. If this attribute is provided, the set of PCR banks are activated
+ before every start of a VM and this step is logged in the swtpm's log.
+ This attribute requires that swtpm_setup v0.7 or later is installed
+ and may not have any effect otherwise. This attribute only works with the
+ ``emulator`` backend. since:`Since 7.10.0`
+
``encryption``
The ``encryption`` element allows the state of a TPM emulator to be
encrypted. The ``secret`` must reference a secret object that holds the
diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng
index a221ff6295..3bd1eebdc4 100644
--- a/docs/schemas/basictypes.rng
+++ b/docs/schemas/basictypes.rng
@@ -88,6 +88,12 @@
</choice>
</define>
+ <define name="pcrBankList">
+ <data type="string">
+ <param name="pattern">(sha1|sha256|sha384|sha512){1}(,(sha1|sha256|sha384|sha512)){0,3}</param>
+ </data>
+ </define>
+
<define name="numaDistanceValue">
<data type="unsignedInt">
<param name="minInclusive">10</param>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 67df13d90d..6801673cf1 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -5331,6 +5331,11 @@
</choice>
</attribute>
</optional>
+ <optional>
+ <attribute name="active_pcr_banks">
+ <ref name="pcrBankList"/>
+ </attribute>
+ </optional>
</group>
</choice>
<optional>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 4644d18120..bc8237fd0b 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -3207,6 +3207,7 @@ void virDomainTPMDefFree(virDomainTPMDef *def)
break;
case VIR_DOMAIN_TPM_TYPE_EMULATOR:
virDomainChrSourceDefClear(&def->data.emulator.source);
+ g_free(def->data.emulator.activePcrBanks);
g_free(def->data.emulator.storagepath);
g_free(def->data.emulator.logfile);
break;
@@ -11733,7 +11734,7 @@ virDomainSmartcardDefParseXML(virDomainXMLOption *xmlopt,
* Emulator state encryption is supported with the following:
*
* <tpm model='tpm-tis'>
- * <backend type='emulator' version='2.0'>
+ * <backend type='emulator' version='2.0' active_pcr_banks='sha256,sha384'>
* <encryption secret='32ee7e76-2178-47a1-ab7b-269e6e348015'/>
* </backend>
* </tpm>
@@ -11759,6 +11760,7 @@ virDomainTPMDefParseXML(virDomainXMLOption *xmlopt,
g_autofree char *version = NULL;
g_autofree char *secretuuid = NULL;
g_autofree char *persistent_state = NULL;
+ g_autofree char *activePcrBanks = NULL;
g_autofree xmlNodePtr *backends = NULL;
def = g_new0(virDomainTPMDef, 1);
@@ -11841,6 +11843,18 @@ virDomainTPMDefParseXML(virDomainXMLOption *xmlopt,
goto error;
}
}
+ if (def->version == VIR_DOMAIN_TPM_VERSION_2_0) {
+ activePcrBanks = virXMLPropString(backends[0], "active_pcr_banks");
+ if (activePcrBanks) {
+ if (!virStringMatch(activePcrBanks,
+ "(sha1|sha256|sha384|sha512)(,(sha1|sha256|sha384|sha512)){0,3}")) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Malformatted list of PCR banks"));
+ goto error;
+ }
+ def->data.emulator.activePcrBanks = g_steal_pointer(&activePcrBanks);
+ }
+ }
break;
case VIR_DOMAIN_TPM_TYPE_LAST:
goto error;
@@ -25433,6 +25447,11 @@ virDomainTPMDefFormat(virBuffer *buf,
virDomainTPMVersionTypeToString(def->version));
if (def->data.emulator.persistent_state)
virBufferAddLit(buf, " persistent_state='yes'");
+ if (def->version == VIR_DOMAIN_TPM_VERSION_2_0 &&
+ def->data.emulator.activePcrBanks) {
+ virBufferAsprintf(buf, " active_pcr_banks='%s'",
+ def->data.emulator.activePcrBanks);
+ }
if (def->data.emulator.hassecretuuid) {
char uuidstr[VIR_UUID_STRING_BUFLEN];
virBufferAddLit(buf, ">\n");
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index cb6d8975b8..19597dba7e 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1381,6 +1381,7 @@ struct _virDomainTPMDef {
unsigned char secretuuid[VIR_UUID_BUFLEN];
bool hassecretuuid;
bool persistent_state;
+ char *activePcrBanks;
} emulator;
} data;
};
diff --git a/src/qemu/qemu_tpm.c b/src/qemu/qemu_tpm.c
index 93cb04f49d..bb14228edc 100644
--- a/src/qemu/qemu_tpm.c
+++ b/src/qemu/qemu_tpm.c
@@ -566,6 +566,78 @@ qemuTPMEmulatorRunSetup(const char *storagepath,
}
+/*
+ * qemuTPMEmulatorReconfigure
+ *
+ *
+ * @storagepath: path to the directory for TPM state
+ * @swtpm_user: The userid to switch to when setting up the TPM;
+ * typically this should be the uid of 'tss' or 'root'
+ * @swtpm_group: The group id to switch to
+ * @swtpmActivePcrBanks: The string describing the active PCR banks
+ * @logfile: The file to write the log into; it must be writable
+ * for the user given by userid or 'tss'
+ * @tpmversion: The version of the TPM, either a TPM 1.2 or TPM 2
+ * @secretuuid: The secret's UUID needed for state encryption
+ *
+ * Reconfigure the active PCR banks of a TPM 2.
+ */
+static int
+qemuTPMEmulatorReconfigure(const char *storagepath,
+ uid_t swtpm_user,
+ gid_t swtpm_group,
+ const char *swtpmActivePcrBanks,
+ const char *logfile,
+ const virDomainTPMVersion tpmversion,
+ const unsigned char *secretuuid)
+{
+ g_autoptr(virCommand) cmd = NULL;
+ int exitstatus;
+ g_autofree char *swtpm_setup = virTPMGetSwtpmSetup();
+ VIR_AUTOCLOSE pwdfile_fd = -1;
+
+ if (!swtpm_setup)
+ return -1;
+
+ if (tpmversion != VIR_DOMAIN_TPM_VERSION_2_0 ||
+ swtpmActivePcrBanks == NULL ||
+ !virTPMSwtpmSetupCapsGet(
+ VIR_TPM_SWTPM_SETUP_FEATURE_CMDARG_RECONFIGURE_PCR_BANKS))
+ return 0;
+
+ cmd = virCommandNew(swtpm_setup);
+ if (!cmd)
+ return -1;
+
+ virCommandSetUID(cmd, swtpm_user);
+ virCommandSetGID(cmd, swtpm_group);
+
+ virCommandAddArgList(cmd, "--tpm2", NULL);
+
+ if (qemuTPMVirCommandAddEncryption(cmd, swtpm_setup, secretuuid) < 0)
+ return -1;
+
+ virCommandAddArgList(cmd,
+ "--tpm-state", storagepath,
+ "--logfile", logfile,
+ "--pcr-banks", swtpmActivePcrBanks,
+ "--reconfigure",
+ NULL);
+
+ virCommandClearCaps(cmd);
+
+ if (virCommandRun(cmd, &exitstatus) < 0 || exitstatus != 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Could not run '%s --reconfigure'. exitstatus: %d; "
+ "Check error log '%s' for details."),
+ swtpm_setup, exitstatus, logfile);
+ return -1;
+ }
+
+ return 0;
+}
+
+
/*
* qemuTPMEmulatorBuildCommand:
*
@@ -620,6 +692,14 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm,
secretuuid, incomingMigration) < 0)
goto error;
+ if (!incomingMigration &&
+ qemuTPMEmulatorReconfigure(tpm->data.emulator.storagepath,
+ swtpm_user, swtpm_group,
+ tpm->data.emulator.activePcrBanks,
+ tpm->data.emulator.logfile, tpm->version,
+ secretuuid) < 0)
+ goto error;
+
unlink(tpm->data.emulator.source.data.nix.path);
cmd = virCommandNew(swtpm);
diff --git a/src/util/virtpm.c b/src/util/virtpm.c
index 40d9272e66..7fa870b803 100644
--- a/src/util/virtpm.c
+++ b/src/util/virtpm.c
@@ -47,6 +47,7 @@ VIR_ENUM_IMPL(virTPMSwtpmSetupFeature,
"cmdarg-pwdfile-fd",
"cmdarg-create-config-files",
"tpm12-not-need-root",
+ "cmdarg-reconfigure-pcr-banks",
);
/**
diff --git a/src/util/virtpm.h b/src/util/virtpm.h
index b75eb84f31..defea6c106 100644
--- a/src/util/virtpm.h
+++ b/src/util/virtpm.h
@@ -40,6 +40,7 @@ typedef enum {
VIR_TPM_SWTPM_SETUP_FEATURE_CMDARG_PWDFILE_FD,
VIR_TPM_SWTPM_SETUP_FEATURE_CMDARG_CREATE_CONFIG_FILES,
VIR_TPM_SWTPM_SETUP_FEATURE_TPM12_NOT_NEED_ROOT,
+ VIR_TPM_SWTPM_SETUP_FEATURE_CMDARG_RECONFIGURE_PCR_BANKS,
VIR_TPM_SWTPM_SETUP_FEATURE_LAST
} virTPMSwtpmSetupFeature;
diff --git a/tests/qemuxml2argvdata/tpm-emulator-tpm2.xml b/tests/qemuxml2argvdata/tpm-emulator-tpm2.xml
index 3e2f485ee7..ca9b38540d 100644
--- a/tests/qemuxml2argvdata/tpm-emulator-tpm2.xml
+++ b/tests/qemuxml2argvdata/tpm-emulator-tpm2.xml
@@ -23,7 +23,7 @@
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<tpm model='tpm-tis'>
- <backend type='emulator' version='2.0'/>
+ <backend type='emulator' version='2.0' active_pcr_banks='sha256,sha512'/>
</tpm>
<memballoon model='virtio'/>
</devices>
diff --git a/tests/qemuxml2xmloutdata/tpm-emulator-tpm2.x86_64-latest.xml b/tests/qemuxml2xmloutdata/tpm-emulator-tpm2.x86_64-latest.xml
index fe4e1aba19..2488f6ad29 100644
--- a/tests/qemuxml2xmloutdata/tpm-emulator-tpm2.x86_64-latest.xml
+++ b/tests/qemuxml2xmloutdata/tpm-emulator-tpm2.x86_64-latest.xml
@@ -28,7 +28,7 @@
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<tpm model='tpm-tis'>
- <backend type='emulator' version='2.0'/>
+ <backend type='emulator' version='2.0' active_pcr_banks='sha256,sha512'/>
</tpm>
<audio id='1' type='none'/>
<memballoon model='virtio'>
--
2.31.1