Extend the TPM backend XML with a node 'active_pcr_banks' that allows a
user to specify the PCR banks to activate before starting a VM. Valid
choices for PCR banks are sha1, sha256, sha384 and sha512. When the XML
node is provided, the set of active PCR banks is 'enforced' by running
swtpm_setup before every start of the VM. The activation requires that
swtpm_setup v0.7 or later is installed and may not have any effect
otherwise.
<tpm model='tpm-tis'>
<backend type='emulator' version='2.0'>
<active_pcr_banks>
<sha256/>
<sha384/>
</active_pcr_banks>
</backend>
</tpm>
Fixes:
https://bugzilla.redhat.com/show_bug.cgi?id=2016599
Signed-off-by: Stefan Berger <stefanb(a)linux.ibm.com>
---
docs/formatdomain.rst | 12 +++
docs/schemas/domaincommon.rng | 30 ++++++
src/conf/domain_conf.c | 50 +++++++++-
src/conf/domain_conf.h | 11 +++
src/libvirt_private.syms | 2 +
src/qemu/qemu_tpm.c | 98 +++++++++++++++++++
src/util/virtpm.c | 1 +
src/util/virtpm.h | 1 +
tests/qemuxml2argvdata/tpm-emulator-tpm2.xml | 7 +-
.../tpm-emulator-tpm2.x86_64-latest.xml | 7 +-
10 files changed, 215 insertions(+), 4 deletions(-)
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index 0651975c88..eb8c973cf1 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -7539,6 +7539,9 @@ Example: usage of the TPM Emulator
<tpm model='tpm-tis'>
<backend type='emulator' version='2.0'>
<encryption secret='6dd3e4a5-1d76-44ce-961f-f119f5aad935'/>
+ <active_pcr_banks>
+ <sha256/>
+ </active_pcr_banks>
</backend>
</tpm>
</devices>
@@ -7598,6 +7601,15 @@ 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`` node is used to define which of the PCR banks
+ of a TPM 2.0 to activate. Valid names are for example sha1, sha256, sha384,
+ and sha512. If this node 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. The selection of PCR banks 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/domaincommon.rng b/docs/schemas/domaincommon.rng
index 67df13d90d..4fe3e04af5 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -5323,6 +5323,7 @@
<value>emulator</value>
</attribute>
<ref name="tpm-backend-emulator-encryption"/>
+ <ref name="tpm-backend-emulator-active-pcr-banks"/>
<optional>
<attribute name="persistent_state">
<choice>
@@ -5366,6 +5367,35 @@
</optional>
</define>
+ <define name="tpm-backend-emulator-active-pcr-banks">
+ <optional>
+ <element name="active_pcr_banks">
+ <interleave>
+ <optional>
+ <element name="sha1">
+ <text/>
+ </element>
+ </optional>
+ <optional>
+ <element name="sha256">
+ <text/>
+ </element>
+ </optional>
+ <optional>
+ <element name="sha384">
+ <text/>
+ </element>
+ </optional>
+ <optional>
+ <element name="sha512">
+ <text/>
+ </element>
+ </optional>
+ </interleave>
+ </element>
+ </optional>
+ </define>
+
<define name="vsock">
<element name="vsock">
<optional>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 4644d18120..da0c64b460 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1258,6 +1258,14 @@ VIR_ENUM_IMPL(virDomainTPMVersion,
"2.0",
);
+VIR_ENUM_IMPL(virDomainTPMPcrBank,
+ VIR_DOMAIN_TPM_PCR_BANK_LAST,
+ "sha1",
+ "sha256",
+ "sha384",
+ "sha512",
+);
+
VIR_ENUM_IMPL(virDomainIOMMUModel,
VIR_DOMAIN_IOMMU_MODEL_LAST,
"intel",
@@ -11735,6 +11743,10 @@ virDomainSmartcardDefParseXML(virDomainXMLOption *xmlopt,
* <tpm model='tpm-tis'>
* <backend type='emulator' version='2.0'>
* <encryption secret='32ee7e76-2178-47a1-ab7b-269e6e348015'/>
+ * <active_pcr_banks>
+ * <sha256/>
+ * <sha384/>
+ * </active_pcr_banks>
* </backend>
* </tpm>
*
@@ -11753,6 +11765,8 @@ virDomainTPMDefParseXML(virDomainXMLOption *xmlopt,
virDomainTPMDef *def;
VIR_XPATH_NODE_AUTORESTORE(ctxt)
int nbackends;
+ int nnodes;
+ size_t i;
g_autofree char *path = NULL;
g_autofree char *model = NULL;
g_autofree char *backend = NULL;
@@ -11760,6 +11774,8 @@ virDomainTPMDefParseXML(virDomainXMLOption *xmlopt,
g_autofree char *secretuuid = NULL;
g_autofree char *persistent_state = NULL;
g_autofree xmlNodePtr *backends = NULL;
+ g_autofree xmlNodePtr *nodes = NULL;
+ int bank;
def = g_new0(virDomainTPMDef, 1);
@@ -11841,6 +11857,19 @@ virDomainTPMDefParseXML(virDomainXMLOption *xmlopt,
goto error;
}
}
+ if (def->version == VIR_DOMAIN_TPM_VERSION_2_0) {
+ if ((nnodes = virXPathNodeSet("./backend/active_pcr_banks/*", ctxt,
&nodes)) < 0)
+ break;
+ for (i = 0; i < nnodes; i++) {
+ if ((bank = virDomainTPMPcrBankTypeFromString((const char
*)nodes[i]->name)) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Unsupported PCR banks '%s'"),
+ nodes[i]->name);
+ goto error;
+ }
+ def->data.emulator.activePcrBanks |= (1 << bank);
+ }
+ }
break;
case VIR_DOMAIN_TPM_TYPE_LAST:
goto error;
@@ -25440,10 +25469,27 @@ virDomainTPMDefFormat(virBuffer *buf,
virBufferAsprintf(buf, "<encryption
secret='%s'/>\n",
virUUIDFormat(def->data.emulator.secretuuid, uuidstr));
virBufferAdjustIndent(buf, -2);
+ }
+ if (def->data.emulator.activePcrBanks) {
+ size_t i;
+ virBufferAddLit(buf, ">\n");
+ virBufferAdjustIndent(buf, 2);
+ virBufferAddLit(buf, "<active_pcr_banks>\n");
+ virBufferAdjustIndent(buf, 2);
+ for (i = VIR_DOMAIN_TPM_PCR_BANK_SHA1; i < VIR_DOMAIN_TPM_PCR_BANK_LAST;
i++) {
+ if ((def->data.emulator.activePcrBanks & (1 << i)))
+ virBufferAsprintf(buf, "<%s/>\n",
+ virDomainTPMPcrBankTypeToString(i));
+ }
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</active_pcr_banks>\n");
+ virBufferAdjustIndent(buf, -2);
+ }
+ if (def->data.emulator.hassecretuuid ||
+ def->data.emulator.activePcrBanks)
virBufferAddLit(buf, "</backend>\n");
- } else {
+ else
virBufferAddLit(buf, "/>\n");
- }
break;
case VIR_DOMAIN_TPM_TYPE_LAST:
break;
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index cb6d8975b8..ab9a7d66f8 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1363,6 +1363,15 @@ typedef enum {
VIR_DOMAIN_TPM_VERSION_LAST
} virDomainTPMVersion;
+typedef enum {
+ VIR_DOMAIN_TPM_PCR_BANK_SHA1,
+ VIR_DOMAIN_TPM_PCR_BANK_SHA256,
+ VIR_DOMAIN_TPM_PCR_BANK_SHA384,
+ VIR_DOMAIN_TPM_PCR_BANK_SHA512,
+
+ VIR_DOMAIN_TPM_PCR_BANK_LAST
+} virDomainPcrBank;
+
#define VIR_DOMAIN_TPM_DEFAULT_DEVICE "/dev/tpm0"
struct _virDomainTPMDef {
@@ -1381,6 +1390,7 @@ struct _virDomainTPMDef {
unsigned char secretuuid[VIR_UUID_BUFLEN];
bool hassecretuuid;
bool persistent_state;
+ unsigned int activePcrBanks;
} emulator;
} data;
};
@@ -3941,6 +3951,7 @@ VIR_ENUM_DECL(virDomainRNGBackend);
VIR_ENUM_DECL(virDomainTPMModel);
VIR_ENUM_DECL(virDomainTPMBackend);
VIR_ENUM_DECL(virDomainTPMVersion);
+VIR_ENUM_DECL(virDomainTPMPcrBank);
VIR_ENUM_DECL(virDomainMemoryModel);
VIR_ENUM_DECL(virDomainMemoryBackingModel);
VIR_ENUM_DECL(virDomainMemorySource);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 55ae7d5b6f..69ff1ca430 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -667,6 +667,8 @@ virDomainTPMBackendTypeToString;
virDomainTPMDefFree;
virDomainTPMModelTypeFromString;
virDomainTPMModelTypeToString;
+virDomainTPMPcrBankTypeFromString;
+virDomainTPMPcrBankTypeToString;
virDomainUSBDeviceDefForeach;
virDomainVideoDefaultRAM;
virDomainVideoDefClear;
diff --git a/src/qemu/qemu_tpm.c b/src/qemu/qemu_tpm.c
index 94a0d3a1f9..b305313ad2 100644
--- a/src/qemu/qemu_tpm.c
+++ b/src/qemu/qemu_tpm.c
@@ -565,6 +565,96 @@ qemuTPMEmulatorRunSetup(const char *storagepath,
}
+static char *
+qemuTPMPcrBankBitmapToStr(unsigned int pcrBanks)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+ const char *comma = "";
+ size_t i;
+
+ for (i = VIR_DOMAIN_TPM_PCR_BANK_SHA1; i < VIR_DOMAIN_TPM_PCR_BANK_LAST; i++) {
+ if (pcrBanks & (1 << i)) {
+ virBufferAsprintf(&buf, "%s%s",
+ comma, virDomainTPMPcrBankTypeToString(i));
+ comma = ",";
+ }
+ }
+ return virBufferContentAndReset(&buf);
+}
+
+
+/*
+ * 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
+ * @activePcrBanks: 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,
+ unsigned int activePcrBanks,
+ const char *logfile,
+ const virDomainTPMVersion tpmversion,
+ const unsigned char *secretuuid)
+{
+ g_autoptr(virCommand) cmd = NULL;
+ int exitstatus;
+ g_autofree char *activePcrBanksStr;
+ g_autofree char *swtpm_setup = virTPMGetSwtpmSetup();
+ VIR_AUTOCLOSE pwdfile_fd = -1;
+
+ if (!swtpm_setup)
+ return -1;
+
+ if (tpmversion != VIR_DOMAIN_TPM_VERSION_2_0 ||
+ (activePcrBanksStr = qemuTPMPcrBankBitmapToStr(activePcrBanks)) == 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", activePcrBanksStr,
+ "--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:
*
@@ -619,6 +709,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..68db8b9232 100644
--- a/tests/qemuxml2argvdata/tpm-emulator-tpm2.xml
+++ b/tests/qemuxml2argvdata/tpm-emulator-tpm2.xml
@@ -23,7 +23,12 @@
<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/>
+ </active_pcr_banks>
+ </backend>
</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..edab6db123 100644
--- a/tests/qemuxml2xmloutdata/tpm-emulator-tpm2.x86_64-latest.xml
+++ b/tests/qemuxml2xmloutdata/tpm-emulator-tpm2.x86_64-latest.xml
@@ -28,7 +28,12 @@
<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/>
+ </active_pcr_banks>
+ </backend>
</tpm>
<audio id='1' type='none'/>
<memballoon model='virtio'>
--
2.31.1