[RFC PATCH v2 0/8] swtpm: Add support for profiles

Upcoming libtpms v0.10 and swtpm v0.10 will have TPM profile support that allows to restrict a TPM's provided set of crypto algorithms and commands and through which backwards compatibility and migration from newer versions of libtpms to older ones (up to libtpms v0.9) is supported. For the latter to work it is necessary that the user chooses the right ('null') profile. This series adds support for passing a profile choice to swtpm_setup by setting it in the domain XML using the <profile/> XML node. An optional attribute 'remove_disabled' can be set in this node and accepts two values: "check": test a few crypto algorithms (tdes, camellia, unpadded encryption, and others) for whether they are currently disabled due to FIPS mode on the host and remove these algorithms in the 'custom' profile if they are disabled; "fips-host": do not test but remove all the possibly disabled crypto algorithms (from list above) Also extend the documentation but point the user to swtpm and libtpms documentation for further details. Follow Deniel's suggestions there's now a PR for swtpm_setup to support searching for profiles though a configurable local directory, distro directory and if no profile could be found there (with appended ".json" suffix) it will fall back to try to use a built-in profile by the provided name: https://github.com/stefanberger/swtpm/pull/918 Stefan Stefan Berger (8): conf: Move TPM emulator parameters into own struct qemu: Pass virQEMUDriverConfig rather than some of its fields util: Add parsing support for swtpm_setup's cmdarg-profile capability conf: Define enum virDomainTPMProfileRemoveDisabled schema: Extend schema for TPM emulator profile node conf: Add support for profile parameter on TPM emulator in domain XML docs: Add documentation for the TPM backend profile node qemu: Extend swtpm_setup command line to set a profile by its name docs/formatdomain.rst | 30 ++++++++ src/conf/domain_conf.c | 43 +++++++++++ src/conf/domain_conf.h | 35 ++++++--- src/conf/domain_validate.c | 7 ++ src/conf/schemas/domaincommon.rng | 25 ++++++ src/conf/virconftypes.h | 2 + src/qemu/qemu_tpm.c | 124 +++++++++++++++++------------- src/util/virtpm.c | 1 + src/util/virtpm.h | 1 + tests/testutilsqemu.c | 1 + 10 files changed, 203 insertions(+), 66 deletions(-) -- 2.46.1

To avoid passing TPM emulator parameters around individually, move them into a structure and pass around the structure. Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> --- src/conf/domain_conf.h | 24 ++++++++++++---------- src/conf/virconftypes.h | 2 ++ src/qemu/qemu_tpm.c | 45 ++++++++++++++++------------------------- 3 files changed, 32 insertions(+), 39 deletions(-) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index a15af4fae3..e5aee3c2cf 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1465,6 +1465,18 @@ typedef enum { #define VIR_DOMAIN_TPM_DEFAULT_DEVICE "/dev/tpm0" +struct _virDomainTPMEmulatorDef { + virDomainTPMVersion version; + virDomainChrSourceDef *source; + char *storagepath; + char *logfile; + unsigned int debug; + unsigned char secretuuid[VIR_UUID_BUFLEN]; + bool hassecretuuid; + bool persistent_state; + virBitmap *activePcrBanks; +}; + struct _virDomainTPMDef { virObject *privateData; @@ -1475,17 +1487,7 @@ struct _virDomainTPMDef { struct { virDomainChrSourceDef *source; } passthrough; - struct { - virDomainTPMVersion version; - virDomainChrSourceDef *source; - char *storagepath; - char *logfile; - unsigned int debug; - unsigned char secretuuid[VIR_UUID_BUFLEN]; - bool hassecretuuid; - bool persistent_state; - virBitmap *activePcrBanks; - } emulator; + virDomainTPMEmulatorDef emulator; struct { virDomainChrSourceDef *source; } external; diff --git a/src/conf/virconftypes.h b/src/conf/virconftypes.h index f18ebcca10..59be61cea4 100644 --- a/src/conf/virconftypes.h +++ b/src/conf/virconftypes.h @@ -234,6 +234,8 @@ typedef struct _virDomainAudioDef virDomainAudioDef; typedef struct _virDomainTPMDef virDomainTPMDef; +typedef struct _virDomainTPMEmulatorDef virDomainTPMEmulatorDef; + typedef struct _virDomainThreadSchedParam virDomainThreadSchedParam; typedef struct _virDomainTimerCatchupDef virDomainTimerCatchupDef; diff --git a/src/qemu/qemu_tpm.c b/src/qemu/qemu_tpm.c index 2f17918cbb..592fcc62fa 100644 --- a/src/qemu/qemu_tpm.c +++ b/src/qemu/qemu_tpm.c @@ -350,10 +350,8 @@ qemuTPMVirCommandAddEncryption(virCommand *cmd, * @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 - * @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 - * @encryption: pointer to virStorageEncryption holding secret + * @emulator: emulator parameters + * @secretuuid: UUID describing virStorageEncryption holding secret * @incomingMigration: whether we have an incoming migration * * Setup the external swtpm by creating endorsement key and @@ -366,8 +364,7 @@ qemuTPMEmulatorRunSetup(const char *storagepath, bool privileged, uid_t swtpm_user, gid_t swtpm_group, - const char *logfile, - const virDomainTPMVersion tpmversion, + const virDomainTPMEmulatorDef *emulator, const unsigned char *secretuuid, bool incomingMigration) { @@ -380,9 +377,9 @@ qemuTPMEmulatorRunSetup(const char *storagepath, if (!swtpm_setup) return -1; - if (!privileged && tpmversion == VIR_DOMAIN_TPM_VERSION_1_2 && + if (!privileged && emulator->version == VIR_DOMAIN_TPM_VERSION_1_2 && !virTPMSwtpmSetupCapsGet(VIR_TPM_SWTPM_SETUP_FEATURE_TPM12_NOT_NEED_ROOT)) { - return virFileWriteStr(logfile, + return virFileWriteStr(emulator->logfile, _("Did not create EK and certificates since this requires privileged mode for a TPM 1.2\n"), 0600); } @@ -397,7 +394,7 @@ qemuTPMEmulatorRunSetup(const char *storagepath, virCommandSetUID(cmd, swtpm_user); virCommandSetGID(cmd, swtpm_group); - switch (tpmversion) { + switch (emulator->version) { case VIR_DOMAIN_TPM_VERSION_1_2: break; case VIR_DOMAIN_TPM_VERSION_2_0: @@ -415,7 +412,7 @@ qemuTPMEmulatorRunSetup(const char *storagepath, virCommandAddArgList(cmd, "--tpm-state", storagepath, "--vmid", vmid, - "--logfile", logfile, + "--logfile", emulator->logfile, "--createek", "--create-ek-cert", "--create-platform-cert", @@ -425,7 +422,7 @@ qemuTPMEmulatorRunSetup(const char *storagepath, } else { virCommandAddArgList(cmd, "--tpm-state", storagepath, - "--logfile", logfile, + "--logfile", emulator->logfile, "--overwrite", NULL); } @@ -435,7 +432,7 @@ qemuTPMEmulatorRunSetup(const char *storagepath, if (virCommandRun(cmd, &exitstatus) < 0 || exitstatus != 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not run '%1$s'. exitstatus: %2$d; Check error log '%3$s' for details."), - swtpm_setup, exitstatus, logfile); + swtpm_setup, exitstatus, emulator->logfile); return -1; } @@ -469,10 +466,7 @@ qemuTPMPcrBankBitmapToStr(virBitmap *activePcrBanks) * @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 + * @emulator: emulator parameters * @secretuuid: The secret's UUID needed for state encryption * * Reconfigure the active PCR banks of a TPM 2. @@ -481,9 +475,7 @@ static int qemuTPMEmulatorReconfigure(const char *storagepath, uid_t swtpm_user, gid_t swtpm_group, - virBitmap *activePcrBanks, - const char *logfile, - const virDomainTPMVersion tpmversion, + const virDomainTPMEmulatorDef *emulator, const unsigned char *secretuuid) { g_autoptr(virCommand) cmd = NULL; @@ -494,8 +486,8 @@ qemuTPMEmulatorReconfigure(const char *storagepath, if (!swtpm_setup) return -1; - if (tpmversion != VIR_DOMAIN_TPM_VERSION_2_0 || - (activePcrBanksStr = qemuTPMPcrBankBitmapToStr(activePcrBanks)) == NULL || + if (emulator->version != VIR_DOMAIN_TPM_VERSION_2_0 || + (activePcrBanksStr = qemuTPMPcrBankBitmapToStr(emulator->activePcrBanks)) == NULL || !virTPMSwtpmSetupCapsGet(VIR_TPM_SWTPM_SETUP_FEATURE_CMDARG_RECONFIGURE_PCR_BANKS)) return 0; @@ -511,7 +503,7 @@ qemuTPMEmulatorReconfigure(const char *storagepath, virCommandAddArgList(cmd, "--tpm-state", storagepath, - "--logfile", logfile, + "--logfile", emulator->logfile, "--pcr-banks", activePcrBanksStr, "--reconfigure", NULL); @@ -521,7 +513,7 @@ qemuTPMEmulatorReconfigure(const char *storagepath, if (virCommandRun(cmd, &exitstatus) < 0 || exitstatus != 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not run '%1$s --reconfigure'. exitstatus: %2$d; Check error log '%3$s' for details."), - swtpm_setup, exitstatus, logfile); + swtpm_setup, exitstatus, emulator->logfile); return -1; } @@ -582,17 +574,14 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm, if (created && qemuTPMEmulatorRunSetup(tpm->data.emulator.storagepath, vmname, vmuuid, privileged, swtpm_user, swtpm_group, - tpm->data.emulator.logfile, - tpm->data.emulator.version, + &tpm->data.emulator, 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->data.emulator.version, + &tpm->data.emulator, secretuuid) < 0) goto error; -- 2.46.1

On Thu, Sep 26, 2024 at 11:38 PM Stefan Berger <stefanb@linux.ibm.com> wrote:
To avoid passing TPM emulator parameters around individually, move them into a structure and pass around the structure.
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
--- src/conf/domain_conf.h | 24 ++++++++++++---------- src/conf/virconftypes.h | 2 ++ src/qemu/qemu_tpm.c | 45 ++++++++++++++++------------------------- 3 files changed, 32 insertions(+), 39 deletions(-)
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index a15af4fae3..e5aee3c2cf 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1465,6 +1465,18 @@ typedef enum {
#define VIR_DOMAIN_TPM_DEFAULT_DEVICE "/dev/tpm0"
+struct _virDomainTPMEmulatorDef { + virDomainTPMVersion version; + virDomainChrSourceDef *source; + char *storagepath; + char *logfile; + unsigned int debug; + unsigned char secretuuid[VIR_UUID_BUFLEN]; + bool hassecretuuid; + bool persistent_state; + virBitmap *activePcrBanks; +}; + struct _virDomainTPMDef { virObject *privateData;
@@ -1475,17 +1487,7 @@ struct _virDomainTPMDef { struct { virDomainChrSourceDef *source; } passthrough; - struct { - virDomainTPMVersion version; - virDomainChrSourceDef *source; - char *storagepath; - char *logfile; - unsigned int debug; - unsigned char secretuuid[VIR_UUID_BUFLEN]; - bool hassecretuuid; - bool persistent_state; - virBitmap *activePcrBanks; - } emulator; + virDomainTPMEmulatorDef emulator; struct { virDomainChrSourceDef *source; } external; diff --git a/src/conf/virconftypes.h b/src/conf/virconftypes.h index f18ebcca10..59be61cea4 100644 --- a/src/conf/virconftypes.h +++ b/src/conf/virconftypes.h @@ -234,6 +234,8 @@ typedef struct _virDomainAudioDef virDomainAudioDef;
typedef struct _virDomainTPMDef virDomainTPMDef;
+typedef struct _virDomainTPMEmulatorDef virDomainTPMEmulatorDef; + typedef struct _virDomainThreadSchedParam virDomainThreadSchedParam;
typedef struct _virDomainTimerCatchupDef virDomainTimerCatchupDef; diff --git a/src/qemu/qemu_tpm.c b/src/qemu/qemu_tpm.c index 2f17918cbb..592fcc62fa 100644 --- a/src/qemu/qemu_tpm.c +++ b/src/qemu/qemu_tpm.c @@ -350,10 +350,8 @@ qemuTPMVirCommandAddEncryption(virCommand *cmd, * @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 - * @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 - * @encryption: pointer to virStorageEncryption holding secret + * @emulator: emulator parameters + * @secretuuid: UUID describing virStorageEncryption holding secret * @incomingMigration: whether we have an incoming migration * * Setup the external swtpm by creating endorsement key and @@ -366,8 +364,7 @@ qemuTPMEmulatorRunSetup(const char *storagepath, bool privileged, uid_t swtpm_user, gid_t swtpm_group, - const char *logfile, - const virDomainTPMVersion tpmversion, + const virDomainTPMEmulatorDef *emulator, const unsigned char *secretuuid, bool incomingMigration) { @@ -380,9 +377,9 @@ qemuTPMEmulatorRunSetup(const char *storagepath, if (!swtpm_setup) return -1;
- if (!privileged && tpmversion == VIR_DOMAIN_TPM_VERSION_1_2 && + if (!privileged && emulator->version == VIR_DOMAIN_TPM_VERSION_1_2 && !virTPMSwtpmSetupCapsGet(VIR_TPM_SWTPM_SETUP_FEATURE_TPM12_NOT_NEED_ROOT)) { - return virFileWriteStr(logfile, + return virFileWriteStr(emulator->logfile, _("Did not create EK and certificates since this requires privileged mode for a TPM 1.2\n"), 0600); }
@@ -397,7 +394,7 @@ qemuTPMEmulatorRunSetup(const char *storagepath, virCommandSetUID(cmd, swtpm_user); virCommandSetGID(cmd, swtpm_group);
- switch (tpmversion) { + switch (emulator->version) { case VIR_DOMAIN_TPM_VERSION_1_2: break; case VIR_DOMAIN_TPM_VERSION_2_0: @@ -415,7 +412,7 @@ qemuTPMEmulatorRunSetup(const char *storagepath, virCommandAddArgList(cmd, "--tpm-state", storagepath, "--vmid", vmid, - "--logfile", logfile, + "--logfile", emulator->logfile, "--createek", "--create-ek-cert", "--create-platform-cert", @@ -425,7 +422,7 @@ qemuTPMEmulatorRunSetup(const char *storagepath, } else { virCommandAddArgList(cmd, "--tpm-state", storagepath, - "--logfile", logfile, + "--logfile", emulator->logfile, "--overwrite", NULL); } @@ -435,7 +432,7 @@ qemuTPMEmulatorRunSetup(const char *storagepath, if (virCommandRun(cmd, &exitstatus) < 0 || exitstatus != 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not run '%1$s'. exitstatus: %2$d; Check error log '%3$s' for details."), - swtpm_setup, exitstatus, logfile); + swtpm_setup, exitstatus, emulator->logfile); return -1; }
@@ -469,10 +466,7 @@ qemuTPMPcrBankBitmapToStr(virBitmap *activePcrBanks) * @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 + * @emulator: emulator parameters * @secretuuid: The secret's UUID needed for state encryption * * Reconfigure the active PCR banks of a TPM 2. @@ -481,9 +475,7 @@ static int qemuTPMEmulatorReconfigure(const char *storagepath, uid_t swtpm_user, gid_t swtpm_group, - virBitmap *activePcrBanks, - const char *logfile, - const virDomainTPMVersion tpmversion, + const virDomainTPMEmulatorDef *emulator, const unsigned char *secretuuid) { g_autoptr(virCommand) cmd = NULL; @@ -494,8 +486,8 @@ qemuTPMEmulatorReconfigure(const char *storagepath, if (!swtpm_setup) return -1;
- if (tpmversion != VIR_DOMAIN_TPM_VERSION_2_0 || - (activePcrBanksStr = qemuTPMPcrBankBitmapToStr(activePcrBanks)) == NULL || + if (emulator->version != VIR_DOMAIN_TPM_VERSION_2_0 || + (activePcrBanksStr = qemuTPMPcrBankBitmapToStr(emulator->activePcrBanks)) == NULL || !virTPMSwtpmSetupCapsGet(VIR_TPM_SWTPM_SETUP_FEATURE_CMDARG_RECONFIGURE_PCR_BANKS)) return 0;
@@ -511,7 +503,7 @@ qemuTPMEmulatorReconfigure(const char *storagepath,
virCommandAddArgList(cmd, "--tpm-state", storagepath, - "--logfile", logfile, + "--logfile", emulator->logfile, "--pcr-banks", activePcrBanksStr, "--reconfigure", NULL); @@ -521,7 +513,7 @@ qemuTPMEmulatorReconfigure(const char *storagepath, if (virCommandRun(cmd, &exitstatus) < 0 || exitstatus != 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not run '%1$s --reconfigure'. exitstatus: %2$d; Check error log '%3$s' for details."), - swtpm_setup, exitstatus, logfile); + swtpm_setup, exitstatus, emulator->logfile); return -1; }
@@ -582,17 +574,14 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm, if (created && qemuTPMEmulatorRunSetup(tpm->data.emulator.storagepath, vmname, vmuuid, privileged, swtpm_user, swtpm_group, - tpm->data.emulator.logfile, - tpm->data.emulator.version, + &tpm->data.emulator, 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->data.emulator.version, + &tpm->data.emulator, secretuuid) < 0) goto error;
-- 2.46.1

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> --- src/qemu/qemu_tpm.c | 47 +++++++++++++++++---------------------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/src/qemu/qemu_tpm.c b/src/qemu/qemu_tpm.c index 592fcc62fa..e8e7e8b5c1 100644 --- a/src/qemu/qemu_tpm.c +++ b/src/qemu/qemu_tpm.c @@ -347,9 +347,7 @@ qemuTPMVirCommandAddEncryption(virCommand *cmd, * @vmname: the name of the VM * @vmuuid: the UUID of the VM * @privileged: whether we are running in privileged mode - * @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 + * @cfg: virQEMUDriverConfig * @emulator: emulator parameters * @secretuuid: UUID describing virStorageEncryption holding secret * @incomingMigration: whether we have an incoming migration @@ -362,8 +360,7 @@ qemuTPMEmulatorRunSetup(const char *storagepath, const char *vmname, const unsigned char *vmuuid, bool privileged, - uid_t swtpm_user, - gid_t swtpm_group, + const virQEMUDriverConfig *cfg, const virDomainTPMEmulatorDef *emulator, const unsigned char *secretuuid, bool incomingMigration) @@ -391,8 +388,8 @@ qemuTPMEmulatorRunSetup(const char *storagepath, virUUIDFormat(vmuuid, uuid); vmid = g_strdup_printf("%s:%s", vmname, uuid); - virCommandSetUID(cmd, swtpm_user); - virCommandSetGID(cmd, swtpm_group); + virCommandSetUID(cmd, cfg->swtpm_user); /* should be uid of 'tss' or 'root' */ + virCommandSetGID(cmd, cfg->swtpm_group); switch (emulator->version) { case VIR_DOMAIN_TPM_VERSION_1_2: @@ -463,9 +460,7 @@ qemuTPMPcrBankBitmapToStr(virBitmap *activePcrBanks) * * * @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 + * @cfg: virQEMUDriverConfig * @emulator: emulator parameters * @secretuuid: The secret's UUID needed for state encryption * @@ -473,8 +468,7 @@ qemuTPMPcrBankBitmapToStr(virBitmap *activePcrBanks) */ static int qemuTPMEmulatorReconfigure(const char *storagepath, - uid_t swtpm_user, - gid_t swtpm_group, + const virQEMUDriverConfig *cfg, const virDomainTPMEmulatorDef *emulator, const unsigned char *secretuuid) { @@ -493,8 +487,8 @@ qemuTPMEmulatorReconfigure(const char *storagepath, cmd = virCommandNew(swtpm_setup); - virCommandSetUID(cmd, swtpm_user); - virCommandSetGID(cmd, swtpm_group); + virCommandSetUID(cmd, cfg->swtpm_user); /* should be uid of 'tss' or 'root' */ + virCommandSetGID(cmd, cfg->swtpm_group); virCommandAddArgList(cmd, "--tpm2", NULL); @@ -528,8 +522,7 @@ qemuTPMEmulatorReconfigure(const char *storagepath, * @vmname: The name of the VM * @vmuuid: The UUID of the VM * @privileged: whether we are running in privileged mode - * @swtpm_user: The uid for the swtpm to run as (drop privileges to from root) - * @swtpm_group: The gid for the swtpm to run as + * @cfg: virQEMUDriverConfig * @incomingMigration: whether we have an incoming migration * * Create the virCommand use for starting the emulator @@ -541,8 +534,7 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm, const char *vmname, const unsigned char *vmuuid, bool privileged, - uid_t swtpm_user, - gid_t swtpm_group, + const virQEMUDriverConfig *cfg, bool incomingMigration) { g_autoptr(virCommand) cmd = NULL; @@ -565,7 +557,8 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm, create_storage = false; if (create_storage && - qemuTPMEmulatorCreateStorage(tpm, &created, swtpm_user, swtpm_group) < 0) + qemuTPMEmulatorCreateStorage(tpm, &created, + cfg->swtpm_user, cfg->swtpm_group) < 0) return NULL; if (tpm->data.emulator.hassecretuuid) @@ -573,16 +566,13 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm, if (created && qemuTPMEmulatorRunSetup(tpm->data.emulator.storagepath, vmname, vmuuid, - privileged, swtpm_user, swtpm_group, - &tpm->data.emulator, + privileged, cfg, &tpm->data.emulator, secretuuid, incomingMigration) < 0) goto error; if (!incomingMigration && - qemuTPMEmulatorReconfigure(tpm->data.emulator.storagepath, - swtpm_user, swtpm_group, - &tpm->data.emulator, - secretuuid) < 0) + qemuTPMEmulatorReconfigure(tpm->data.emulator.storagepath, cfg, + &tpm->data.emulator, secretuuid) < 0) goto error; unlink(tpm->data.emulator.source->data.nix.path); @@ -608,8 +598,8 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm, virCommandAddArg(cmd, "--terminate"); - virCommandSetUID(cmd, swtpm_user); - virCommandSetGID(cmd, swtpm_group); + virCommandSetUID(cmd, cfg->swtpm_user); + virCommandSetGID(cmd, cfg->swtpm_group); switch (tpm->data.emulator.version) { case VIR_DOMAIN_TPM_VERSION_1_2: @@ -926,8 +916,7 @@ qemuTPMEmulatorStart(virQEMUDriver *driver, if (!(cmd = qemuTPMEmulatorBuildCommand(tpm, vm->def->name, vm->def->uuid, driver->privileged, - cfg->swtpm_user, - cfg->swtpm_group, + cfg, incomingMigration))) return -1; -- 2.46.1

On Thu, Sep 26, 2024 at 11:32 PM Stefan Berger <stefanb@linux.ibm.com> wrote:
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
--- src/qemu/qemu_tpm.c | 47 +++++++++++++++++---------------------------- 1 file changed, 18 insertions(+), 29 deletions(-)
diff --git a/src/qemu/qemu_tpm.c b/src/qemu/qemu_tpm.c index 592fcc62fa..e8e7e8b5c1 100644 --- a/src/qemu/qemu_tpm.c +++ b/src/qemu/qemu_tpm.c @@ -347,9 +347,7 @@ qemuTPMVirCommandAddEncryption(virCommand *cmd, * @vmname: the name of the VM * @vmuuid: the UUID of the VM * @privileged: whether we are running in privileged mode - * @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 + * @cfg: virQEMUDriverConfig * @emulator: emulator parameters * @secretuuid: UUID describing virStorageEncryption holding secret * @incomingMigration: whether we have an incoming migration @@ -362,8 +360,7 @@ qemuTPMEmulatorRunSetup(const char *storagepath, const char *vmname, const unsigned char *vmuuid, bool privileged, - uid_t swtpm_user, - gid_t swtpm_group, + const virQEMUDriverConfig *cfg, const virDomainTPMEmulatorDef *emulator, const unsigned char *secretuuid, bool incomingMigration) @@ -391,8 +388,8 @@ qemuTPMEmulatorRunSetup(const char *storagepath, virUUIDFormat(vmuuid, uuid); vmid = g_strdup_printf("%s:%s", vmname, uuid);
- virCommandSetUID(cmd, swtpm_user); - virCommandSetGID(cmd, swtpm_group); + virCommandSetUID(cmd, cfg->swtpm_user); /* should be uid of 'tss' or 'root' */ + virCommandSetGID(cmd, cfg->swtpm_group);
switch (emulator->version) { case VIR_DOMAIN_TPM_VERSION_1_2: @@ -463,9 +460,7 @@ qemuTPMPcrBankBitmapToStr(virBitmap *activePcrBanks) * * * @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 + * @cfg: virQEMUDriverConfig * @emulator: emulator parameters * @secretuuid: The secret's UUID needed for state encryption * @@ -473,8 +468,7 @@ qemuTPMPcrBankBitmapToStr(virBitmap *activePcrBanks) */ static int qemuTPMEmulatorReconfigure(const char *storagepath, - uid_t swtpm_user, - gid_t swtpm_group, + const virQEMUDriverConfig *cfg, const virDomainTPMEmulatorDef *emulator, const unsigned char *secretuuid) { @@ -493,8 +487,8 @@ qemuTPMEmulatorReconfigure(const char *storagepath,
cmd = virCommandNew(swtpm_setup);
- virCommandSetUID(cmd, swtpm_user); - virCommandSetGID(cmd, swtpm_group); + virCommandSetUID(cmd, cfg->swtpm_user); /* should be uid of 'tss' or 'root' */ + virCommandSetGID(cmd, cfg->swtpm_group);
virCommandAddArgList(cmd, "--tpm2", NULL);
@@ -528,8 +522,7 @@ qemuTPMEmulatorReconfigure(const char *storagepath, * @vmname: The name of the VM * @vmuuid: The UUID of the VM * @privileged: whether we are running in privileged mode - * @swtpm_user: The uid for the swtpm to run as (drop privileges to from root) - * @swtpm_group: The gid for the swtpm to run as + * @cfg: virQEMUDriverConfig * @incomingMigration: whether we have an incoming migration * * Create the virCommand use for starting the emulator @@ -541,8 +534,7 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm, const char *vmname, const unsigned char *vmuuid, bool privileged, - uid_t swtpm_user, - gid_t swtpm_group, + const virQEMUDriverConfig *cfg, bool incomingMigration) { g_autoptr(virCommand) cmd = NULL; @@ -565,7 +557,8 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm, create_storage = false;
if (create_storage && - qemuTPMEmulatorCreateStorage(tpm, &created, swtpm_user, swtpm_group) < 0) + qemuTPMEmulatorCreateStorage(tpm, &created, + cfg->swtpm_user, cfg->swtpm_group) < 0) return NULL;
if (tpm->data.emulator.hassecretuuid) @@ -573,16 +566,13 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm,
if (created && qemuTPMEmulatorRunSetup(tpm->data.emulator.storagepath, vmname, vmuuid, - privileged, swtpm_user, swtpm_group, - &tpm->data.emulator, + privileged, cfg, &tpm->data.emulator, secretuuid, incomingMigration) < 0) goto error;
if (!incomingMigration && - qemuTPMEmulatorReconfigure(tpm->data.emulator.storagepath, - swtpm_user, swtpm_group, - &tpm->data.emulator, - secretuuid) < 0) + qemuTPMEmulatorReconfigure(tpm->data.emulator.storagepath, cfg, + &tpm->data.emulator, secretuuid) < 0) goto error;
unlink(tpm->data.emulator.source->data.nix.path); @@ -608,8 +598,8 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm,
virCommandAddArg(cmd, "--terminate");
- virCommandSetUID(cmd, swtpm_user); - virCommandSetGID(cmd, swtpm_group); + virCommandSetUID(cmd, cfg->swtpm_user); + virCommandSetGID(cmd, cfg->swtpm_group);
switch (tpm->data.emulator.version) { case VIR_DOMAIN_TPM_VERSION_1_2: @@ -926,8 +916,7 @@ qemuTPMEmulatorStart(virQEMUDriver *driver,
if (!(cmd = qemuTPMEmulatorBuildCommand(tpm, vm->def->name, vm->def->uuid, driver->privileged, - cfg->swtpm_user, - cfg->swtpm_group, + cfg, incomingMigration))) return -1;
-- 2.46.1

Add support for parsing swtpm_setup 'cmdarg-profile' capability (since v0.10). Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> --- src/util/virtpm.c | 1 + src/util/virtpm.h | 1 + tests/testutilsqemu.c | 1 + 3 files changed, 3 insertions(+) diff --git a/src/util/virtpm.c b/src/util/virtpm.c index 81fd6166cf..d991657696 100644 --- a/src/util/virtpm.c +++ b/src/util/virtpm.c @@ -50,6 +50,7 @@ VIR_ENUM_IMPL(virTPMSwtpmSetupFeature, "cmdarg-reconfigure-pcr-banks", "tpm-1.2", "tpm-2.0", + "cmdarg-profile", ); /** diff --git a/src/util/virtpm.h b/src/util/virtpm.h index fb330effa8..18c2877c03 100644 --- a/src/util/virtpm.h +++ b/src/util/virtpm.h @@ -42,6 +42,7 @@ typedef enum { VIR_TPM_SWTPM_SETUP_FEATURE_CMDARG_RECONFIGURE_PCR_BANKS, VIR_TPM_SWTPM_SETUP_FEATURE_TPM_1_2, VIR_TPM_SWTPM_SETUP_FEATURE_TPM_2_0, + VIR_TPM_SWTPM_SETUP_FEATURE_CMDARG_PROFILE, VIR_TPM_SWTPM_SETUP_FEATURE_LAST } virTPMSwtpmSetupFeature; diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c index ee6cae218a..ba4677fb4c 100644 --- a/tests/testutilsqemu.c +++ b/tests/testutilsqemu.c @@ -71,6 +71,7 @@ virTPMSwtpmSetupCapsGet(virTPMSwtpmSetupFeature cap) case VIR_TPM_SWTPM_SETUP_FEATURE_CMDARG_CREATE_CONFIG_FILES: case VIR_TPM_SWTPM_SETUP_FEATURE_TPM12_NOT_NEED_ROOT: case VIR_TPM_SWTPM_SETUP_FEATURE_CMDARG_RECONFIGURE_PCR_BANKS: + case VIR_TPM_SWTPM_SETUP_FEATURE_CMDARG_PROFILE: case VIR_TPM_SWTPM_SETUP_FEATURE_LAST: break; } -- 2.46.1

On Thu, Sep 26, 2024 at 11:32 PM Stefan Berger <stefanb@linux.ibm.com> wrote:
Add support for parsing swtpm_setup 'cmdarg-profile' capability (since v0.10).
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
--- src/util/virtpm.c | 1 + src/util/virtpm.h | 1 + tests/testutilsqemu.c | 1 + 3 files changed, 3 insertions(+)
diff --git a/src/util/virtpm.c b/src/util/virtpm.c index 81fd6166cf..d991657696 100644 --- a/src/util/virtpm.c +++ b/src/util/virtpm.c @@ -50,6 +50,7 @@ VIR_ENUM_IMPL(virTPMSwtpmSetupFeature, "cmdarg-reconfigure-pcr-banks", "tpm-1.2", "tpm-2.0", + "cmdarg-profile", );
/** diff --git a/src/util/virtpm.h b/src/util/virtpm.h index fb330effa8..18c2877c03 100644 --- a/src/util/virtpm.h +++ b/src/util/virtpm.h @@ -42,6 +42,7 @@ typedef enum { VIR_TPM_SWTPM_SETUP_FEATURE_CMDARG_RECONFIGURE_PCR_BANKS, VIR_TPM_SWTPM_SETUP_FEATURE_TPM_1_2, VIR_TPM_SWTPM_SETUP_FEATURE_TPM_2_0, + VIR_TPM_SWTPM_SETUP_FEATURE_CMDARG_PROFILE,
VIR_TPM_SWTPM_SETUP_FEATURE_LAST } virTPMSwtpmSetupFeature; diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c index ee6cae218a..ba4677fb4c 100644 --- a/tests/testutilsqemu.c +++ b/tests/testutilsqemu.c @@ -71,6 +71,7 @@ virTPMSwtpmSetupCapsGet(virTPMSwtpmSetupFeature cap) case VIR_TPM_SWTPM_SETUP_FEATURE_CMDARG_CREATE_CONFIG_FILES: case VIR_TPM_SWTPM_SETUP_FEATURE_TPM12_NOT_NEED_ROOT: case VIR_TPM_SWTPM_SETUP_FEATURE_CMDARG_RECONFIGURE_PCR_BANKS: + case VIR_TPM_SWTPM_SETUP_FEATURE_CMDARG_PROFILE: case VIR_TPM_SWTPM_SETUP_FEATURE_LAST: break; } -- 2.46.1

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> --- src/conf/domain_conf.c | 7 +++++++ src/conf/domain_conf.h | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 7f6a91c427..1c8fffdfa5 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1330,6 +1330,13 @@ VIR_ENUM_IMPL(virDomainTPMPcrBank, "sha512", ); +VIR_ENUM_IMPL(virDomainTPMProfileRemoveDisabled, + VIR_DOMAIN_TPM_PROFILE_REMOVE_DISABLED_LAST, + "none", + "check", + "fips-host", +); + VIR_ENUM_IMPL(virDomainIOMMUModel, VIR_DOMAIN_IOMMU_MODEL_LAST, "intel", diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index e5aee3c2cf..ec821ea6fc 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1463,6 +1463,14 @@ typedef enum { VIR_DOMAIN_TPM_PCR_BANK_LAST } virDomainPcrBank; +typedef enum { + VIR_DOMAIN_TPM_PROFILE_REMOVE_DISABLED_NONE = 0, + VIR_DOMAIN_TPM_PROFILE_REMOVE_DISABLED_CHECK, + VIR_DOMAIN_TPM_PROFILE_REMOVE_DISABLED_FIPS_HOST, + + VIR_DOMAIN_TPM_PROFILE_REMOVE_DISABLED_LAST +} virDomainTPMProfileRemoveDisabled; + #define VIR_DOMAIN_TPM_DEFAULT_DEVICE "/dev/tpm0" struct _virDomainTPMEmulatorDef { @@ -4280,6 +4288,7 @@ VIR_ENUM_DECL(virDomainTPMModel); VIR_ENUM_DECL(virDomainTPMBackend); VIR_ENUM_DECL(virDomainTPMVersion); VIR_ENUM_DECL(virDomainTPMPcrBank); +VIR_ENUM_DECL(virDomainTPMProfileRemoveDisabled); VIR_ENUM_DECL(virDomainMemoryModel); VIR_ENUM_DECL(virDomainMemoryBackingModel); VIR_ENUM_DECL(virDomainMemorySource); -- 2.46.1

On Thu, Sep 26, 2024 at 11:32 PM Stefan Berger <stefanb@linux.ibm.com> wrote:
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
--- src/conf/domain_conf.c | 7 +++++++ src/conf/domain_conf.h | 9 +++++++++ 2 files changed, 16 insertions(+)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 7f6a91c427..1c8fffdfa5 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1330,6 +1330,13 @@ VIR_ENUM_IMPL(virDomainTPMPcrBank, "sha512", );
+VIR_ENUM_IMPL(virDomainTPMProfileRemoveDisabled, + VIR_DOMAIN_TPM_PROFILE_REMOVE_DISABLED_LAST, + "none", + "check", + "fips-host", +); + VIR_ENUM_IMPL(virDomainIOMMUModel, VIR_DOMAIN_IOMMU_MODEL_LAST, "intel", diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index e5aee3c2cf..ec821ea6fc 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1463,6 +1463,14 @@ typedef enum { VIR_DOMAIN_TPM_PCR_BANK_LAST } virDomainPcrBank;
+typedef enum { + VIR_DOMAIN_TPM_PROFILE_REMOVE_DISABLED_NONE = 0, + VIR_DOMAIN_TPM_PROFILE_REMOVE_DISABLED_CHECK, + VIR_DOMAIN_TPM_PROFILE_REMOVE_DISABLED_FIPS_HOST, + + VIR_DOMAIN_TPM_PROFILE_REMOVE_DISABLED_LAST +} virDomainTPMProfileRemoveDisabled; + #define VIR_DOMAIN_TPM_DEFAULT_DEVICE "/dev/tpm0"
struct _virDomainTPMEmulatorDef { @@ -4280,6 +4288,7 @@ VIR_ENUM_DECL(virDomainTPMModel); VIR_ENUM_DECL(virDomainTPMBackend); VIR_ENUM_DECL(virDomainTPMVersion); VIR_ENUM_DECL(virDomainTPMPcrBank); +VIR_ENUM_DECL(virDomainTPMProfileRemoveDisabled); VIR_ENUM_DECL(virDomainMemoryModel); VIR_ENUM_DECL(virDomainMemoryBackingModel); VIR_ENUM_DECL(virDomainMemorySource); -- 2.46.1

Extend the schema for the TPM emulator profile node. Require that the profile the user provides is describe in a name attribute. An optional remove_disabled attribute is also supported for swtpm to automatically remove algorithms from the 'custom' profile if they are disabled by FIPS mode on the host. Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> --- src/conf/schemas/domaincommon.rng | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index efb5f00d77..29e45d47e9 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -5923,6 +5923,7 @@ <interleave> <ref name="tpm-backend-emulator-encryption"/> <ref name="tpm-backend-emulator-active-pcr-banks"/> + <ref name="tpm-backend-emulator-profile"/> </interleave> <optional> <attribute name="persistent_state"> @@ -6020,6 +6021,30 @@ </optional> </define> + <define name="profileName"> + <data type="string"> + <param name="pattern">[A-Za-z0-9\-\.]+</param> + </data> + </define> + + <define name="tpm-backend-emulator-profile"> + <optional> + <element name="profile"> + <attribute name="name"> + <ref name="profileName"/> + </attribute> + <optional> + <attribute name="remove_disabled"> + <choice> + <value>check</value> + <value>fips-host</value> + </choice> + </attribute> + </optional> + </element> + </optional> + </define> + <define name="vsock"> <element name="vsock"> <optional> -- 2.46.1

Extend the parser and XML builder with support for the profile parameter and its remove_disabled attribute. Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> --- src/conf/domain_conf.c | 36 ++++++++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 2 ++ src/conf/domain_validate.c | 7 +++++++ 3 files changed, 45 insertions(+) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 1c8fffdfa5..23bdfb51ca 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -3471,6 +3471,7 @@ void virDomainTPMDefFree(virDomainTPMDef *def) g_free(def->data.emulator.storagepath); g_free(def->data.emulator.logfile); virBitmapFree(def->data.emulator.activePcrBanks); + g_free(def->data.emulator.profile_name); break; case VIR_DOMAIN_TPM_TYPE_EXTERNAL: virObjectUnref(def->data.external.source); @@ -10779,6 +10780,15 @@ virDomainSmartcardDefParseXML(virDomainXMLOption *xmlopt, * <tpm model='tpm-tis'> * <backend type='emulator' version='2.0' persistent_state='yes'> * </tpm> + * + * A profile for a TPM 2.0 can be added like this: + * + * <tpm model='tpm-crb'> + * <backend type='emulator' version='2.0'> + * <profile name='local:restricted' remove_disabled='check'/> + * </backend> + * </tpm> + * */ static virDomainTPMDef * virDomainTPMDefParseXML(virDomainXMLOption *xmlopt, @@ -10797,6 +10807,8 @@ virDomainTPMDefParseXML(virDomainXMLOption *xmlopt, g_autofree xmlNodePtr *backends = NULL; g_autofree xmlNodePtr *nodes = NULL; g_autofree char *type = NULL; + virDomainTPMProfileRemoveDisabled profile_remove_disabled; + xmlNodePtr profile; int bank; if (!(def = virDomainTPMDefNew(xmlopt))) @@ -10887,6 +10899,22 @@ virDomainTPMDefParseXML(virDomainXMLOption *xmlopt, } virBitmapSetBitExpand(def->data.emulator.activePcrBanks, bank); } + + if ((profile = virXPathNode("./backend/profile[1]", ctxt))) { + def->data.emulator.profile_name = virXMLPropString(profile, "name"); + if (!def->data.emulator.profile_name) { + virReportError(VIR_ERR_XML_ERROR, "%s", _("missing profile name")); + goto error; + } + if (virXMLPropEnum(profile, "remove_disabled", + virDomainTPMProfileRemoveDisabledTypeFromString, + VIR_XML_PROP_NONZERO, + &profile_remove_disabled) < 0) + goto error; + if (profile_remove_disabled != VIR_DOMAIN_TPM_PROFILE_REMOVE_DISABLED_NONE) + def->data.emulator.profile_remove_disabled = + virDomainTPMProfileRemoveDisabledTypeToString(profile_remove_disabled); + } break; case VIR_DOMAIN_TPM_TYPE_EXTERNAL: if (!(type = virXPathString("string(./backend/source/@type)", ctxt))) { @@ -25077,6 +25105,14 @@ virDomainTPMDefFormat(virBuffer *buf, virXMLFormatElement(&backendChildBuf, "active_pcr_banks", NULL, &activePcrBanksBuf); } + if (def->data.emulator.profile_name) { + virBufferAsprintf(&backendChildBuf, "<profile name='%s'", + def->data.emulator.profile_name); + if (def->data.emulator.profile_remove_disabled) + virBufferAsprintf(&backendChildBuf, " remove_disabled='%s'", + def->data.emulator.profile_remove_disabled); + virBufferAddLit(&backendChildBuf, "/>\n"); + } break; case VIR_DOMAIN_TPM_TYPE_EXTERNAL: if (def->data.external.source->type == VIR_DOMAIN_CHR_TYPE_UNIX) { diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index ec821ea6fc..6b08665bb7 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1483,6 +1483,8 @@ struct _virDomainTPMEmulatorDef { bool hassecretuuid; bool persistent_state; virBitmap *activePcrBanks; + char *profile_name; + const char *profile_remove_disabled; }; struct _virDomainTPMDef { diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c index eddb4a5e74..4dc2b468f0 100644 --- a/src/conf/domain_validate.c +++ b/src/conf/domain_validate.c @@ -3025,6 +3025,13 @@ virDomainTPMDevValidate(const virDomainTPMDef *tpm) virDomainTPMVersionTypeToString(VIR_DOMAIN_TPM_VERSION_2_0)); return -1; } + if (tpm->data.emulator.profile_name && + tpm->data.emulator.version != VIR_DOMAIN_TPM_VERSION_2_0) { + virReportError(VIR_ERR_XML_ERROR, + _("<profile/> requires TPM version '%1$s'"), + virDomainTPMVersionTypeToString(VIR_DOMAIN_TPM_VERSION_2_0)); + return -1; + } break; case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH: -- 2.46.1

Add documentation for the TPM backend profile node and point the reader to further documentation about TPM profiles available in the swtpm and TPMLIB_SetProfile man pages. Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> --- docs/formatdomain.rst | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 4336cff3ac..fe6230f39b 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -8119,6 +8119,7 @@ Example: usage of the TPM Emulator <active_pcr_banks> <sha256/> </active_pcr_banks> + <profile name='local:restricted' remove_disabled='check'/> </backend> </tpm> </devices> @@ -8191,6 +8192,35 @@ Example: usage of the TPM Emulator and may not have any effect otherwise. The selection of PCR banks only works with the ``emulator`` backend. :since:`Since 7.10.0` +``profile`` + The ``profile`` node is used to set a profile for a TPM 2.0. 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. + + The built-in 'null' profile provides backwards compatibility with + libtpms v0.9 but also restricts the user to use only TPM features that were + available at the time of libtpms v0.9. The built-in 'custom' profile is the + only profile that a user can modify and where the ``remove_disabled`` + attribute has any effect. This attribute is particularly useful when a host + is running in FIPS mode and therefore some crypto algorithms (camellia, + tdes, unpadded RSA encryption, 1024-bit RSA keys, and others) are + disabled. When it is set to ``check`` (recommended) then only those + algorithms that are currently disabled will automatically be removed from + the 'custom' profile, while when it is set to ``fips-host`` then all + potentially disabled algorithms will be removed. :since:`Since 10.??.0` + + TPM profiles provided by a distro can be referenced with the 'distro' + attribute. Locally created TPM profiles can be referenced with the + 'local' attribute. + + For further information about TPM profiles see the man pages for ``swtpm`` + (swtpm v0.10) and libtpms's ``TPMLIB_SetProfile`` (libtpms v0.10). + ``encryption`` The ``encryption`` element allows the state of a TPM emulator to be encrypted. The ``secret`` must reference a secret object that holds the -- 2.46.1

On Thu, Sep 26, 2024 at 03:32:07PM -0400, Stefan Berger wrote:
Add documentation for the TPM backend profile node and point the reader to further documentation about TPM profiles available in the swtpm and TPMLIB_SetProfile man pages.
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> --- docs/formatdomain.rst | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 4336cff3ac..fe6230f39b 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -8119,6 +8119,7 @@ Example: usage of the TPM Emulator <active_pcr_banks> <sha256/> </active_pcr_banks> + <profile name='local:restricted' remove_disabled='check'/> </backend> </tpm> </devices> @@ -8191,6 +8192,35 @@ Example: usage of the TPM Emulator and may not have any effect otherwise. The selection of PCR banks only works with the ``emulator`` backend. :since:`Since 7.10.0`
+``profile`` + The ``profile`` node is used to set a profile for a TPM 2.0. 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.
Am I right that "profile" name only used on the first boot, at the time of manufacturing ? IOW, if we later live migrate to a new host with different default profile the guest will still use the original manufactured profile. In any case, I think if no profile is set, then we should fill in the XML to record the profile that we manufactured. This will allow an admin to look at the guest XML later and identify any guests manufactured with potentially outdated profiles.
+ 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 + available at the time of libtpms v0.9. The built-in 'custom' profile is the + only profile that a user can modify and where the ``remove_disabled`` + attribute has any effect. This attribute is particularly useful when a host + is running in FIPS mode and therefore some crypto algorithms (camellia, + tdes, unpadded RSA encryption, 1024-bit RSA keys, and others) are + disabled. When it is set to ``check`` (recommended) then only those + algorithms that are currently disabled will automatically be removed from + the 'custom' profile, while when it is set to ``fips-host`` then all + potentially disabled algorithms will be removed. :since:`Since 10.??.0`
I'm not sure I understand what "custom" means as a profile here ? What defines the set of algs that go into 'custom' profile ? With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

On 9/26/24 4:18 PM, Daniel P. Berrangé wrote:
On Thu, Sep 26, 2024 at 03:32:07PM -0400, Stefan Berger wrote:
Add documentation for the TPM backend profile node and point the reader to further documentation about TPM profiles available in the swtpm and TPMLIB_SetProfile man pages.
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> --- docs/formatdomain.rst | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 4336cff3ac..fe6230f39b 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -8119,6 +8119,7 @@ Example: usage of the TPM Emulator <active_pcr_banks> <sha256/> </active_pcr_banks> + <profile name='local:restricted' remove_disabled='check'/> </backend> </tpm> </devices> @@ -8191,6 +8192,35 @@ Example: usage of the TPM Emulator and may not have any effect otherwise. The selection of PCR banks only works with the ``emulator`` backend. :since:`Since 7.10.0`
+``profile`` + The ``profile`` node is used to set a profile for a TPM 2.0. 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.
Am I right that "profile" name only used on the first boot, at the time of manufacturing ?
IOW, if we later live migrate to a new host with different default profile the guest will still use the original manufactured profile.
Correct. You cannot gain access to new crypto algorithms and you cannot loose them either when migrating. In the worst case the migration will be rejected because you had access to a crypto algo (which you presumably also used because it is enabled in the profile) and the libtpms on the target machine does not support this yet because it is an older verson. It wouldn't be helpful to take away access to some crypto algo that an application/kernel driver relies on when migrating to another host and now the decryption of data doesn't work anymore. The whole problem wouldn't exist if TPM 2 development had ended but it hasn't ended. Next I would expect PQ-crypto to be added to TPM 2s.
In any case, I think if no profile is set, then we should fill in the XML to record the profile that we manufactured. This will allow an admin to
For detecting which profile was actually set we would have to look at the VM's swtpm log file where that is reflected -- or start swtpm and query its control channel. The custom profile can be changed quite a bit by reducing the Commands and Algorithms and setting Attributes. You would have to really record the whole JSON profile -- and that's logged in the swtpm log.
look at the guest XML later and identify any guests manufactured with potentially outdated profiles.
+ 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 + available at the time of libtpms v0.9. The built-in 'custom' profile is the + only profile that a user can modify and where the ``remove_disabled`` + attribute has any effect. This attribute is particularly useful when a host + is running in FIPS mode and therefore some crypto algorithms (camellia, + tdes, unpadded RSA encryption, 1024-bit RSA keys, and others) are + disabled. When it is set to ``check`` (recommended) then only those + algorithms that are currently disabled will automatically be removed from + the 'custom' profile, while when it is set to ``fips-host`` then all + potentially disabled algorithms will be removed. :since:`Since 10.??.0`
I'm not sure I understand what "custom" means as a profile here ? What defines the set of algs that go into 'custom' profile ?
With regards, Daniel

On Thu, Sep 26, 2024 at 04:44:28PM -0400, Stefan Berger wrote:
On 9/26/24 4:18 PM, Daniel P. Berrangé wrote:
On Thu, Sep 26, 2024 at 03:32:07PM -0400, Stefan Berger wrote:
Add documentation for the TPM backend profile node and point the reader to further documentation about TPM profiles available in the swtpm and TPMLIB_SetProfile man pages.
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> --- docs/formatdomain.rst | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 4336cff3ac..fe6230f39b 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -8119,6 +8119,7 @@ Example: usage of the TPM Emulator <active_pcr_banks> <sha256/> </active_pcr_banks> + <profile name='local:restricted' remove_disabled='check'/> </backend> </tpm> </devices> @@ -8191,6 +8192,35 @@ Example: usage of the TPM Emulator and may not have any effect otherwise. The selection of PCR banks only works with the ``emulator`` backend. :since:`Since 7.10.0` +``profile`` + The ``profile`` node is used to set a profile for a TPM 2.0. 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.
Am I right that "profile" name only used on the first boot, at the time of manufacturing ?
IOW, if we later live migrate to a new host with different default profile the guest will still use the original manufactured profile.
Correct. You cannot gain access to new crypto algorithms and you cannot loose them either when migrating. In the worst case the migration will be rejected because you had access to a crypto algo (which you presumably also used because it is enabled in the profile) and the libtpms on the target machine does not support this yet because it is an older verson. It wouldn't be helpful to take away access to some crypto algo that an application/kernel driver relies on when migrating to another host and now the decryption of data doesn't work anymore. The whole problem wouldn't exist if TPM 2 development had ended but it hasn't ended. Next I would expect PQ-crypto to be added to TPM 2s.
In any case, I think if no profile is set, then we should fill in the XML to record the profile that we manufactured. This will allow an admin to
For detecting which profile was actually set we would have to look at the VM's swtpm log file where that is reflected -- or start swtpm and query its control channel.
The custom profile can be changed quite a bit by reducing the Commands and Algorithms and setting Attributes. You would have to really record the whole JSON profile -- and that's logged in the swtpm log.
I wasn't really thinking about that level of detail, rather the more mundane level of whether the vTPM was created with 'default-v1' or 'default-v2' or 'default-v3', etc. Recording the default profile in the XML exposes this otherwise hidden info.
look at the guest XML later and identify any guests manufactured with potentially outdated profiles.
+ 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 + available at the time of libtpms v0.9. The built-in 'custom' profile is the + only profile that a user can modify and where the ``remove_disabled`` + attribute has any effect. This attribute is particularly useful when a host + is running in FIPS mode and therefore some crypto algorithms (camellia, + tdes, unpadded RSA encryption, 1024-bit RSA keys, and others) are + disabled. When it is set to ``check`` (recommended) then only those + algorithms that are currently disabled will automatically be removed from + the 'custom' profile, while when it is set to ``fips-host`` then all + potentially disabled algorithms will be removed. :since:`Since 10.??.0`
I'm not sure I understand what "custom" means as a profile here ? What defines the set of algs that go into 'custom' profile ?
Why are the 'fips-host' and 'remove_disable' flags limted to the 'custom' profile ? I would think it is valid to want to apply them to the default profiles too, as those give you a clear baseline against which you're removing features. With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

On 9/27/24 1:06 PM, Daniel P. Berrangé wrote:
On Thu, Sep 26, 2024 at 04:44:28PM -0400, Stefan Berger wrote:
On 9/26/24 4:18 PM, Daniel P. Berrangé wrote:
On Thu, Sep 26, 2024 at 03:32:07PM -0400, Stefan Berger wrote:
Add documentation for the TPM backend profile node and point the reader to further documentation about TPM profiles available in the swtpm and TPMLIB_SetProfile man pages.
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> --- docs/formatdomain.rst | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 4336cff3ac..fe6230f39b 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -8119,6 +8119,7 @@ Example: usage of the TPM Emulator <active_pcr_banks> <sha256/> </active_pcr_banks> + <profile name='local:restricted' remove_disabled='check'/> </backend> </tpm> </devices> @@ -8191,6 +8192,35 @@ Example: usage of the TPM Emulator and may not have any effect otherwise. The selection of PCR banks only works with the ``emulator`` backend. :since:`Since 7.10.0` +``profile`` + The ``profile`` node is used to set a profile for a TPM 2.0. 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.
Am I right that "profile" name only used on the first boot, at the time of manufacturing ?
IOW, if we later live migrate to a new host with different default profile the guest will still use the original manufactured profile.
Correct. You cannot gain access to new crypto algorithms and you cannot loose them either when migrating. In the worst case the migration will be rejected because you had access to a crypto algo (which you presumably also used because it is enabled in the profile) and the libtpms on the target machine does not support this yet because it is an older verson. It wouldn't be helpful to take away access to some crypto algo that an application/kernel driver relies on when migrating to another host and now the decryption of data doesn't work anymore. The whole problem wouldn't exist if TPM 2 development had ended but it hasn't ended. Next I would expect PQ-crypto to be added to TPM 2s.
In any case, I think if no profile is set, then we should fill in the XML to record the profile that we manufactured. This will allow an admin to
For detecting which profile was actually set we would have to look at the VM's swtpm log file where that is reflected -- or start swtpm and query its control channel.
The custom profile can be changed quite a bit by reducing the Commands and Algorithms and setting Attributes. You would have to really record the whole JSON profile -- and that's logged in the swtpm log.
I wasn't really thinking about that level of detail, rather the more mundane level of whether the vTPM was created with 'default-v1' or 'default-v2' or 'default-v3', etc. Recording the default profile in the XML exposes this otherwise hidden info.
Then we also need to lock down this part of the XML. I'd have to search but is there an example that locks down part of the domain XML once it has been known that a VM has been created?
look at the guest XML later and identify any guests manufactured with potentially outdated profiles.
+ 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 + available at the time of libtpms v0.9. The built-in 'custom' profile is the + only profile that a user can modify and where the ``remove_disabled`` + attribute has any effect. This attribute is particularly useful when a host + is running in FIPS mode and therefore some crypto algorithms (camellia, + tdes, unpadded RSA encryption, 1024-bit RSA keys, and others) are + disabled. When it is set to ``check`` (recommended) then only those + algorithms that are currently disabled will automatically be removed from + the 'custom' profile, while when it is set to ``fips-host`` then all + potentially disabled algorithms will be removed. :since:`Since 10.??.0`
I'm not sure I understand what "custom" means as a profile here ? What defines the set of algs that go into 'custom' profile ?
Why are the 'fips-host' and 'remove_disable' flags limted to the 'custom' profile ? I would think it is valid to want to apply them to the default profiles too, as those give you a clear baseline against which you're removing features.
Only the custom profile can be modified, none other. The user can always make a copy of the default profile, rename it, and have it adjusted by this option. With profiles being created from the local profiles directory I think that's something users should be able to do. Stefan
With regards, Daniel

On Sat, Sep 28, 2024 at 12:33:37PM -0400, Stefan Berger wrote:
On 9/27/24 1:06 PM, Daniel P. Berrangé wrote:
On Thu, Sep 26, 2024 at 04:44:28PM -0400, Stefan Berger wrote:
On 9/26/24 4:18 PM, Daniel P. Berrangé wrote:
On Thu, Sep 26, 2024 at 03:32:07PM -0400, Stefan Berger wrote:
Add documentation for the TPM backend profile node and point the reader to further documentation about TPM profiles available in the swtpm and TPMLIB_SetProfile man pages.
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> --- docs/formatdomain.rst | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 4336cff3ac..fe6230f39b 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -8119,6 +8119,7 @@ Example: usage of the TPM Emulator <active_pcr_banks> <sha256/> </active_pcr_banks> + <profile name='local:restricted' remove_disabled='check'/> </backend> </tpm> </devices> @@ -8191,6 +8192,35 @@ Example: usage of the TPM Emulator and may not have any effect otherwise. The selection of PCR banks only works with the ``emulator`` backend. :since:`Since 7.10.0` +``profile`` + The ``profile`` node is used to set a profile for a TPM 2.0. 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.
Am I right that "profile" name only used on the first boot, at the time of manufacturing ?
IOW, if we later live migrate to a new host with different default profile the guest will still use the original manufactured profile.
Correct. You cannot gain access to new crypto algorithms and you cannot loose them either when migrating. In the worst case the migration will be rejected because you had access to a crypto algo (which you presumably also used because it is enabled in the profile) and the libtpms on the target machine does not support this yet because it is an older verson. It wouldn't be helpful to take away access to some crypto algo that an application/kernel driver relies on when migrating to another host and now the decryption of data doesn't work anymore. The whole problem wouldn't exist if TPM 2 development had ended but it hasn't ended. Next I would expect PQ-crypto to be added to TPM 2s.
In any case, I think if no profile is set, then we should fill in the XML to record the profile that we manufactured. This will allow an admin to
For detecting which profile was actually set we would have to look at the VM's swtpm log file where that is reflected -- or start swtpm and query its control channel.
The custom profile can be changed quite a bit by reducing the Commands and Algorithms and setting Attributes. You would have to really record the whole JSON profile -- and that's logged in the swtpm log.
I wasn't really thinking about that level of detail, rather the more mundane level of whether the vTPM was created with 'default-v1' or 'default-v2' or 'default-v3', etc. Recording the default profile in the XML exposes this otherwise hidden info.
Then we also need to lock down this part of the XML. I'd have to search but is there an example that locks down part of the domain XML once it has been known that a VM has been created?
The "post parse" callbacks can be used to fill-in defaults in the XML after parsing.
look at the guest XML later and identify any guests manufactured with potentially outdated profiles.
+ 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 + available at the time of libtpms v0.9. The built-in 'custom' profile is the + only profile that a user can modify and where the ``remove_disabled`` + attribute has any effect. This attribute is particularly useful when a host + is running in FIPS mode and therefore some crypto algorithms (camellia, + tdes, unpadded RSA encryption, 1024-bit RSA keys, and others) are + disabled. When it is set to ``check`` (recommended) then only those + algorithms that are currently disabled will automatically be removed from + the 'custom' profile, while when it is set to ``fips-host`` then all + potentially disabled algorithms will be removed. :since:`Since 10.??.0`
I'm not sure I understand what "custom" means as a profile here ? What defines the set of algs that go into 'custom' profile ?
Why are the 'fips-host' and 'remove_disable' flags limted to the 'custom' profile ? I would think it is valid to want to apply them to the default profiles too, as those give you a clear baseline against which you're removing features.
Only the custom profile can be modified, none other. The user can always make a copy of the default profile, rename it, and have it adjusted by this option. With profiles being created from the local profiles directory I think that's something users should be able to do.
What's the rational for special casing this to not allow the 'default-vNN' profiles to be modified ? This special case makes it more difficult and error prone to consume this, as there's no guarantee that the 'default' profiles will be usable wrt host crypto policies. With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

On 9/30/24 6:04 AM, Daniel P. Berrangé wrote:
On Sat, Sep 28, 2024 at 12:33:37PM -0400, Stefan Berger wrote:
On 9/27/24 1:06 PM, Daniel P. Berrangé wrote:
On Thu, Sep 26, 2024 at 04:44:28PM -0400, Stefan Berger wrote:
On 9/26/24 4:18 PM, Daniel P. Berrangé wrote:
On Thu, Sep 26, 2024 at 03:32:07PM -0400, Stefan Berger wrote:
Add documentation for the TPM backend profile node and point the reader to further documentation about TPM profiles available in the swtpm and TPMLIB_SetProfile man pages.
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> --- docs/formatdomain.rst | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 4336cff3ac..fe6230f39b 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -8119,6 +8119,7 @@ Example: usage of the TPM Emulator <active_pcr_banks> <sha256/> </active_pcr_banks> + <profile name='local:restricted' remove_disabled='check'/> </backend> </tpm> </devices> @@ -8191,6 +8192,35 @@ Example: usage of the TPM Emulator and may not have any effect otherwise. The selection of PCR banks only works with the ``emulator`` backend. :since:`Since 7.10.0` +``profile`` + The ``profile`` node is used to set a profile for a TPM 2.0. 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.
Am I right that "profile" name only used on the first boot, at the time of manufacturing ?
IOW, if we later live migrate to a new host with different default profile the guest will still use the original manufactured profile.
Correct. You cannot gain access to new crypto algorithms and you cannot loose them either when migrating. In the worst case the migration will be rejected because you had access to a crypto algo (which you presumably also used because it is enabled in the profile) and the libtpms on the target machine does not support this yet because it is an older verson. It wouldn't be helpful to take away access to some crypto algo that an application/kernel driver relies on when migrating to another host and now the decryption of data doesn't work anymore. The whole problem wouldn't exist if TPM 2 development had ended but it hasn't ended. Next I would expect PQ-crypto to be added to TPM 2s.
In any case, I think if no profile is set, then we should fill in the XML to record the profile that we manufactured. This will allow an admin to
For detecting which profile was actually set we would have to look at the VM's swtpm log file where that is reflected -- or start swtpm and query its control channel.
The custom profile can be changed quite a bit by reducing the Commands and Algorithms and setting Attributes. You would have to really record the whole JSON profile -- and that's logged in the swtpm log.
I wasn't really thinking about that level of detail, rather the more mundane level of whether the vTPM was created with 'default-v1' or 'default-v2' or 'default-v3', etc. Recording the default profile in the XML exposes this otherwise hidden info.
Then we also need to lock down this part of the XML. I'd have to search but is there an example that locks down part of the domain XML once it has been known that a VM has been created?
The "post parse" callbacks can be used to fill-in defaults in the XML after parsing.
look at the guest XML later and identify any guests manufactured with potentially outdated profiles.
+ 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 + available at the time of libtpms v0.9. The built-in 'custom' profile is the + only profile that a user can modify and where the ``remove_disabled`` + attribute has any effect. This attribute is particularly useful when a host + is running in FIPS mode and therefore some crypto algorithms (camellia, + tdes, unpadded RSA encryption, 1024-bit RSA keys, and others) are + disabled. When it is set to ``check`` (recommended) then only those + algorithms that are currently disabled will automatically be removed from + the 'custom' profile, while when it is set to ``fips-host`` then all + potentially disabled algorithms will be removed. :since:`Since 10.??.0`
I'm not sure I understand what "custom" means as a profile here ? What defines the set of algs that go into 'custom' profile ?
Why are the 'fips-host' and 'remove_disable' flags limted to the 'custom' profile ? I would think it is valid to want to apply them to the default profiles too, as those give you a clear baseline against which you're removing features.
Only the custom profile can be modified, none other. The user can always make a copy of the default profile, rename it, and have it adjusted by this option. With profiles being created from the local profiles directory I think that's something users should be able to do.
What's the rational for special casing this to not allow the 'default-vNN' profiles to be modified ? This special case makes it more difficult and
I would like to have the default-vNN profiles be known constant profiles that enable all algorithms by default, similar to what TPM 2 does today. Users may then make modifications to profiles with either name 'custom' or 'custom:' prefix in the name.
error prone to consume this, as there's no guarantee that the 'default' profiles will be usable wrt host crypto policies.
With regards, Daniel

Runs swtpm_setup with the --profile-name option if the user provided the name of a profile. swtpm_setup will try to load the profile from directories with local profiles and distro profiles and if no profile by this name with appended '.json' suffix could be found there, it will fall back to try to use an internal profile with the given name. Also set the --profile-remove-disabled option if the user provided a value in the remove_disabled attribute in the profile XML node. Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> --- src/qemu/qemu_tpm.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/qemu/qemu_tpm.c b/src/qemu/qemu_tpm.c index e8e7e8b5c1..48446cd631 100644 --- a/src/qemu/qemu_tpm.c +++ b/src/qemu/qemu_tpm.c @@ -340,6 +340,40 @@ qemuTPMVirCommandAddEncryption(virCommand *cmd, } +/* + * Add a (optional) profile to the swtpm_setup command line. + * + * @cmd: virCommand to add options to + * @emulator: emulator parameters + * + * Returns 0 on success, -1 on failure. + */ +static int +qemuTPMVirCommandAddProfile(virCommand *cmd, + const virDomainTPMEmulatorDef *emulator) +{ + if (!emulator->profile_name) + return 0; + + if (!virTPMSwtpmSetupCapsGet( + VIR_TPM_SWTPM_SETUP_FEATURE_CMDARG_PROFILE)) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("swtpm_setup has no support for profiles")); + return -1; + } + + virCommandAddArgList(cmd, + "--profile-name", emulator->profile_name, + NULL); + + if (emulator->profile_remove_disabled) + virCommandAddArgList(cmd, + "--profile-remove-disable", + emulator->profile_remove_disabled, + NULL); + return 0; +} + /* * qemuTPMEmulatorRunSetup * @@ -416,6 +450,8 @@ qemuTPMEmulatorRunSetup(const char *storagepath, "--lock-nvram", "--not-overwrite", NULL); + if (qemuTPMVirCommandAddProfile(cmd, emulator) < 0) + return -1; } else { virCommandAddArgList(cmd, "--tpm-state", storagepath, -- 2.46.1

On Thu, Sep 26, 2024 at 11:32 PM Stefan Berger <stefanb@linux.ibm.com> wrote:
Runs swtpm_setup with the --profile-name option if the user provided the name of a profile. swtpm_setup will try to load the profile from directories with local profiles and distro profiles and if no profile by this name with appended '.json' suffix could be found there, it will fall back to try to use an internal profile with the given name.
Also set the --profile-remove-disabled option if the user provided a value in the remove_disabled attribute in the profile XML node.
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
--- src/qemu/qemu_tpm.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+)
diff --git a/src/qemu/qemu_tpm.c b/src/qemu/qemu_tpm.c index e8e7e8b5c1..48446cd631 100644 --- a/src/qemu/qemu_tpm.c +++ b/src/qemu/qemu_tpm.c @@ -340,6 +340,40 @@ qemuTPMVirCommandAddEncryption(virCommand *cmd, }
+/* + * Add a (optional) profile to the swtpm_setup command line. + * + * @cmd: virCommand to add options to + * @emulator: emulator parameters + * + * Returns 0 on success, -1 on failure. + */ +static int +qemuTPMVirCommandAddProfile(virCommand *cmd, + const virDomainTPMEmulatorDef *emulator) +{ + if (!emulator->profile_name) + return 0; + + if (!virTPMSwtpmSetupCapsGet( + VIR_TPM_SWTPM_SETUP_FEATURE_CMDARG_PROFILE)) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("swtpm_setup has no support for profiles")); + return -1; + } + + virCommandAddArgList(cmd, + "--profile-name", emulator->profile_name, + NULL); + + if (emulator->profile_remove_disabled) + virCommandAddArgList(cmd, + "--profile-remove-disable", + emulator->profile_remove_disabled, + NULL); + return 0; +} + /* * qemuTPMEmulatorRunSetup * @@ -416,6 +450,8 @@ qemuTPMEmulatorRunSetup(const char *storagepath, "--lock-nvram", "--not-overwrite", NULL); + if (qemuTPMVirCommandAddProfile(cmd, emulator) < 0) + return -1; } else { virCommandAddArgList(cmd, "--tpm-state", storagepath, -- 2.46.1

Hi On Thu, Sep 26, 2024 at 11:32 PM Stefan Berger <stefanb@linux.ibm.com> wrote:
Upcoming libtpms v0.10 and swtpm v0.10 will have TPM profile support that allows to restrict a TPM's provided set of crypto algorithms and commands and through which backwards compatibility and migration from newer versions of libtpms to older ones (up to libtpms v0.9) is supported. For the latter to work it is necessary that the user chooses the right ('null') profile.
This series adds support for passing a profile choice to swtpm_setup by setting it in the domain XML using the <profile/> XML node. An optional attribute 'remove_disabled' can be set in this node and accepts two values:
"check": test a few crypto algorithms (tdes, camellia, unpadded encryption, and others) for whether they are currently disabled due to FIPS mode on the host and remove these algorithms in the 'custom' profile if they are disabled;
Given that this option can expose a different vTPM to the guest, I wonder if it should be in the libvirt XML. So if no "remove_disabled" option is given, no check and removal is performed? there should probably be a third option then. "none" ?
"fips-host": do not test but remove all the possibly disabled crypto algorithms (from list above)
This one however feels safer to expose. I'd suggest a simpler naming too: disable_crypto=none/fips ?
Also extend the documentation but point the user to swtpm and libtpms documentation for further details.
Follow Deniel's suggestions there's now a PR for swtpm_setup to support searching for profiles though a configurable local directory, distro directory and if no profile could be found there (with appended ".json" suffix) it will fall back to try to use a built-in profile by the provided name: https://github.com/stefanberger/swtpm/pull/918
Stefan
Stefan Berger (8): conf: Move TPM emulator parameters into own struct qemu: Pass virQEMUDriverConfig rather than some of its fields util: Add parsing support for swtpm_setup's cmdarg-profile capability conf: Define enum virDomainTPMProfileRemoveDisabled schema: Extend schema for TPM emulator profile node conf: Add support for profile parameter on TPM emulator in domain XML docs: Add documentation for the TPM backend profile node qemu: Extend swtpm_setup command line to set a profile by its name
docs/formatdomain.rst | 30 ++++++++ src/conf/domain_conf.c | 43 +++++++++++ src/conf/domain_conf.h | 35 ++++++--- src/conf/domain_validate.c | 7 ++ src/conf/schemas/domaincommon.rng | 25 ++++++ src/conf/virconftypes.h | 2 + src/qemu/qemu_tpm.c | 124 +++++++++++++++++------------- src/util/virtpm.c | 1 + src/util/virtpm.h | 1 + tests/testutilsqemu.c | 1 + 10 files changed, 203 insertions(+), 66 deletions(-)
-- 2.46.1

On 9/30/24 5:52 AM, Marc-André Lureau wrote:
Hi
On Thu, Sep 26, 2024 at 11:32 PM Stefan Berger <stefanb@linux.ibm.com> wrote:
Upcoming libtpms v0.10 and swtpm v0.10 will have TPM profile support that allows to restrict a TPM's provided set of crypto algorithms and commands and through which backwards compatibility and migration from newer versions of libtpms to older ones (up to libtpms v0.9) is supported. For the latter to work it is necessary that the user chooses the right ('null') profile.
This series adds support for passing a profile choice to swtpm_setup by setting it in the domain XML using the <profile/> XML node. An optional attribute 'remove_disabled' can be set in this node and accepts two values:
"check": test a few crypto algorithms (tdes, camellia, unpadded encryption, and others) for whether they are currently disabled due to FIPS mode on the host and remove these algorithms in the 'custom' profile if they are disabled;
Given that this option can expose a different vTPM to the guest, I wonder if it should be in the libvirt XML.
You mean different vTPM because of the changes it can make to the profile? [ It will make different changes to the profile depending on OS. Fedora, CentOS, and RHEL are **at the moment** all slightly different per this page here: https://trustedcomputinggroup.org/wp-content/uploads/TCG-FIPS-140-3-Guidance... ]
So if no "remove_disabled" option is given, no check and removal is performed? there should probably be a third option then. "none" ?
"fips-host": do not test but remove all the possibly disabled crypto algorithms (from list above)
This one however feels safer to expose.
I'd suggest a simpler naming too: disable_crypto=none/fips ?
The problem with naming it 'fips' is that FIPS can be quite a lot more in relation to TPM and required extensions to profiles: - https://trustedcomputinggroup.org/wp-content/uploads/TCG-FIPS-140-3-Guidance... - https://github.com/stefanberger/libtpms/pull/428
Also extend the documentation but point the user to swtpm and libtpms documentation for further details.
Follow Deniel's suggestions there's now a PR for swtpm_setup to support searching for profiles though a configurable local directory, distro directory and if no profile could be found there (with appended ".json" suffix) it will fall back to try to use a built-in profile by the provided name: https://github.com/stefanberger/swtpm/pull/918
Stefan
Stefan Berger (8): conf: Move TPM emulator parameters into own struct qemu: Pass virQEMUDriverConfig rather than some of its fields util: Add parsing support for swtpm_setup's cmdarg-profile capability conf: Define enum virDomainTPMProfileRemoveDisabled schema: Extend schema for TPM emulator profile node conf: Add support for profile parameter on TPM emulator in domain XML docs: Add documentation for the TPM backend profile node qemu: Extend swtpm_setup command line to set a profile by its name
docs/formatdomain.rst | 30 ++++++++ src/conf/domain_conf.c | 43 +++++++++++ src/conf/domain_conf.h | 35 ++++++--- src/conf/domain_validate.c | 7 ++ src/conf/schemas/domaincommon.rng | 25 ++++++ src/conf/virconftypes.h | 2 + src/qemu/qemu_tpm.c | 124 +++++++++++++++++------------- src/util/virtpm.c | 1 + src/util/virtpm.h | 1 + tests/testutilsqemu.c | 1 + 10 files changed, 203 insertions(+), 66 deletions(-)
-- 2.46.1
participants (3)
-
Daniel P. Berrangé
-
Marc-André Lureau
-
Stefan Berger