diff --git a/libvirt-qemu-tpm-Account-for-possible-migration-without-actually-sharing-storage.patch b/libvirt-qemu-tpm-Account-for-possible-migration-without-actually-sharing-storage.patch new file mode 100644 index 0000000..bd7cb4c --- /dev/null +++ b/libvirt-qemu-tpm-Account-for-possible-migration-without-actually-sharing-storage.patch @@ -0,0 +1,119 @@ +From 582ac1d5b308d1b9816c57ebca762a8796c67df4 Mon Sep 17 00:00:00 2001 +Message-ID: <582ac1d5b308d1b9816c57ebca762a8796c67df4.1766070256.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-108915 +--- + 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 4c9445d72c..660410bcba 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) { +@@ -809,16 +820,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; +@@ -885,6 +893,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 && +@@ -892,13 +903,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/libvirt-tests-Test-virFileIsSharedFSOverride.patch b/libvirt-tests-Test-virFileIsSharedFSOverride.patch new file mode 100644 index 0000000..f13d965 --- /dev/null +++ b/libvirt-tests-Test-virFileIsSharedFSOverride.patch @@ -0,0 +1,111 @@ +From b630429647207ba0d406cf855e590ddaa98fdb9b Mon Sep 17 00:00:00 2001 +Message-ID: +From: Jiri Denemark +Date: Fri, 5 Dec 2025 15:09:15 +0100 +Subject: [PATCH] tests: Test virFileIsSharedFSOverride + +Technically virFileIsSharedFSOverride is available on any OS, but we +need a mocked realpath() to test it. Because the virfilemock library +also mocks statfs() which is only available on Linux, we don't even try +to load the library anywhere else. Thus we need to skip testing +virFileIsSharedFSOverride on non-Linux too. + +Signed-off-by: Jiri Denemark +(cherry picked from commit 121d179e068b584f62ea2c029d89a44e67c909c0) + +https://issues.redhat.com/browse/RHEL-135287 + +Signed-off-by: Jiri Denemark +--- + tests/virfiletest.c | 69 +++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 69 insertions(+) + +diff --git a/tests/virfiletest.c b/tests/virfiletest.c +index e05925a321..ccd76a3fac 100644 +--- a/tests/virfiletest.c ++++ b/tests/virfiletest.c +@@ -329,6 +329,55 @@ testFileIsSharedFSType(const void *opaque G_GNUC_UNUSED) + } + + ++static const char *shared_filesystems[] = { ++ "/run/user/501/gvfs", ++ "/nfs", ++ "/gluster", ++ "/ceph/multi", ++ "/gpfs/data/blaf", ++ "/quobyte", ++ NULL, ++}; ++ ++static int ++testFileIsSharedFSOverride(const void *opaque G_GNUC_UNUSED) ++{ ++#ifndef __linux__ ++ return EXIT_AM_SKIP; ++#else ++ const struct testFileIsSharedFSType *data = opaque; ++ g_autofree char *mtabFile = NULL; ++ bool actual; ++ int ret = -1; ++ ++ /* mtab is used by mocked realpath to decide whether a given path exists */ ++ mtabFile = g_strdup_printf(abs_srcdir "/virfiledata/%s", data->mtabFile); ++ ++ if (!g_setenv("LIBVIRT_MTAB", mtabFile, true)) { ++ fprintf(stderr, "Unable to set env variable\n"); ++ goto cleanup; ++ } ++ ++ actual = virFileIsSharedFSOverride(data->filename, ++ (char * const *) shared_filesystems); ++ ++ if (actual != data->expected) { ++ fprintf(stderr, "FS of '%s' is %s. Expected: %s\n", ++ data->filename, ++ actual ? "shared" : "not shared", ++ data->expected ? "shared" : "not shared"); ++ goto cleanup; ++ } ++ ++ ret = 0; ++ ++ cleanup: ++ g_unsetenv("LIBVIRT_MTAB"); ++ return ret; ++#endif ++} ++ ++ + static int + mymain(void) + { +@@ -439,6 +488,26 @@ mymain(void) + DO_TEST_FILE_IS_SHARED_FS_TYPE("mounts3.txt", "/gpfs/data", true); + DO_TEST_FILE_IS_SHARED_FS_TYPE("mounts3.txt", "/quobyte", true); + ++#define DO_TEST_FILE_IS_SHARED_FS_OVERRIDE(mtab, file, exp) \ ++ do { \ ++ struct testFileIsSharedFSType data = { \ ++ .mtabFile = mtab, .filename = file, .expected = exp \ ++ }; \ ++ if (virTestRun(virTestCounterNext(), testFileIsSharedFSOverride, &data) < 0) \ ++ ret = -1; \ ++ } while (0) ++ ++ virTestCounterReset("testFileIsSharedFSOverride "); ++ DO_TEST_FILE_IS_SHARED_FS_OVERRIDE("mounts2.txt", "/boot/vmlinuz", false); ++ DO_TEST_FILE_IS_SHARED_FS_OVERRIDE("mounts2.txt", "/run/user/501/gvfs/some/file", true); ++ DO_TEST_FILE_IS_SHARED_FS_OVERRIDE("mounts3.txt", "/nfs/file", true); ++ DO_TEST_FILE_IS_SHARED_FS_OVERRIDE("mounts3.txt", "/gluster/file", true); ++ DO_TEST_FILE_IS_SHARED_FS_OVERRIDE("mounts3.txt", "/some/symlink/file", true); ++ DO_TEST_FILE_IS_SHARED_FS_OVERRIDE("mounts3.txt", "/ceph/file", false); ++ DO_TEST_FILE_IS_SHARED_FS_OVERRIDE("mounts3.txt", "/ceph/multi/file", true); ++ DO_TEST_FILE_IS_SHARED_FS_OVERRIDE("mounts3.txt", "/gpfs/data", false); ++ DO_TEST_FILE_IS_SHARED_FS_OVERRIDE("mounts3.txt", "/quobyte", true); ++ + return ret != 0 ? EXIT_FAILURE : EXIT_SUCCESS; + } + +-- +2.52.0 diff --git a/libvirt-util-Fix-race-condition-in-virFileIsSharedFSOverride.patch b/libvirt-util-Fix-race-condition-in-virFileIsSharedFSOverride.patch new file mode 100644 index 0000000..f826270 --- /dev/null +++ b/libvirt-util-Fix-race-condition-in-virFileIsSharedFSOverride.patch @@ -0,0 +1,114 @@ +From 7f7d60e42f39deaec69318b93cf922f1dda54a26 Mon Sep 17 00:00:00 2001 +Message-ID: <7f7d60e42f39deaec69318b93cf922f1dda54a26.1766070256.git.jdenemar@redhat.com> +From: Jiri Denemark +Date: Fri, 5 Dec 2025 16:51:25 +0100 +Subject: [PATCH] util: Fix race condition in virFileIsSharedFSOverride + +Switch virFileIsSharedFSOverride to use virFileCheckParents to avoid a +race which could result in virFileCanonicalizePath to be called on a +path that does not exist anymore. + +Signed-off-by: Jiri Denemark +(cherry picked from commit 3a44f0c23d75519a9a374f790f4b91ab7b65a138) + +https://issues.redhat.com/browse/RHEL-135287 + +Signed-off-by: Jiri Denemark +--- + src/util/virfile.c | 59 +++++++++++++++++----------------------------- + 1 file changed, 22 insertions(+), 37 deletions(-) + +diff --git a/src/util/virfile.c b/src/util/virfile.c +index 95fc8ff0e6..52d711d2a9 100644 +--- a/src/util/virfile.c ++++ b/src/util/virfile.c +@@ -3502,33 +3502,6 @@ virFileCheckParents(const char *path, + } + + +-static char * +-virFileGetExistingParent(const char *path) +-{ +- g_autofree char *dirpath = g_strdup(path); +- char *p = NULL; +- +- /* Try less and less of the path until we get to a directory we can access. +- * Even if we don't have 'x' permission on any directory in the path on the +- * NFS server (assuming it's NFS), we will be able to stat the mount point. +- */ +- while (!virFileExists(dirpath) && p != dirpath) { +- if (!(p = strrchr(dirpath, '/'))) { +- virReportSystemError(EINVAL, +- _("Invalid relative path '%1$s'"), path); +- return NULL; +- } +- +- if (p == dirpath) +- *(p + 1) = '\0'; +- else +- *p = '\0'; +- } +- +- return g_steal_pointer(&dirpath); +-} +- +- + #ifdef __linux__ + + # ifndef NFS_SUPER_MAGIC +@@ -3875,6 +3848,17 @@ virFileGetDefaultHugepage(virHugeTLBFS *fs, + } + + ++static bool ++virFileCheckParentsCanonicalize(const char *path, ++ void *opaque) ++{ ++ char **canonical = opaque; ++ ++ *canonical = virFileCanonicalizePath(path); ++ return !!*canonical; ++} ++ ++ + /** + * virFileIsSharedFSOverride: + * @path: Path to check +@@ -3888,24 +3872,25 @@ virFileIsSharedFSOverride(const char *path, + char *const *overrides) + { + g_autofree char *dirpath = NULL; +- g_autofree char *existing = NULL; + char *p = NULL; ++ int rc; + + if (!path || path[0] != '/' || !overrides) + return false; + + /* We only care about the longest existing sub-path. Further components +- * may will later be created by libvirt will not magically become a shared +- * filesystem. */ +- if (!(existing = virFileGetExistingParent(path))) ++ * that may later be created by libvirt will not magically become a shared ++ * filesystem. Overrides have been canonicalized ahead of time, so we need ++ * to do the same for the provided path or we'll never be able to find a ++ * match if symlinks are involved. ++ */ ++ rc = virFileCheckParents(path, NULL, ++ virFileCheckParentsCanonicalize, &dirpath); ++ if (rc == -1) + return false; + +- /* Overrides have been canonicalized ahead of time, so we need to +- * do the same for the provided path or we'll never be able to +- * find a match if symlinks are involved */ +- if (!(dirpath = virFileCanonicalizePath(existing))) { +- VIR_DEBUG("Cannot canonicalize parent '%s' of path '%s'", +- existing, path); ++ if (rc != 0) { ++ VIR_DEBUG("Cannot canonicalize path '%s'", path); + return false; + } + +-- +2.52.0 diff --git a/libvirt-util-Fix-race-condition-in-virFileIsSharedFSType.patch b/libvirt-util-Fix-race-condition-in-virFileIsSharedFSType.patch new file mode 100644 index 0000000..9ba7572 --- /dev/null +++ b/libvirt-util-Fix-race-condition-in-virFileIsSharedFSType.patch @@ -0,0 +1,144 @@ +From 4596ee4c2fe33d3b44a44b120d61052ac943bae4 Mon Sep 17 00:00:00 2001 +Message-ID: <4596ee4c2fe33d3b44a44b120d61052ac943bae4.1766070256.git.jdenemar@redhat.com> +From: Jiri Denemark +Date: Fri, 5 Dec 2025 16:47:14 +0100 +Subject: [PATCH] util: Fix race condition in virFileIsSharedFSType + +virFileIsSharedFSType could end up calling statfs on a path that no +longer exists and return an error. If this happens for a path on a +shared filesystem, the caller may incorrectly consider the path as +non-shared. + +Specifically, when starting a domain with TPM enabled and deciding +whether its vTPM state is stored on a shared storage, the race could +cause qemuTPMEmulatorBuildCommand to consider the state to be +non-shared. This means swtpm would be started without --migration even +when the state is actually stored on a shared storage and any attempt to +migrate such domain would fail with + + Operation not supported: the running swtpm does not support + migration with shared storage + +In fact, any caller of virFileGetExistingParent contained an inherent +TOCTOU race condition as the existing parent of a given path return by +virFileGetExistingParent may no longer exist at the time the caller +wants to check it. + +This patch introduces a new virFileCheckParents API which is almost +identical to virFileGetExistingParent, but uses a supplied callback to +check each path. This new API is used in virFileIsSharedFSType to avoid +the race. The old function will later be completely removed once all +callers are switched to the new one. + +Fixes: 05526b50909ff50c16e13a0b5580d41de74e3d59 +Signed-off-by: Jiri Denemark +(cherry picked from commit b6addd42bece693debbf2e95551a2b4d2e1b453f) + +https://issues.redhat.com/browse/RHEL-135287 + +Signed-off-by: Jiri Denemark +--- + src/util/virfile.c | 71 ++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 69 insertions(+), 2 deletions(-) + +diff --git a/src/util/virfile.c b/src/util/virfile.c +index a5c9fbe0d9..95fc8ff0e6 100644 +--- a/src/util/virfile.c ++++ b/src/util/virfile.c +@@ -3445,6 +3445,63 @@ virFileRemoveLastComponent(char *path) + } + + ++/* Check callback for virFileCheckParents */ ++typedef bool (*virFileCheckParentsCallback)(const char *dirpath, ++ void *opaque); ++ ++/** ++ * virFileCheckParents: ++ * @path: path to check ++ * @parent: where to store the closest parent satisfying the check ++ * @check: callback called on parent paths ++ * @opaque: data for the @check callback ++ * ++ * Calls @check on the @path and its parent paths until it returns true or a ++ * root directory is reached. When @check returns true, the @parent (if ++ * non-NULL) will be set to a copy of the corresponding path. The caller is ++ * responsible for freeing it. ++ * ++ * Returns 0 on success (@parent set), ++ * -1 on invalid input, ++ * -2 when no path (including "/") satisfies the @check. ++ */ ++static int ++virFileCheckParents(const char *path, ++ char **parent, ++ virFileCheckParentsCallback check, ++ void *opaque) ++{ ++ g_autofree char *dirpath = g_strdup(path); ++ char *p = NULL; ++ bool checkOK; ++ ++ checkOK = check(dirpath, opaque); ++ ++ while (!checkOK && p != dirpath) { ++ if (!(p = strrchr(dirpath, G_DIR_SEPARATOR))) { ++ virReportSystemError(EINVAL, ++ _("Invalid absolute path '%1$s'"), path); ++ return -1; ++ } ++ ++ if (p == dirpath) ++ *(p + 1) = '\0'; ++ else ++ *p = '\0'; ++ ++ checkOK = check(dirpath, opaque); ++ } ++ ++ if (!checkOK) ++ return -2; ++ ++ if (parent) ++ *parent = g_steal_pointer(&dirpath); ++ ++ return 0; ++} ++ ++ + static char * + virFileGetExistingParent(const char *path) + { +@@ -3599,6 +3656,14 @@ static const struct virFileSharedFsData virFileSharedFs[] = { + }; + + ++static bool ++virFileCheckParentsStatFS(const char *path, ++ void *opaque) ++{ ++ return statfs(path, (struct statfs *) opaque) == 0; ++} ++ ++ + int + virFileIsSharedFSType(const char *path, + unsigned int fstypes) +@@ -3607,11 +3672,13 @@ virFileIsSharedFSType(const char *path, + struct statfs sb; + long long f_type = 0; + size_t i; ++ int rc; + +- if (!(dirpath = virFileGetExistingParent(path))) ++ if ((rc = virFileCheckParents(path, &dirpath, ++ virFileCheckParentsStatFS, &sb)) == -1) + return -1; + +- if (statfs(dirpath, &sb) < 0) { ++ if (rc != 0) { + virReportSystemError(errno, + _("cannot determine filesystem for '%1$s'"), + path); +-- +2.52.0 diff --git a/libvirt-util-Rework-virFileIsSharedFSOverride-using-virFileCheckParents.patch b/libvirt-util-Rework-virFileIsSharedFSOverride-using-virFileCheckParents.patch new file mode 100644 index 0000000..e5af23d --- /dev/null +++ b/libvirt-util-Rework-virFileIsSharedFSOverride-using-virFileCheckParents.patch @@ -0,0 +1,84 @@ +From d85627338e531618aa72b6039483b0d0a3e3d474 Mon Sep 17 00:00:00 2001 +Message-ID: +From: Jiri Denemark +Date: Fri, 5 Dec 2025 16:52:32 +0100 +Subject: [PATCH] util: Rework virFileIsSharedFSOverride using + virFileCheckParents + +The newly introduced virFileCheckParents is generic enough to be used +for checking whether a specific path or any of its parents is included +in the overrides array. + +Signed-off-by: Jiri Denemark +(cherry picked from commit eedf9ed68b45585569865604bf2a403670feaf3e) + +https://issues.redhat.com/browse/RHEL-135287 + +Signed-off-by: Jiri Denemark +--- + src/util/virfile.c | 35 ++++++++++++----------------------- + 1 file changed, 12 insertions(+), 23 deletions(-) + +diff --git a/src/util/virfile.c b/src/util/virfile.c +index 52d711d2a9..05b2fa8168 100644 +--- a/src/util/virfile.c ++++ b/src/util/virfile.c +@@ -3859,6 +3859,14 @@ virFileCheckParentsCanonicalize(const char *path, + } + + ++static bool ++virFileCheckParentsInOverrides(const char *path, ++ void *opaque) ++{ ++ return g_strv_contains((const char *const *) opaque, path); ++} ++ ++ + /** + * virFileIsSharedFSOverride: + * @path: Path to check +@@ -3872,7 +3880,6 @@ virFileIsSharedFSOverride(const char *path, + char *const *overrides) + { + g_autofree char *dirpath = NULL; +- char *p = NULL; + int rc; + + if (!path || path[0] != '/' || !overrides) +@@ -3894,29 +3901,11 @@ virFileIsSharedFSOverride(const char *path, + return false; + } + +- if (g_strv_contains((const char *const *) overrides, dirpath)) +- return true; ++ if (virFileCheckParents(dirpath, NULL, virFileCheckParentsInOverrides, ++ (void *) overrides) < 0) ++ return false; + +- /* Continue until we've scanned the entire path */ +- while (p != dirpath) { +- +- /* Find the last slash */ +- if ((p = strrchr(dirpath, '/')) == NULL) +- break; +- +- /* Truncate the path by overwriting the slash that we've just +- * found with a null byte. If it is the very first slash in +- * the path, we need to handle things slightly differently */ +- if (p == dirpath) +- *(p+1) = '\0'; +- else +- *p = '\0'; +- +- if (g_strv_contains((const char *const *) overrides, dirpath)) +- return true; +- } +- +- return false; ++ return true; + } + + +-- +2.52.0 diff --git a/libvirt.spec b/libvirt.spec index 21a6112..7468abd 100644 --- a/libvirt.spec +++ b/libvirt.spec @@ -294,7 +294,7 @@ Summary: Library providing a simple virtualization API Name: libvirt Version: 11.10.0 -Release: 1%{?dist}%{?extra_release} +Release: 2%{?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/ @@ -302,6 +302,12 @@ URL: https://libvirt.org/ %define mainturl stable_updates/ %endif Source: https://download.libvirt.org/%{?mainturl}libvirt-%{version}.tar.xz +Patch1: libvirt-qemu-tpm-Account-for-possible-migration-without-actually-sharing-storage.patch +Patch2: libvirt-tests-Test-virFileIsSharedFSOverride.patch +Patch3: libvirt-util-Fix-race-condition-in-virFileIsSharedFSType.patch +Patch4: libvirt-util-Fix-race-condition-in-virFileIsSharedFSOverride.patch +Patch5: libvirt-util-Rework-virFileIsSharedFSOverride-using-virFileCheckParents.patch + Requires: libvirt-daemon = %{version}-%{release} Requires: libvirt-daemon-config-network = %{version}-%{release} @@ -1168,6 +1174,9 @@ MinGW Windows libvirt virtualization library. %prep %autosetup -S git_am -N +%autopatch + + %build %if 0%{?fedora} >= %{min_fedora} || 0%{?rhel} >= %{min_rhel} %define supported_platform 1 @@ -2689,6 +2698,13 @@ exit 0 %endif %changelog +* Thu Dec 18 2025 Jiri Denemark - 11.10.0-2 +- qemu: tpm: Account for possible migration without actually sharing storage (RHEL-108915) +- tests: Test virFileIsSharedFSOverride (RHEL-135287) +- util: Fix race condition in virFileIsSharedFSType (RHEL-135287) +- util: Fix race condition in virFileIsSharedFSOverride (RHEL-135287) +- util: Rework virFileIsSharedFSOverride using virFileCheckParents (RHEL-135287) + * Tue Dec 2 2025 Jiri Denemark - 11.10.0-1 - Rebased to libvirt-11.10.0 (RHEL-118197) - The rebase also fixes the following bugs: