diff --git a/SOURCES/libvirt-qemu-correctly-detect-working-TDX-support.patch b/SOURCES/libvirt-qemu-correctly-detect-working-TDX-support.patch new file mode 100644 index 0000000..df7fdba --- /dev/null +++ b/SOURCES/libvirt-qemu-correctly-detect-working-TDX-support.patch @@ -0,0 +1,151 @@ +From 020c4bc3213cc2466e2a03bef5d81a95d6331f5f Mon Sep 17 00:00:00 2001 +Message-ID: <020c4bc3213cc2466e2a03bef5d81a95d6331f5f.1766050330.git.jdenemar@redhat.com> +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +Date: Thu, 20 Nov 2025 06:24:31 -0500 +Subject: [PATCH] qemu: correctly detect working TDX support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Querying existence of the 'tdx-guest' type merely tells us whether +QEMU has been compiled with TDX support, not whether it is usable +on the host. Thus QEMU was incorrectly reporting + + + ... + + + tdx + + + +on every platform with new enough QEMU. + +Unfortunately an earlier patch for a 'query-tdx-capabilities' QMP +command in QEMU was dropped, so there is no way to ask QEMU whether +it can launch a TDX guest. Libvirt must directly query the KVM +device and ask for supported VM types. + +Reviewed-by: Peter Krempa +Signed-off-by: Daniel P. Berrangé +(cherry picked from commit 62d14ba496634d5a98f7becc3875b9311cb38931) +[DB: replace ATTRIBUTE_MOCKABLE with G_NO_INLINE] +https://issues.redhat.com/browse/RHEL-136239 +Signed-off-by: Daniel P. Berrangé +--- + src/qemu/qemu_capabilities.c | 51 ++++++++++++++++++++++++++++++++++++ + src/qemu/qemu_capabilities.h | 3 +++ + tests/domaincapsmock.c | 6 +++++ + 3 files changed, 60 insertions(+) + +diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c +index b75ecd5046..c7ee5da225 100644 +--- a/src/qemu/qemu_capabilities.c ++++ b/src/qemu/qemu_capabilities.c +@@ -54,11 +54,17 @@ + # include + # include + #endif ++#ifdef WITH_LINUX_KVM_H ++# include ++# include ++#endif + + #define VIR_FROM_THIS VIR_FROM_QEMU + + VIR_LOG_INIT("qemu.qemu_capabilities"); + ++#define KVM_DEVICE "/dev/kvm" ++ + /* While not public, these strings must not change. They + * are used in domain status files which are read on + * daemon restarts +@@ -3690,6 +3696,50 @@ virQEMUCapsProbeQMPSEVCapabilities(virQEMUCaps *qemuCaps, + } + + ++bool ++virQEMUCapsKVMSupportsVMTypeTDX(void) ++{ ++#if defined(KVM_CAP_VM_TYPES) && defined(KVM_X86_TDX_VM) ++ VIR_AUTOCLOSE kvmfd = -1; ++ int types; ++ ++ if (!virFileExists(KVM_DEVICE)) ++ return false; ++ ++ if ((kvmfd = open(KVM_DEVICE, O_RDONLY)) < 0) { ++ VIR_DEBUG("Unable to open %s, cannot check TDX", KVM_DEVICE); ++ return false; ++ } ++ ++ if ((types = ioctl(kvmfd, KVM_CHECK_EXTENSION, KVM_CAP_VM_TYPES)) < 0) ++ types = 0; ++ ++ VIR_DEBUG("KVM VM types: 0x%x", types); ++ ++ return !!(types & (1 << KVM_X86_TDX_VM)); ++#else ++ VIR_DEBUG("KVM not compiled"); ++ return false; ++#endif ++} ++ ++ ++/* This ought to be virQEMUCapsProbeQMPTDXCapabilities, ++ * but there is no 'query-tdx-capabilities' command ++ * available in QEMU currently. If one arrives, rename ++ * this method & switch to using that on new enough QEMU ++ */ ++static void ++virQEMUCapsProbeTDXCapabilities(virQEMUCaps *qemuCaps) ++{ ++ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_TDX_GUEST)) ++ return; ++ ++ if (!virQEMUCapsKVMSupportsVMTypeTDX()) ++ virQEMUCapsClear(qemuCaps, QEMU_CAPS_TDX_GUEST); ++} ++ ++ + static int + virQEMUCapsProbeQMPSGXCapabilities(virQEMUCaps *qemuCaps, + qemuMonitor *mon) +@@ -5880,6 +5930,7 @@ virQEMUCapsInitQMPMonitor(virQEMUCaps *qemuCaps, + return -1; + if (virQEMUCapsProbeQMPSGXCapabilities(qemuCaps, mon) < 0) + return -1; ++ virQEMUCapsProbeTDXCapabilities(qemuCaps); + + virQEMUCapsInitProcessCaps(qemuCaps); + +diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h +index 9cce91d643..86eac19583 100644 +--- a/src/qemu/qemu_capabilities.h ++++ b/src/qemu/qemu_capabilities.h +@@ -954,3 +954,6 @@ int + virQEMUCapsProbeQMPMachineTypes(virQEMUCaps *qemuCaps, + virDomainVirtType virtType, + qemuMonitor *mon); ++ ++bool ++virQEMUCapsKVMSupportsVMTypeTDX(void) G_NO_INLINE; +diff --git a/tests/domaincapsmock.c b/tests/domaincapsmock.c +index cb6e98dbb8..7bece6c8c1 100644 +--- a/tests/domaincapsmock.c ++++ b/tests/domaincapsmock.c +@@ -48,6 +48,12 @@ virHostCPUGetPhysAddrSize(const virArch hostArch, + } + + #if WITH_QEMU ++bool ++virQEMUCapsKVMSupportsVMTypeTDX(void) ++{ ++ return true; ++} ++ + static bool (*real_virQEMUCapsGetKVMSupportsSecureGuest)(virQEMUCaps *qemuCaps); + + bool +-- +2.52.0 diff --git a/SOURCES/libvirt-qemu-tpm-Account-for-possible-migration-without-actually-sharing-storage.patch b/SOURCES/libvirt-qemu-tpm-Account-for-possible-migration-without-actually-sharing-storage.patch new file mode 100644 index 0000000..40ee3d5 --- /dev/null +++ b/SOURCES/libvirt-qemu-tpm-Account-for-possible-migration-without-actually-sharing-storage.patch @@ -0,0 +1,119 @@ +From 5f3c13e461f59e321bd4b14387a65d7006e96242 Mon Sep 17 00:00:00 2001 +Message-ID: <5f3c13e461f59e321bd4b14387a65d7006e96242.1765467744.git.jdenemar@redhat.com> +From: Peter Krempa +Date: Mon, 1 Dec 2025 11:35:32 +0100 +Subject: [PATCH] qemu: tpm: Account for possible migration without actually + sharing storage + +The current logic in 'qemuTPMEmulatorBuildCommand' skips all setup if +the *location* of the data is on what we'd consider shared storage. + +This means that if the location is not actually shared (e.g. it's shared +betweeh some other hosts than the two doing the migration) and the path +wasn't ever used (e.g. by migrating out) from the host where we're +migrating into the complete setup of the location would be skipped even +when it doesn't exist. + +Fix the logic by skipping only some of the setup steps so that +'qemuTPMEmulatorCreateStorage' can still create the storage if it +doesn't exist. + +The rest of the code then needs to take the 'created' flag returned from +'qemuTPMEmulatorCreateStorage' into account. + +Fixes: 68103e9daf633b789428fedef56f816c92f6ee75 +Signed-off-by: Peter Krempa +Reviewed-by: Michal Privoznik +(cherry picked from commit d56d0560946770d4364a4918cc289e6a7fe5d15c) +https://issues.redhat.com/browse/RHEL-132345 +--- + src/qemu/qemu_tpm.c | 29 ++++++++++++++++++++--------- + 1 file changed, 20 insertions(+), 9 deletions(-) + +diff --git a/src/qemu/qemu_tpm.c b/src/qemu/qemu_tpm.c +index f910a26286..fde495c9d2 100644 +--- a/src/qemu/qemu_tpm.c ++++ b/src/qemu/qemu_tpm.c +@@ -158,6 +158,7 @@ qemuTPMEmulatorGetPid(const char *swtpmStateDir, + /** + * qemuTPMEmulatorCreateStorage: + * @tpm: TPM definition for an emulator type ++ * @sharedStorageMigration: VM is being migrated with possibly shared storage + * @created: a pointer to a bool that will be set to true if the + * storage was created because it did not exist yet + * @swtpm_user: The uid that needs to be able to access the directory +@@ -169,6 +170,7 @@ qemuTPMEmulatorGetPid(const char *swtpmStateDir, + */ + static int + qemuTPMEmulatorCreateStorage(virDomainTPMDef *tpm, ++ bool sharedStorageMigration, + bool *created, + uid_t swtpm_user, + gid_t swtpm_group) +@@ -187,8 +189,17 @@ qemuTPMEmulatorCreateStorage(virDomainTPMDef *tpm, + *created = false; + + if (!virFileExists(source_path) || +- virDirIsEmpty(source_path, true) > 0) ++ virDirIsEmpty(source_path, true) > 0) { + *created = true; ++ } else { ++ /* If the location exists and is shared, we don't need to create it ++ * during migration */ ++ if (sharedStorageMigration) { ++ VIR_DEBUG("Skipping TPM storage creation. Path '%s' already exists and is on shared storage.", ++ source_path); ++ return 0; ++ } ++ } + + if (virDirCreate(source_path, 0700, swtpm_user, swtpm_group, + VIR_DIR_CREATE_ALLOW_EXIST) < 0) { +@@ -749,16 +760,13 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm, + run_setup = true; + } + +- /* Do not create storage and run swtpm_setup on incoming migration over +- * shared storage +- */ + on_shared_storage = virFileIsSharedFS(tpm->data.emulator.source_path, + cfg->sharedFilesystems) == 1; +- if (incomingMigration && on_shared_storage) +- create_storage = false; + + if (create_storage) { +- if (qemuTPMEmulatorCreateStorage(tpm, &created, ++ if (qemuTPMEmulatorCreateStorage(tpm, ++ incomingMigration && on_shared_storage, ++ &created, + cfg->swtpm_user, cfg->swtpm_group) < 0) + return NULL; + run_setup = created; +@@ -825,6 +833,9 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm, + /* If swtpm supports it and the TPM state is stored on shared storage, + * start swtpm with --migration release-lock-outgoing so it can migrate + * across shared storage if needed. ++ * ++ * Note that if 'created' is true, the location didn't exist so the storage ++ * is not actually shared. + */ + QEMU_DOMAIN_TPM_PRIVATE(tpm)->swtpm.can_migrate_shared_storage = false; + if (on_shared_storage && +@@ -832,13 +843,13 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm, + + virCommandAddArg(cmd, "--migration"); + virCommandAddArgFormat(cmd, "release-lock-outgoing%s", +- incomingMigration ? ",incoming": ""); ++ incomingMigration && !created ? ",incoming": ""); + QEMU_DOMAIN_TPM_PRIVATE(tpm)->swtpm.can_migrate_shared_storage = true; + } else { + /* Report an error if there's an incoming migration across shared + * storage and swtpm does not support the --migration option. + */ +- if (incomingMigration && on_shared_storage) { ++ if (incomingMigration && on_shared_storage && !created) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, + _("%1$s (on destination side) does not support the --migration option needed for migration with shared storage"), + swtpm); +-- +2.52.0 diff --git a/SPECS/libvirt.spec b/SPECS/libvirt.spec index 042ff75..197d936 100644 --- a/SPECS/libvirt.spec +++ b/SPECS/libvirt.spec @@ -289,7 +289,7 @@ Summary: Library providing a simple virtualization API Name: libvirt Version: 10.10.0 -Release: 15.4%{?dist}%{?extra_release} +Release: 15.6.0.1%{?dist}%{?extra_release} License: GPL-2.0-or-later AND LGPL-2.1-only AND LGPL-2.1-or-later AND OFL-1.1 URL: https://libvirt.org/ @@ -504,6 +504,8 @@ Patch204: libvirt-qemu_domain-Fix-qemuDomainFixupCPUs.patch Patch205: libvirt-qemu_process-Always-fix-CPUs-on-reconnect.patch Patch206: libvirt-qemu_monitor-Filter-CPU-features-reported-by-QEMU.patch Patch207: libvirt-qemu-Ignore-ht-CPU-feature.patch +Patch208: libvirt-qemu-tpm-Account-for-possible-migration-without-actually-sharing-storage.patch +Patch209: libvirt-qemu-correctly-detect-working-TDX-support.patch Requires: libvirt-daemon = %{version}-%{release} @@ -1525,7 +1527,8 @@ exit 1 %define arg_packager_version -Dpackager_version="%{release}" %define arg_selinux_mount -Dselinux_mount="/sys/fs/selinux" -# place macros above and build commands below this comment +# Set SOURCE_DATE_EPOCH from changelog +%define source_date_epoch_from_changelog 1 export SOURCE_DATE_EPOCH=$(stat --printf='%Y' %{_specdir}/libvirt.spec) @@ -2829,6 +2832,15 @@ exit 0 %endif %changelog +* Tue Jan 27 2026 EL Errata - 10.10.0-15.6.0.1 +- Set SOURCE_DATE_EPOCH from changelog [Orabug: 32019554] + +* Thu Dec 18 2025 Jiri Denemark - 10.10.0-15.6.el9_7 +- qemu: correctly detect working TDX support (RHEL-136239) + +* Thu Dec 11 2025 Jiri Denemark - 10.10.0-15.5.el9_7 +- qemu: tpm: Account for possible migration without actually sharing storage (RHEL-132345) + * Fri Nov 21 2025 Jiri Denemark - 10.10.0-15.4.el9_7 - cpu_conf: Make virCPUDefFilterFeatures return void (RHEL-126096) - qemu_domain: Simplify qemuDomainFixupCPUs (RHEL-126096)