From bfc31e8282358b9786ef858a86f36c396bf6e415 Mon Sep 17 00:00:00 2001 From: Pavel Hrdina Date: Fri, 20 Mar 2026 17:25:56 +0100 Subject: [PATCH] libvirt-11.10.0-10.4.el10nv - security_apparmor: Use g_auto* in AppArmorSetSecurityHostdevLabel (VOYAGER-309) - security: Cleanup hostdev label error logic (VOYAGER-309) - qemu: Fix IOMMUFD and VFIO security labels (VOYAGER-309) - viriommufd: Set IOMMU_OPTION_RLIMIT_MODE only when running privileged (VOYAGER-309) - conf: Move and rename virStorageSourceFDTuple object (VOYAGER-309) - conf: Refactor virHostdevIsPCIDevice (VOYAGER-309) - hypervisor: Fix virHostdevNeedsVFIO detection (VOYAGER-309) - qemu: Expand call to qemuDomainNeedsVFIO (VOYAGER-309) - qemu: Update qemuDomainNeedsVFIO to ignore PCI hostdev with IOMMUFD (VOYAGER-309) - src: Use virHostdevIsPCIDeviceWith* to check for IOMMUFD (VOYAGER-309) - conf: Introduce domain iommufd element (VOYAGER-309) - qemu: Implement iommufd (VOYAGER-309) - conf: Add iommufd fdgroup support (VOYAGER-309) - qemu: Implement iommufd fdgroup (VOYAGER-309) - tests: Add iommufd fdgroup test (VOYAGER-309) Resolves: VOYAGER-309 --- ...irt-conf-Add-iommufd-fdgroup-support.patch | 162 +++++ ...onf-Introduce-domain-iommufd-element.patch | 220 +++++++ ...ename-virStorageSourceFDTuple-object.patch | 332 ++++++++++ ...-conf-Refactor-virHostdevIsPCIDevice.patch | 82 +++ ...or-Fix-virHostdevNeedsVFIO-detection.patch | 100 +++ ...u-Expand-call-to-qemuDomainNeedsVFIO.patch | 53 ++ ...Fix-IOMMUFD-and-VFIO-security-labels.patch | 247 +++++++ libvirt-qemu-Implement-iommufd-fdgroup.patch | 129 ++++ libvirt-qemu-Implement-iommufd.patch | 121 ++++ ...O-to-ignore-PCI-hostdev-with-IOMMUFD.patch | 109 ++++ ...ty-Cleanup-hostdev-label-error-logic.patch | 613 ++++++++++++++++++ ...o-in-AppArmorSetSecurityHostdevLabel.patch | 120 ++++ ...IsPCIDeviceWith-to-check-for-IOMMUFD.patch | 154 +++++ libvirt-tests-Add-iommufd-fdgroup-test.patch | 268 ++++++++ ...IT_MODE-only-when-running-privileged.patch | 81 +++ libvirt.spec | 34 +- 16 files changed, 2824 insertions(+), 1 deletion(-) create mode 100644 libvirt-conf-Add-iommufd-fdgroup-support.patch create mode 100644 libvirt-conf-Introduce-domain-iommufd-element.patch create mode 100644 libvirt-conf-Move-and-rename-virStorageSourceFDTuple-object.patch create mode 100644 libvirt-conf-Refactor-virHostdevIsPCIDevice.patch create mode 100644 libvirt-hypervisor-Fix-virHostdevNeedsVFIO-detection.patch create mode 100644 libvirt-qemu-Expand-call-to-qemuDomainNeedsVFIO.patch create mode 100644 libvirt-qemu-Fix-IOMMUFD-and-VFIO-security-labels.patch create mode 100644 libvirt-qemu-Implement-iommufd-fdgroup.patch create mode 100644 libvirt-qemu-Implement-iommufd.patch create mode 100644 libvirt-qemu-Update-qemuDomainNeedsVFIO-to-ignore-PCI-hostdev-with-IOMMUFD.patch create mode 100644 libvirt-security-Cleanup-hostdev-label-error-logic.patch create mode 100644 libvirt-security_apparmor-Use-g_auto-in-AppArmorSetSecurityHostdevLabel.patch create mode 100644 libvirt-src-Use-virHostdevIsPCIDeviceWith-to-check-for-IOMMUFD.patch create mode 100644 libvirt-tests-Add-iommufd-fdgroup-test.patch create mode 100644 libvirt-viriommufd-Set-IOMMU_OPTION_RLIMIT_MODE-only-when-running-privileged.patch diff --git a/libvirt-conf-Add-iommufd-fdgroup-support.patch b/libvirt-conf-Add-iommufd-fdgroup-support.patch new file mode 100644 index 0000000..83d10c7 --- /dev/null +++ b/libvirt-conf-Add-iommufd-fdgroup-support.patch @@ -0,0 +1,162 @@ +From b06fc0bbe490630c77ac8382ff73d5fb8bc86682 Mon Sep 17 00:00:00 2001 +Message-ID: +From: Pavel Hrdina +Date: Fri, 13 Mar 2026 15:28:17 +0100 +Subject: [PATCH] conf: Add iommufd fdgroup support + +From: Pavel Hrdina + +This will allow management applications running libvirt without +necessary permissions to pass FD for /dev/iommu with per-process +locked memory accounting enabled. + +Kernel uses per-user locked memory accounting by default which may +cause error while starting multiple VMs with host devices using IOMMUFD. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Peter Krempa +(cherry picked from commit 58875a6df679c5272f61028d33bf1380c51b0d5b) + +Resolves: https://redhat.atlassian.net/browse/VOYAGER-309 +Signed-off-by: Pavel Hrdina +--- + docs/formatdomain.rst | 8 +++++++- + src/conf/domain_conf.c | 6 ++++++ + src/conf/domain_conf.h | 1 + + src/conf/domain_validate.c | 16 ++++++++++++++++ + src/conf/schemas/domaincommon.rng | 3 +++ + tests/genericxml2xmlindata/iommufd.xml | 2 +- + 6 files changed, 34 insertions(+), 2 deletions(-) + +diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst +index a211de1237..44f9b6e197 100644 +--- a/docs/formatdomain.rst ++++ b/docs/formatdomain.rst +@@ -1368,7 +1368,7 @@ Host Device IOMMUFD + + + ... +- ++ + ... + + +@@ -1382,6 +1382,12 @@ Host Device IOMMUFD + This controls IOMMUFD usage for all host devices, each device can change this + global default by setting ``iommufd`` attribute for ``driver`` element. + ++ Optional ``fdgroup`` attribute can be used together with ++ `virDomainFDAssociate `__ ++ to pass /dev/iommu FD instead of letting libvirt to open it. Caller is ++ responsible for setting per-process locked memory accounting otherwise ++ starting multiple VMs with host devices using IOMMUFD may fail. ++ + Resource partitioning + --------------------- + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index fe8309cb81..06790e0962 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -4192,6 +4192,8 @@ void virDomainDefFree(virDomainDef *def) + g_free(def->kvm_features); + g_free(def->tcg_features); + ++ g_free(def->iommufd_fdgroup); ++ + virBlkioDeviceArrayClear(def->blkio.devices, + def->blkio.ndevices); + g_free(def->blkio.devices); +@@ -19806,6 +19808,8 @@ virDomainDefIommufdParse(virDomainDef *def, + if (virXMLPropTristateBool(nodes[0], "enabled", VIR_XML_PROP_REQUIRED, &def->iommufd) < 0) + return -1; + ++ def->iommufd_fdgroup = virXMLPropString(nodes[0], "fdgroup"); ++ + return 0; + } + +@@ -28081,6 +28085,8 @@ virDomainDefIommufdFormat(virBuffer *buf, + virBufferAsprintf(&attrBuf, " enabled='%s'", + virTristateBoolTypeToString(def->iommufd)); + ++ virBufferEscapeString(&attrBuf, " fdgroup='%s'", def->iommufd_fdgroup); ++ + virXMLFormatElement(buf, "iommufd", &attrBuf, NULL); + } + +diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h +index 0d41aca3a9..06e03deafe 100644 +--- a/src/conf/domain_conf.h ++++ b/src/conf/domain_conf.h +@@ -3239,6 +3239,7 @@ struct _virDomainDef { + virDomainFeatureTCG *tcg_features; + + virTristateBool iommufd; ++ char *iommufd_fdgroup; + + bool tseg_specified; + unsigned long long tseg_size; +diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c +index 51f7961e3c..f243b119a4 100644 +--- a/src/conf/domain_validate.c ++++ b/src/conf/domain_validate.c +@@ -1996,6 +1996,19 @@ virDomainDefValidateThrottleGroups(const virDomainDef *def) + } + + ++static int ++virDomainDefValidateIommufd(const virDomainDef *def) ++{ ++ if (def->iommufd == VIR_TRISTATE_BOOL_NO && def->iommufd_fdgroup) { ++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", ++ _("Setting 'fdgroup' when 'iommufd' is disabled is not supported.")); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ + static int + virDomainDefValidateInternal(const virDomainDef *def, + virDomainXMLOption *xmlopt) +@@ -2057,6 +2070,9 @@ virDomainDefValidateInternal(const virDomainDef *def, + if (virDomainDefValidateThrottleGroups(def) < 0) + return -1; + ++ if (virDomainDefValidateIommufd(def) < 0) ++ return -1; ++ + return 0; + } + +diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng +index 40aa3eac27..839a144da8 100644 +--- a/src/conf/schemas/domaincommon.rng ++++ b/src/conf/schemas/domaincommon.rng +@@ -1353,6 +1353,9 @@ + + + ++ ++ ++ + + + +diff --git a/tests/genericxml2xmlindata/iommufd.xml b/tests/genericxml2xmlindata/iommufd.xml +index 63ea839383..10d59ca548 100644 +--- a/tests/genericxml2xmlindata/iommufd.xml ++++ b/tests/genericxml2xmlindata/iommufd.xml +@@ -4,7 +4,7 @@ + 219136 + 219136 + 1 +- ++ + + hvm + +-- +2.53.0 diff --git a/libvirt-conf-Introduce-domain-iommufd-element.patch b/libvirt-conf-Introduce-domain-iommufd-element.patch new file mode 100644 index 0000000..6ffa97e --- /dev/null +++ b/libvirt-conf-Introduce-domain-iommufd-element.patch @@ -0,0 +1,220 @@ +From 449dfefeb208ed42425a76a1ba69d5dd5401a7d0 Mon Sep 17 00:00:00 2001 +Message-ID: <449dfefeb208ed42425a76a1ba69d5dd5401a7d0.1774023916.git.phrdina@redhat.com> +From: Pavel Hrdina +Date: Fri, 13 Mar 2026 11:57:57 +0100 +Subject: [PATCH] conf: Introduce domain iommufd element + +From: Pavel Hrdina + +In addition to configuring IOMMUFD for each host device add +configuration for the whole VM. This will be extended to add support for +passing FD to libvirt from management applications. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Peter Krempa +(cherry picked from commit c03b8f0804f648a2bbc2eb7e957f2f8821b8e167) + +Resolves: https://redhat.atlassian.net/browse/VOYAGER-309 +Signed-off-by: Pavel Hrdina +--- + docs/formatdomain.rst | 21 ++++++++++++ + src/conf/domain_conf.c | 46 ++++++++++++++++++++++++++ + src/conf/domain_conf.h | 2 ++ + src/conf/schemas/domaincommon.rng | 12 +++++++ + tests/genericxml2xmlindata/iommufd.xml | 18 ++++++++++ + tests/genericxml2xmltest.c | 2 ++ + 6 files changed, 101 insertions(+) + create mode 100644 tests/genericxml2xmlindata/iommufd.xml + +diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst +index 8f1be253de..a211de1237 100644 +--- a/docs/formatdomain.rst ++++ b/docs/formatdomain.rst +@@ -1361,6 +1361,27 @@ Block I/O Tuning + ``write_iops_sec`` + Write I/O operations per second limit. :since:`Since 1.2.2` + ++Host Device IOMMUFD ++------------------- ++ ++:: ++ ++ ++ ... ++ ++ ... ++ ++ ++``iommufd`` ++ :since:`Since 12.2.0 (QEMU/KVM only)` The optional ``iommufd`` element with ++ mandatory ``enabled`` attribute can be used to enable IOMMUFD backend for ++ VFIO host devices. This provides an interface to propagate DMA mappings to ++ kernel for assigned devices. Libvirt will open the /dev/iommu and VFIO device ++ cdev and pass associated file descriptors to QEMU. ++ ++ This controls IOMMUFD usage for all host devices, each device can change this ++ global default by setting ``iommufd`` attribute for ``driver`` element. ++ + Resource partitioning + --------------------- + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index 6e49507e83..fe8309cb81 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -19784,6 +19784,31 @@ virDomainDefControllersParse(virDomainDef *def, + return 0; + } + ++static int ++virDomainDefIommufdParse(virDomainDef *def, ++ xmlXPathContextPtr ctxt) ++{ ++ int n; ++ g_autofree xmlNodePtr *nodes = NULL; ++ ++ if ((n = virXPathNodeSet("./iommufd", ctxt, &nodes)) < 0) ++ return -1; ++ ++ if (n > 1) { ++ virReportError(VIR_ERR_XML_ERROR, "%s", ++ _("only one 'iommufd' element is supported")); ++ return -1; ++ } ++ ++ if (n == 0) ++ return 0; ++ ++ if (virXMLPropTristateBool(nodes[0], "enabled", VIR_XML_PROP_REQUIRED, &def->iommufd) < 0) ++ return -1; ++ ++ return 0; ++} ++ + static virDomainDef * + virDomainDefParseXML(xmlXPathContextPtr ctxt, + virDomainXMLOption *xmlopt, +@@ -19862,6 +19887,9 @@ virDomainDefParseXML(xmlXPathContextPtr ctxt, + !virDomainIOThreadIDArrayHasPin(def)) + def->placement_mode = VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO; + ++ if (virDomainDefIommufdParse(def, ctxt) < 0) ++ return NULL; ++ + if ((n = virXPathNodeSet("./resource", ctxt, &nodes)) < 0) + return NULL; + +@@ -28041,6 +28069,22 @@ virDomainHubDefFormat(virBuffer *buf, + } + + ++static void ++virDomainDefIommufdFormat(virBuffer *buf, ++ virDomainDef *def) ++{ ++ g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER; ++ ++ if (def->iommufd == VIR_TRISTATE_BOOL_ABSENT) ++ return; ++ ++ virBufferAsprintf(&attrBuf, " enabled='%s'", ++ virTristateBoolTypeToString(def->iommufd)); ++ ++ virXMLFormatElement(buf, "iommufd", &attrBuf, NULL); ++} ++ ++ + static void + virDomainResourceDefFormat(virBuffer *buf, + virDomainResourceDef *def) +@@ -29589,6 +29633,8 @@ virDomainDefFormatInternalSetRootName(virDomainDef *def, + if (virDomainNumatuneFormatXML(buf, def->numa) < 0) + return -1; + ++ virDomainDefIommufdFormat(buf, def); ++ + virDomainResourceDefFormat(buf, def->resource); + + for (i = 0; i < def->nsysinfo; i++) { +diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h +index de803d0dcc..0d41aca3a9 100644 +--- a/src/conf/domain_conf.h ++++ b/src/conf/domain_conf.h +@@ -3238,6 +3238,8 @@ struct _virDomainDef { + virTristateSwitch apic_eoi; + virDomainFeatureTCG *tcg_features; + ++ virTristateBool iommufd; ++ + bool tseg_specified; + unsigned long long tseg_size; + +diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng +index 5d0e538535..40aa3eac27 100644 +--- a/src/conf/schemas/domaincommon.rng ++++ b/src/conf/schemas/domaincommon.rng +@@ -1001,6 +1001,10 @@ + + + ++ ++ ++ ++ + + + +@@ -1344,6 +1348,14 @@ + + + ++ ++ ++ ++ ++ ++ ++ ++ + + + +diff --git a/tests/genericxml2xmlindata/iommufd.xml b/tests/genericxml2xmlindata/iommufd.xml +new file mode 100644 +index 0000000000..63ea839383 +--- /dev/null ++++ b/tests/genericxml2xmlindata/iommufd.xml +@@ -0,0 +1,18 @@ ++ ++ foo ++ c7a5fdbd-edaf-9455-926a-d65c16db1809 ++ 219136 ++ 219136 ++ 1 ++ ++ ++ hvm ++ ++ ++ ++ destroy ++ restart ++ destroy ++ ++ ++ +diff --git a/tests/genericxml2xmltest.c b/tests/genericxml2xmltest.c +index 6757fc44de..6be694cac5 100644 +--- a/tests/genericxml2xmltest.c ++++ b/tests/genericxml2xmltest.c +@@ -263,6 +263,8 @@ mymain(void) + + DO_TEST("iothreadids"); + ++ DO_TEST("iommufd"); ++ + virObjectUnref(caps); + virObjectUnref(xmlopt); + +-- +2.53.0 diff --git a/libvirt-conf-Move-and-rename-virStorageSourceFDTuple-object.patch b/libvirt-conf-Move-and-rename-virStorageSourceFDTuple-object.patch new file mode 100644 index 0000000..47a9afb --- /dev/null +++ b/libvirt-conf-Move-and-rename-virStorageSourceFDTuple-object.patch @@ -0,0 +1,332 @@ +From 29bd170f0fafdb9518f0c795207aab1ea73f2fad Mon Sep 17 00:00:00 2001 +Message-ID: <29bd170f0fafdb9518f0c795207aab1ea73f2fad.1774023916.git.phrdina@redhat.com> +From: Pavel Hrdina +Date: Fri, 13 Mar 2026 16:59:01 +0100 +Subject: [PATCH] conf: Move and rename virStorageSourceFDTuple object + +From: Pavel Hrdina + +Associating FD can be used by other parts of VM so rename it to generic +virDomainFDTuple. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Peter Krempa +(cherry picked from commit f89e3dbce809f64246a8fe5ef0d05a63a28a05c0) + +Resolves: https://redhat.atlassian.net/browse/VOYAGER-309 +Signed-off-by: Pavel Hrdina +--- + src/conf/meson.build | 1 + + src/conf/storage_source_conf.c | 42 --------------------------- + src/conf/storage_source_conf.h | 24 ++-------------- + src/conf/virdomainfd.c | 52 ++++++++++++++++++++++++++++++++++ + src/conf/virdomainfd.h | 27 ++++++++++++++++++ + src/libvirt_private.syms | 5 +++- + src/qemu/qemu_backup.c | 2 +- + src/qemu/qemu_domain.c | 2 +- + src/qemu/qemu_driver.c | 6 ++-- + tests/testutilsqemu.c | 2 +- + 10 files changed, 92 insertions(+), 71 deletions(-) + create mode 100644 src/conf/virdomainfd.c + create mode 100644 src/conf/virdomainfd.h + +diff --git a/src/conf/meson.build b/src/conf/meson.build +index 5116c23fe3..6f95b23cce 100644 +--- a/src/conf/meson.build ++++ b/src/conf/meson.build +@@ -20,6 +20,7 @@ domain_conf_sources = [ + 'numa_conf.c', + 'snapshot_conf.c', + 'virdomaincheckpointobjlist.c', ++ 'virdomainfd.c', + 'virdomainjob.c', + 'virdomainmomentobjlist.c', + 'virdomainobjlist.c', +diff --git a/src/conf/storage_source_conf.c b/src/conf/storage_source_conf.c +index 24d4b0de6a..493b1411b3 100644 +--- a/src/conf/storage_source_conf.c ++++ b/src/conf/storage_source_conf.c +@@ -1413,48 +1413,6 @@ virStorageSourceInitiatorClear(virStorageSourceInitiatorDef *initiator) + VIR_FREE(initiator->iqn); + } + +-G_DEFINE_TYPE(virStorageSourceFDTuple, vir_storage_source_fd_tuple, G_TYPE_OBJECT); +- +-static void +-vir_storage_source_fd_tuple_init(virStorageSourceFDTuple *fdt G_GNUC_UNUSED) +-{ +-} +- +- +-static void +-virStorageSourceFDTupleFinalize(GObject *object) +-{ +- virStorageSourceFDTuple *fdt = VIR_STORAGE_SOURCE_FD_TUPLE(object); +- size_t i; +- +- if (!fdt) +- return; +- +- for (i = 0; i < fdt->nfds; i++) +- VIR_FORCE_CLOSE(fdt->fds[i]); +- +- g_free(fdt->fds); +- g_free(fdt->testfds); +- g_free(fdt->selinuxLabel); +- G_OBJECT_CLASS(vir_storage_source_fd_tuple_parent_class)->finalize(object); +-} +- +- +-static void +-vir_storage_source_fd_tuple_class_init(virStorageSourceFDTupleClass *klass) +-{ +- GObjectClass *obj = G_OBJECT_CLASS(klass); +- +- obj->finalize = virStorageSourceFDTupleFinalize; +-} +- +- +-virStorageSourceFDTuple * +-virStorageSourceFDTupleNew(void) +-{ +- return g_object_new(vir_storage_source_fd_tuple_get_type(), NULL); +-} +- + + /** + * virStorageSourceNetworkProtocolPathSplit: +diff --git a/src/conf/storage_source_conf.h b/src/conf/storage_source_conf.h +index 5a4b088eeb..b47313bae5 100644 +--- a/src/conf/storage_source_conf.h ++++ b/src/conf/storage_source_conf.h +@@ -24,6 +24,7 @@ + #include "storage_encryption_conf.h" + #include "virbitmap.h" + #include "virconftypes.h" ++#include "virdomainfd.h" + #include "virenum.h" + #include "virobject.h" + #include "virpci.h" +@@ -268,27 +269,6 @@ struct _virStorageSourceSlice { + void + virStorageSourceSliceFree(virStorageSourceSlice *slice); + +-struct _virStorageSourceFDTuple { +- GObject parent; +- int *fds; +- size_t nfds; +- int *testfds; /* populated by tests to ensure stable FDs */ +- +- bool writable; +- bool tryRestoreLabel; +- +- /* connection this FD tuple is associated with for auto-closing */ +- virConnect *conn; +- +- /* original selinux label when we relabel the image */ +- char *selinuxLabel; +-}; +-G_DECLARE_FINAL_TYPE(virStorageSourceFDTuple, vir_storage_source_fd_tuple, VIR, STORAGE_SOURCE_FD_TUPLE, GObject); +- +-virStorageSourceFDTuple * +-virStorageSourceFDTupleNew(void); +- +- + typedef struct _virStorageSource virStorageSource; + + /* Stores information related to a host resource. In the case of backing +@@ -441,7 +421,7 @@ struct _virStorageSource { + * one event for it */ + bool thresholdEventWithIndex; + +- virStorageSourceFDTuple *fdtuple; ++ virDomainFDTuple *fdtuple; + + /* Setting 'seclabelSkipRemember' to true will cause the security driver to + * not remember the security label even if it otherwise were to be +diff --git a/src/conf/virdomainfd.c b/src/conf/virdomainfd.c +new file mode 100644 +index 0000000000..13c3161e6a +--- /dev/null ++++ b/src/conf/virdomainfd.c +@@ -0,0 +1,52 @@ ++/* ++ * SPDX-License-Identifier: LGPL-2.1-or-later ++ */ ++ ++#include ++ ++#include "virdomainfd.h" ++ ++#include "virfile.h" ++ ++G_DEFINE_TYPE(virDomainFDTuple, vir_domain_fd_tuple, G_TYPE_OBJECT); ++ ++ ++static void ++vir_domain_fd_tuple_init(virDomainFDTuple *fdt G_GNUC_UNUSED) ++{ ++} ++ ++ ++static void ++virDomainFDTupleFinalize(GObject *object) ++{ ++ virDomainFDTuple *fdt = VIR_DOMAIN_FD_TUPLE(object); ++ size_t i; ++ ++ if (!fdt) ++ return; ++ ++ for (i = 0; i < fdt->nfds; i++) ++ VIR_FORCE_CLOSE(fdt->fds[i]); ++ ++ g_free(fdt->fds); ++ g_free(fdt->testfds); ++ g_free(fdt->selinuxLabel); ++ G_OBJECT_CLASS(vir_domain_fd_tuple_parent_class)->finalize(object); ++} ++ ++ ++static void ++vir_domain_fd_tuple_class_init(virDomainFDTupleClass *klass) ++{ ++ GObjectClass *obj = G_OBJECT_CLASS(klass); ++ ++ obj->finalize = virDomainFDTupleFinalize; ++} ++ ++ ++virDomainFDTuple * ++virDomainFDTupleNew(void) ++{ ++ return g_object_new(vir_domain_fd_tuple_get_type(), NULL); ++} +diff --git a/src/conf/virdomainfd.h b/src/conf/virdomainfd.h +new file mode 100644 +index 0000000000..0c0d475ed6 +--- /dev/null ++++ b/src/conf/virdomainfd.h +@@ -0,0 +1,27 @@ ++/* ++ * SPDX-License-Identifier: LGPL-2.1-or-later ++ */ ++ ++#pragma once ++ ++#include "internal.h" ++ ++struct _virDomainFDTuple { ++ GObject parent; ++ int *fds; ++ size_t nfds; ++ int *testfds; /* populated by tests to ensure stable FDs */ ++ ++ bool writable; ++ bool tryRestoreLabel; ++ ++ /* connection this FD tuple is associated with for auto-closing */ ++ virConnect *conn; ++ ++ /* original selinux label when we relabel the image */ ++ char *selinuxLabel; ++}; ++G_DECLARE_FINAL_TYPE(virDomainFDTuple, vir_domain_fd_tuple, VIR, DOMAIN_FD_TUPLE, GObject); ++ ++virDomainFDTuple * ++virDomainFDTupleNew(void); +diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms +index effe44fe57..386e757d81 100644 +--- a/src/libvirt_private.syms ++++ b/src/libvirt_private.syms +@@ -1177,7 +1177,6 @@ virStorageSourceChainHasManagedPR; + virStorageSourceChainHasNVMe; + virStorageSourceClear; + virStorageSourceCopy; +-virStorageSourceFDTupleNew; + virStorageSourceGetActualType; + virStorageSourceGetSecurityLabelDef; + virStorageSourceHasBacking; +@@ -1230,6 +1229,10 @@ virDomainCheckpointUpdateRelations; + virDomainListCheckpoints; + + ++# conf/virdomainfd.h ++virDomainFDTupleNew; ++ ++ + #conf/virdomainjob.h + virDomainAgentJobTypeToString; + virDomainAsyncJobTypeFromString; +diff --git a/src/qemu/qemu_backup.c b/src/qemu/qemu_backup.c +index c3566bcd57..eebf6cdc06 100644 +--- a/src/qemu/qemu_backup.c ++++ b/src/qemu/qemu_backup.c +@@ -876,7 +876,7 @@ qemuBackupBegin(virDomainObj *vm, + priv->backup = g_steal_pointer(&def); + + if (pull && priv->backup->server->fdgroup) { +- virStorageSourceFDTuple *fdt = NULL; ++ virDomainFDTuple *fdt = NULL; + VIR_AUTOCLOSE fdcopy = -1; + + if (!(fdt = virHashLookup(priv->fds, priv->backup->server->fdgroup))) { +diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c +index ccbfc8bac7..5c9f4831fd 100644 +--- a/src/qemu/qemu_domain.c ++++ b/src/qemu/qemu_domain.c +@@ -9835,7 +9835,7 @@ qemuDomainPrepareStorageSourceFDs(virStorageSource *src, + { + qemuDomainStorageSourcePrivate *srcpriv = NULL; + virStorageType actualType = virStorageSourceGetActualType(src); +- virStorageSourceFDTuple *fdt = NULL; ++ virDomainFDTuple *fdt = NULL; + size_t i; + + if (actualType != VIR_STORAGE_TYPE_FILE && +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index f3e7410f9e..5e63614b4a 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -20234,7 +20234,7 @@ qemuDomainFDHashCloseConnect(virDomainObj *vm, + virConnectPtr conn) + { + qemuDomainObjPrivate *priv = QEMU_DOMAIN_PRIVATE(vm); +- virStorageSourceFDTuple *data; ++ virDomainFDTuple *data; + GHashTableIter htitr; + + if (!priv->fds) +@@ -20258,7 +20258,7 @@ qemuDomainFDAssociate(virDomainPtr domain, + { + virDomainObj *vm = NULL; + qemuDomainObjPrivate *priv; +- g_autoptr(virStorageSourceFDTuple) new = NULL; ++ g_autoptr(virDomainFDTuple) new = NULL; + size_t i; + int ret = -1; + +@@ -20276,7 +20276,7 @@ qemuDomainFDAssociate(virDomainPtr domain, + + priv = vm->privateData; + +- new = virStorageSourceFDTupleNew(); ++ new = virDomainFDTupleNew(); + new->nfds = nfds; + new->fds = g_new0(int, new->nfds); + for (i = 0; i < new->nfds; i++) { +diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c +index 78ec521266..fc51e0e3df 100644 +--- a/tests/testutilsqemu.c ++++ b/tests/testutilsqemu.c +@@ -713,7 +713,7 @@ testQemuInfoSetArgs(testQemuInfo *info, + break; + + case ARG_FD_GROUP: { +- virStorageSourceFDTuple *new = virStorageSourceFDTupleNew(); ++ virDomainFDTuple *new = virDomainFDTupleNew(); + const char *fdname = va_arg(argptr, char *); + VIR_AUTOCLOSE fakefd = open("/dev/zero", O_RDWR); + bool writable = va_arg(argptr, int); +-- +2.53.0 diff --git a/libvirt-conf-Refactor-virHostdevIsPCIDevice.patch b/libvirt-conf-Refactor-virHostdevIsPCIDevice.patch new file mode 100644 index 0000000..c95bb2d --- /dev/null +++ b/libvirt-conf-Refactor-virHostdevIsPCIDevice.patch @@ -0,0 +1,82 @@ +From 67ed6a3cc79096910ce80aebd4998e856b73de1d Mon Sep 17 00:00:00 2001 +Message-ID: <67ed6a3cc79096910ce80aebd4998e856b73de1d.1774023916.git.phrdina@redhat.com> +From: Pavel Hrdina +Date: Wed, 18 Mar 2026 11:47:21 +0100 +Subject: [PATCH] conf: Refactor virHostdevIsPCIDevice + +From: Pavel Hrdina + +Future patches will need to check if the host device uses IOMMUFD or not +but we also need to keep a function that will check only if it is PCI device. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Peter Krempa +(cherry picked from commit d0afa0a842ce8a6dcb3f881d7dccdf5198f78fa7) + +Resolves: https://redhat.atlassian.net/browse/VOYAGER-309 +Signed-off-by: Pavel Hrdina +--- + src/conf/domain_conf.c | 34 +++++++++++++++++++++++++++++----- + 1 file changed, 29 insertions(+), 5 deletions(-) + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index 4e12ebf712..da90fd1446 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -32883,6 +32883,33 @@ virHostdevIsMdevDevice(const virDomainHostdevDef *hostdev) + } + + ++static bool ++virHostdevPCIDevHasIOMMUFD(const virDomainHostdevDef *hostdev) ++{ ++ return hostdev->source.subsys.u.pci.driver.name == VIR_DEVICE_HOSTDEV_PCI_DRIVER_NAME_VFIO && ++ hostdev->source.subsys.u.pci.driver.iommufd == VIR_TRISTATE_BOOL_YES; ++} ++ ++ ++static bool ++virHostdevIsPCIDeviceImpl(const virDomainHostdevDef *hostdev, ++ virTristateBool iommufd) ++{ ++ if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) ++ return false; ++ ++ if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) ++ return false; ++ ++ if (iommufd != VIR_TRISTATE_BOOL_ABSENT) { ++ bool hasIOMMUFD = iommufd == VIR_TRISTATE_BOOL_YES; ++ return hasIOMMUFD == virHostdevPCIDevHasIOMMUFD(hostdev); ++ } ++ ++ return true; ++} ++ ++ + /** + * virHostdevIsPCIDevice: + * @hostdev: host device to check +@@ -32892,8 +32919,7 @@ virHostdevIsMdevDevice(const virDomainHostdevDef *hostdev) + bool + virHostdevIsPCIDevice(const virDomainHostdevDef *hostdev) + { +- return hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && +- hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI; ++ return virHostdevIsPCIDeviceImpl(hostdev, VIR_TRISTATE_BOOL_ABSENT); + } + + +@@ -32906,9 +32932,7 @@ virHostdevIsPCIDevice(const virDomainHostdevDef *hostdev) + bool + virHostdevIsPCIDeviceWithIOMMUFD(const virDomainHostdevDef *hostdev) + { +- return virHostdevIsPCIDevice(hostdev) && +- hostdev->source.subsys.u.pci.driver.name == VIR_DEVICE_HOSTDEV_PCI_DRIVER_NAME_VFIO && +- hostdev->source.subsys.u.pci.driver.iommufd == VIR_TRISTATE_BOOL_YES; ++ return virHostdevIsPCIDeviceImpl(hostdev, VIR_TRISTATE_BOOL_YES); + } + + +-- +2.53.0 diff --git a/libvirt-hypervisor-Fix-virHostdevNeedsVFIO-detection.patch b/libvirt-hypervisor-Fix-virHostdevNeedsVFIO-detection.patch new file mode 100644 index 0000000..e777a22 --- /dev/null +++ b/libvirt-hypervisor-Fix-virHostdevNeedsVFIO-detection.patch @@ -0,0 +1,100 @@ +From c57b38c1bf7771489142198c7cf6fdc6ac1b15e1 Mon Sep 17 00:00:00 2001 +Message-ID: +From: Pavel Hrdina +Date: Wed, 18 Mar 2026 11:57:43 +0100 +Subject: [PATCH] hypervisor: Fix virHostdevNeedsVFIO detection + +From: Pavel Hrdina + +Function virHostdevNeedsVFIO is used only in QEMU to figure out if the +host device needs access to /dev/vfio/vfio, for PCI host devices that is +true only if libvirt is not using IOMMUFD. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Peter Krempa +(cherry picked from commit ffa8020d3665f7ff27c6b82e88d3a93674155c8d) + +Resolves: https://redhat.atlassian.net/browse/VOYAGER-309 +Signed-off-by: Pavel Hrdina +--- + src/conf/domain_conf.c | 13 +++++++++++++ + src/conf/domain_conf.h | 3 +++ + src/hypervisor/virhostdev.c | 9 ++++++++- + src/libvirt_private.syms | 1 + + 4 files changed, 25 insertions(+), 1 deletion(-) + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index da90fd1446..e8c4116fa0 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -32936,6 +32936,19 @@ virHostdevIsPCIDeviceWithIOMMUFD(const virDomainHostdevDef *hostdev) + } + + ++/** ++ * virHostdevIsPCIDeviceWithIOMMUFD: ++ * @hostdev: host device to check ++ * ++ * Returns true if @hostdev is a PCI device with IOMMUFD disabled, false otherwise. ++ */ ++bool ++virHostdevIsPCIDeviceWithoutIOMMUFD(const virDomainHostdevDef *hostdev) ++{ ++ return virHostdevIsPCIDeviceImpl(hostdev, VIR_TRISTATE_BOOL_NO); ++} ++ ++ + static void + virDomainObjGetMessagesIOErrorsSrc(virStorageSource *src, + const char *diskdst, +diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h +index 91b8976ea5..36e69ad6fd 100644 +--- a/src/conf/domain_conf.h ++++ b/src/conf/domain_conf.h +@@ -4726,6 +4726,9 @@ virHostdevIsPCIDevice(const virDomainHostdevDef *hostdev) + bool + virHostdevIsPCIDeviceWithIOMMUFD(const virDomainHostdevDef *hostdev) + ATTRIBUTE_NONNULL(1); ++bool ++virHostdevIsPCIDeviceWithoutIOMMUFD(const virDomainHostdevDef *hostdev) ++ ATTRIBUTE_NONNULL(1); + + void + virDomainObjGetMessagesIOErrorsChain(virStorageSource *src, +diff --git a/src/hypervisor/virhostdev.c b/src/hypervisor/virhostdev.c +index 7d7df4418d..43155ceb6c 100644 +--- a/src/hypervisor/virhostdev.c ++++ b/src/hypervisor/virhostdev.c +@@ -2510,10 +2510,17 @@ virHostdevUpdateActiveNVMeDevices(virHostdevManager *hostdev_mgr, + goto cleanup; + } + ++/** ++ * virHostdevNeedsVFIO: ++ * @hostdev: host device to check ++ * ++ * Returns true if using the @hostdev requires access to /dev/vfio/vfio, ++ * otherwise false. ++ */ + bool + virHostdevNeedsVFIO(const virDomainHostdevDef *hostdev) + { +- return virHostdevIsPCIDevice(hostdev) || ++ return virHostdevIsPCIDeviceWithoutIOMMUFD(hostdev) || + virHostdevIsMdevDevice(hostdev); + } + +diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms +index 386e757d81..ea1e2d8586 100644 +--- a/src/libvirt_private.syms ++++ b/src/libvirt_private.syms +@@ -814,6 +814,7 @@ virDomainQemuMonitorEventStateRegisterID; + virHostdevIsMdevDevice; + virHostdevIsPCIDevice; + virHostdevIsPCIDeviceWithIOMMUFD; ++virHostdevIsPCIDeviceWithoutIOMMUFD; + virHostdevIsSCSIDevice; + + +-- +2.53.0 diff --git a/libvirt-qemu-Expand-call-to-qemuDomainNeedsVFIO.patch b/libvirt-qemu-Expand-call-to-qemuDomainNeedsVFIO.patch new file mode 100644 index 0000000..b9f7758 --- /dev/null +++ b/libvirt-qemu-Expand-call-to-qemuDomainNeedsVFIO.patch @@ -0,0 +1,53 @@ +From 0ee217dd22cb6f93191e495e7b6a8127f5e9983f Mon Sep 17 00:00:00 2001 +Message-ID: <0ee217dd22cb6f93191e495e7b6a8127f5e9983f.1774023916.git.phrdina@redhat.com> +From: Pavel Hrdina +Date: Wed, 18 Mar 2026 12:52:05 +0100 +Subject: [PATCH] qemu: Expand call to qemuDomainNeedsVFIO + +From: Pavel Hrdina + +The function qemuDomainNeedsVFIO() was originally used by other parts +of qemu code to figure out if the VM needs /dev/vfio/vfio. + +Later it was also used by code calculating locked memory limit for all +architectures, and after that change again and used only for PPC64. + +Now it needs to be changed again due to IOMMUFD support, the +/dev/vfio/vfio device is used by QEMU only if IOMMUFD is not used +but for accounting we still need consider all PCI host devices +because if IOMMUFD is used it still requires increasing locked +memory limit. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Peter Krempa +(cherry picked from commit c89b2bf1a80e3261bd18cdb352be1ffce9f4639e) + +Resolves: https://redhat.atlassian.net/browse/VOYAGER-309 +Signed-off-by: Pavel Hrdina +--- + src/qemu/qemu_domain.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c +index 5c9f4831fd..57f18a02b6 100644 +--- a/src/qemu/qemu_domain.c ++++ b/src/qemu/qemu_domain.c +@@ -8259,8 +8259,14 @@ getPPC64MemLockLimitBytes(virDomainDef *def) + passthroughLimit = maxMemory + + 128 * (1ULL<<30) / 512 * nPCIHostBridges + + 8192; +- } else if (qemuDomainNeedsVFIO(def) || virDomainDefHasVDPANet(def)) { +- /* For regular (non-NVLink2 present) VFIO passthrough, the value ++ } else if (virDomainDefHasPCIHostdev(def) || ++ virDomainDefHasMdevHostdev(def) || ++ virDomainDefHasNVMeDisk(def) || ++ virDomainDefHasVDPANet(def)) { ++ /* Not using qemuDomainNeedsVFIO() as that doesn't take PCI host ++ * devices with IOMMFD into account. ++ * ++ * For regular (non-NVLink2 present) VFIO passthrough, the value + * of passthroughLimit is: + * + * passthroughLimit := max( 2 GiB * #PHBs, (c) +-- +2.53.0 diff --git a/libvirt-qemu-Fix-IOMMUFD-and-VFIO-security-labels.patch b/libvirt-qemu-Fix-IOMMUFD-and-VFIO-security-labels.patch new file mode 100644 index 0000000..d83252a --- /dev/null +++ b/libvirt-qemu-Fix-IOMMUFD-and-VFIO-security-labels.patch @@ -0,0 +1,247 @@ +From 0feb51944a7355e5c8502536df4c63e91f474d43 Mon Sep 17 00:00:00 2001 +Message-ID: <0feb51944a7355e5c8502536df4c63e91f474d43.1774023916.git.phrdina@redhat.com> +From: Pavel Hrdina +Date: Fri, 27 Feb 2026 17:55:34 +0100 +Subject: [PATCH] qemu: Fix IOMMUFD and VFIO security labels +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Pavel Hrdina + +When IOMMUFD support was introduced it incorrectly tried to label +`/dev/iommu` and `/dev/vfio/devices/vfioX` but they are not added to +QEMU namespace because libvirt opens FDs and passes these FDs to QEMU. + +We need to label these FDs instead. + +Fixes: 7d2f91f9cb572ab95d0916bdd1a46dd198874529 +Signed-off-by: Pavel Hrdina +Reviewed-by: Ján Tomko +(cherry picked from commit 03f2672ab4eff8ee01410c9acba6288bfb4fa231) + +Resolves: https://redhat.atlassian.net/browse/VOYAGER-309 +Signed-off-by: Pavel Hrdina +--- + src/qemu/qemu_hotplug.c | 2 +- + src/qemu/qemu_process.c | 16 ++++++++++++---- + src/qemu/qemu_process.h | 3 ++- + src/security/security_apparmor.c | 12 ------------ + src/security/security_dac.c | 27 --------------------------- + src/security/security_selinux.c | 23 ----------------------- + 6 files changed, 15 insertions(+), 68 deletions(-) + +diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c +index 845f42bf20..994cc749f6 100644 +--- a/src/qemu/qemu_hotplug.c ++++ b/src/qemu/qemu_hotplug.c +@@ -1621,7 +1621,7 @@ qemuDomainAttachHostPCIDevice(virQEMUDriver *driver, + } + + if (virHostdevIsPCIDeviceWithIOMMUFD(hostdev)) { +- if (qemuProcessOpenVfioDeviceFd(hostdev) < 0) ++ if (qemuProcessOpenVfioDeviceFd(vm, hostdev) < 0) + goto error; + + if (!priv->iommufdState) { +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 1aff3a277b..7fb992ce5a 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -7685,13 +7685,16 @@ int + qemuProcessOpenIommuFd(virDomainObj *vm) + { + qemuDomainObjPrivate *priv = vm->privateData; +- int iommufd; ++ VIR_AUTOCLOSE iommufd = -1; + + VIR_DEBUG("Opening IOMMU FD for domain %s", vm->def->name); + + if ((iommufd = virIOMMUFDOpenDevice()) < 0) + return -1; + ++ if (qemuSecuritySetImageFDLabel(priv->driver->securityManager, vm->def, iommufd) < 0) ++ return -1; ++ + priv->iommufd = qemuFDPassDirectNew("iommufd", &iommufd); + + return 0; +@@ -7706,16 +7709,21 @@ qemuProcessOpenIommuFd(virDomainObj *vm) + * Returns: 0 on success, -1 on failure + */ + int +-qemuProcessOpenVfioDeviceFd(virDomainHostdevDef *hostdev) ++qemuProcessOpenVfioDeviceFd(virDomainObj *vm, ++ virDomainHostdevDef *hostdev) + { ++ qemuDomainObjPrivate *priv = vm->privateData; + qemuDomainHostdevPrivate *hostdevPriv = QEMU_DOMAIN_HOSTDEV_PRIVATE(hostdev); + virDomainHostdevSubsysPCI *pci = &hostdev->source.subsys.u.pci; + g_autofree char *name = g_strdup_printf("hostdev-%s-fd", hostdev->info->alias); +- int vfioDeviceFd; ++ VIR_AUTOCLOSE vfioDeviceFd = -1; + + if ((vfioDeviceFd = virPCIDeviceOpenVfioFd(&pci->addr)) < 0) + return -1; + ++ if (qemuSecuritySetImageFDLabel(priv->driver->securityManager, vm->def, vfioDeviceFd) < 0) ++ return -1; ++ + hostdevPriv->vfioDeviceFd = qemuFDPassDirectNew(name, &vfioDeviceFd); + + return 0; +@@ -7733,7 +7741,7 @@ qemuProcessPrepareHostHostdev(virDomainObj *vm) + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: + if (virHostdevIsPCIDeviceWithIOMMUFD(hostdev)) { + /* Open VFIO device FD */ +- if (qemuProcessOpenVfioDeviceFd(hostdev) < 0) ++ if (qemuProcessOpenVfioDeviceFd(vm, hostdev) < 0) + return -1; + } + break; +diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h +index 1023b7cb25..dc16622ed9 100644 +--- a/src/qemu/qemu_process.h ++++ b/src/qemu/qemu_process.h +@@ -136,7 +136,8 @@ int qemuProcessPrepareHostBackendChardevHotplug(virDomainObj *vm, + + int qemuProcessOpenIommuFd(virDomainObj *vm); + +-int qemuProcessOpenVfioDeviceFd(virDomainHostdevDef *hostdev); ++int qemuProcessOpenVfioDeviceFd(virDomainObj *vm, ++ virDomainHostdevDef *hostdev); + + int qemuProcessPrepareHost(virQEMUDriver *driver, + virDomainObj *vm, +diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c +index 1c3496893c..40f13ec1a5 100644 +--- a/src/security/security_apparmor.c ++++ b/src/security/security_apparmor.c +@@ -45,7 +45,6 @@ + #include "virstring.h" + #include "virscsi.h" + #include "virmdev.h" +-#include "viriommufd.h" + + #define VIR_FROM_THIS VIR_FROM_SECURITY + +@@ -856,17 +855,6 @@ AppArmorSetSecurityHostdevLabel(virSecurityManager *mgr, + + if (AppArmorSetSecurityPCILabel(pci, vfioGroupDev, ptr) < 0) + return -1; +- } else { +- g_autofree char *vfiofdDev = NULL; +- +- if (virPCIDeviceGetVfioPath(pci, &vfiofdDev) < 0) +- return -1; +- +- if (AppArmorSetSecurityPCILabel(pci, vfiofdDev, ptr) < 0) +- return -1; +- +- if (AppArmorSetSecurityPCILabel(pci, VIR_IOMMU_DEV_PATH, ptr) < 0) +- return -1; + } + } else { + if (virPCIDeviceFileIterate(pci, AppArmorSetSecurityPCILabel, ptr) < 0) +diff --git a/src/security/security_dac.c b/src/security/security_dac.c +index 2a4c7f6a3c..d8cf117fc4 100644 +--- a/src/security/security_dac.c ++++ b/src/security/security_dac.c +@@ -41,7 +41,6 @@ + #include "virscsivhost.h" + #include "virstring.h" + #include "virutil.h" +-#include "viriommufd.h" + + #define VIR_FROM_THIS VIR_FROM_SECURITY + +@@ -1295,17 +1294,6 @@ virSecurityDACSetHostdevLabel(virSecurityManager *mgr, + &cbdata) < 0) { + return -1; + } +- } else { +- g_autofree char *vfiofdDev = NULL; +- +- if (virPCIDeviceGetVfioPath(pci, &vfiofdDev) < 0) +- return -1; +- +- if (virSecurityDACSetHostdevLabelHelper(vfiofdDev, false, &cbdata) < 0) +- return -1; +- +- if (virSecurityDACSetHostdevLabelHelper(VIR_IOMMU_DEV_PATH, false, &cbdata) < 0) +- return -1; + } + } else { + if (virPCIDeviceFileIterate(pci, +@@ -1476,21 +1464,6 @@ virSecurityDACRestoreHostdevLabel(virSecurityManager *mgr, + vfioGroupDev, false) < 0) { + return -1; + } +- } else { +- g_autofree char *vfiofdDev = NULL; +- +- if (virPCIDeviceGetVfioPath(pci, &vfiofdDev) < 0) +- return -1; +- +- if (virSecurityDACRestoreFileLabelInternal(mgr, NULL, +- vfiofdDev, false) < 0) { +- return -1; +- } +- +- if (virSecurityDACRestoreFileLabelInternal(mgr, NULL, +- VIR_IOMMU_DEV_PATH, false) < 0) { +- return -1; +- } + } + } else { + if (virPCIDeviceFileIterate(pci, virSecurityDACRestorePCILabel, mgr) < 0) +diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c +index 96ca59a7a4..0fa50630f7 100644 +--- a/src/security/security_selinux.c ++++ b/src/security/security_selinux.c +@@ -41,7 +41,6 @@ + #include "virconf.h" + #include "virtpm.h" + #include "virstring.h" +-#include "viriommufd.h" + + #define VIR_FROM_THIS VIR_FROM_SECURITY + +@@ -2267,17 +2266,6 @@ virSecuritySELinuxSetHostdevSubsysLabel(virSecurityManager *mgr, + &data) < 0) { + return -1; + } +- } else { +- g_autofree char *vfiofdDev = NULL; +- +- if (virPCIDeviceGetVfioPath(pci, &vfiofdDev) < 0) +- return -1; +- +- if (virSecuritySELinuxSetHostdevLabelHelper(vfiofdDev, false, &data) < 0) +- return -1; +- +- if (virSecuritySELinuxSetHostdevLabelHelper(VIR_IOMMU_DEV_PATH, false, &data) < 0) +- return -1; + } + } else { + if (virPCIDeviceFileIterate(pci, virSecuritySELinuxSetPCILabel, &data) < 0) +@@ -2519,17 +2507,6 @@ virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManager *mgr, + + if (virSecuritySELinuxRestoreFileLabel(mgr, vfioGroupDev, false, false) < 0) + return -1; +- } else { +- g_autofree char *vfiofdDev = NULL; +- +- if (virPCIDeviceGetVfioPath(pci, &vfiofdDev) < 0) +- return -1; +- +- if (virSecuritySELinuxRestoreFileLabel(mgr, vfiofdDev, false, false) < 0) +- return -1; +- +- if (virSecuritySELinuxRestoreFileLabel(mgr, VIR_IOMMU_DEV_PATH, false, false) < 0) +- return -1; + } + } else { + if (virPCIDeviceFileIterate(pci, virSecuritySELinuxRestorePCILabel, mgr) < 0) +-- +2.53.0 diff --git a/libvirt-qemu-Implement-iommufd-fdgroup.patch b/libvirt-qemu-Implement-iommufd-fdgroup.patch new file mode 100644 index 0000000..ad39204 --- /dev/null +++ b/libvirt-qemu-Implement-iommufd-fdgroup.patch @@ -0,0 +1,129 @@ +From 5e9b5534fdf50bcfc19b0fd12d44db5c8f635675 Mon Sep 17 00:00:00 2001 +Message-ID: <5e9b5534fdf50bcfc19b0fd12d44db5c8f635675.1774023916.git.phrdina@redhat.com> +From: Pavel Hrdina +Date: Mon, 16 Mar 2026 15:29:32 +0100 +Subject: [PATCH] qemu: Implement iommufd fdgroup + +From: Pavel Hrdina + +When fdgroup is used for iommufd we will start QEMU with -object iommufd +even if the VM has no host device. When virDomainFDAssociate() is used +the FD libvirt is holding is closed with connection. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Peter Krempa +(cherry picked from commit 0a83b28795f0c18592f9d842927528f0676cc56d) + +Resolves: https://redhat.atlassian.net/browse/VOYAGER-309 +Signed-off-by: Pavel Hrdina +--- + src/qemu/qemu_command.c | 4 +++- + src/qemu/qemu_hotplug.c | 4 ++-- + src/qemu/qemu_process.c | 47 ++++++++++++++++++++++++++++++++++++++--- + 3 files changed, 49 insertions(+), 6 deletions(-) + +diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c +index 30bed14b0c..a76f504e6f 100644 +--- a/src/qemu/qemu_command.c ++++ b/src/qemu/qemu_command.c +@@ -5361,8 +5361,10 @@ qemuBuildIOMMUFDCommandLine(virCommand *cmd, + qemuDomainObjPrivate *priv = vm->privateData; + g_autoptr(virJSONValue) props = NULL; + +- if (!virDomainDefHasPCIHostdevWithIOMMUFD(def)) ++ if (!virDomainDefHasPCIHostdevWithIOMMUFD(def) && ++ !def->iommufd_fdgroup) { + return 0; ++ } + + qemuFDPassDirectTransferCommand(priv->iommufd, cmd); + +diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c +index 25fe699bb3..8944062aa4 100644 +--- a/src/qemu/qemu_hotplug.c ++++ b/src/qemu/qemu_hotplug.c +@@ -1624,7 +1624,7 @@ qemuDomainAttachHostPCIDevice(virQEMUDriver *driver, + if (qemuProcessOpenVfioDeviceFd(vm, hostdev) < 0) + goto error; + +- if (!priv->iommufdState) { ++ if (!priv->iommufdState && !vm->def->iommufd_fdgroup) { + if (qemuProcessOpenIommuFd(vm) < 0) + goto error; + +@@ -5031,7 +5031,7 @@ qemuDomainRemoveHostDevice(virQEMUDriver *driver, + } + } + +- if (priv->iommufdState && ++ if (priv->iommufdState && !vm->def->iommufd_fdgroup && + !virDomainDefHasPCIHostdevWithIOMMUFD(vm->def)) { + qemuDomainObjEnterMonitor(vm); + ignore_value(qemuMonitorDelObject(priv->mon, "iommufd0", false)); +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 5fe4a33944..2b1d47ed86 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -7700,6 +7700,44 @@ qemuProcessOpenIommuFd(virDomainObj *vm) + return 0; + } + ++/** ++ * qemuProcessGetPassedIommuFd: ++ * @vm: domain object ++ * ++ * Find passed FD via virDomainFDAssociate() API for the VM. ++ * ++ * Returns: 0 on success, -1 on failure ++ */ ++static int ++qemuProcessGetPassedIommuFd(virDomainObj *vm) ++{ ++ qemuDomainObjPrivate *priv = vm->privateData; ++ virDomainFDTuple *fdt = virHashLookup(priv->fds, vm->def->iommufd_fdgroup); ++ VIR_AUTOCLOSE iommufd = -1; ++ ++ if (!fdt) { ++ virReportError(VIR_ERR_INVALID_ARG, ++ _("file descriptor group '%1$s' was not associated with the domain"), ++ vm->def->iommufd_fdgroup); ++ return -1; ++ } ++ ++ if (fdt->nfds != 1) { ++ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", ++ _("Only one file descriptor needs to be associated with iommufd")); ++ return -1; ++ } ++ ++ iommufd = dup(fdt->fds[0]); ++ ++ if (qemuSecuritySetImageFDLabel(priv->driver->securityManager, vm->def, iommufd) < 0) ++ return -1; ++ ++ priv->iommufd = qemuFDPassDirectNew("iommufd", &iommufd); ++ ++ return 0; ++} ++ + /** + * qemuProcessOpenVfioDeviceFd: + * @hostdev: host device definition +@@ -7755,9 +7793,12 @@ qemuProcessPrepareHostHostdev(virDomainObj *vm) + } + + /* Open IOMMU FD */ +- if (virDomainDefHasPCIHostdevWithIOMMUFD(vm->def) && +- qemuProcessOpenIommuFd(vm) < 0) { +- return -1; ++ if (vm->def->iommufd_fdgroup) { ++ if (qemuProcessGetPassedIommuFd(vm) < 0) ++ return -1; ++ } else if (virDomainDefHasPCIHostdevWithIOMMUFD(vm->def)) { ++ if (qemuProcessOpenIommuFd(vm) < 0) ++ return -1; + } + + return 0; +-- +2.53.0 diff --git a/libvirt-qemu-Implement-iommufd.patch b/libvirt-qemu-Implement-iommufd.patch new file mode 100644 index 0000000..3ae0852 --- /dev/null +++ b/libvirt-qemu-Implement-iommufd.patch @@ -0,0 +1,121 @@ +From aa8c64443e0f8dfdd0d304372e68a2b50543f1bc Mon Sep 17 00:00:00 2001 +Message-ID: +From: Pavel Hrdina +Date: Wed, 18 Mar 2026 17:59:01 +0100 +Subject: [PATCH] qemu: Implement iommufd + +From: Pavel Hrdina + +Ideally this should be done in qemuDomainHostdevDefPostParse but that +would require a lot of refactoring mainly due to how interface backed by +hostdev works. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Peter Krempa +(cherry picked from commit fc516031ed865f78d590068424ada19a941046ba) + +Resolves: https://redhat.atlassian.net/browse/VOYAGER-309 +Signed-off-by: Pavel Hrdina +--- + src/qemu/qemu_domain.c | 12 +++++++++--- + src/qemu/qemu_domain.h | 3 ++- + src/qemu/qemu_hotplug.c | 2 +- + src/qemu/qemu_process.c | 4 ++-- + 4 files changed, 14 insertions(+), 7 deletions(-) + +diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c +index a61939aa15..495cbd4f7d 100644 +--- a/src/qemu/qemu_domain.c ++++ b/src/qemu/qemu_domain.c +@@ -10120,10 +10120,12 @@ qemuDomainPrepareHostdevSCSI(virDomainHostdevDef *hostdev, + + + static int +-qemuDomainPrepareHostdevPCI(virDomainHostdevDef *hostdev, ++qemuDomainPrepareHostdevPCI(const virDomainDef *def, ++ virDomainHostdevDef *hostdev, + virQEMUCaps *qemuCaps) + { + virDeviceHostdevPCIDriverName *driverName = &hostdev->source.subsys.u.pci.driver.name; ++ virDomainHostdevSubsysPCI *pcisrc = &hostdev->source.subsys.u.pci; + + /* assign defaults for hostdev passthrough */ + switch (*driverName) { +@@ -10160,12 +10162,16 @@ qemuDomainPrepareHostdevPCI(virDomainHostdevDef *hostdev, + return -1; + } + ++ if (pcisrc->driver.iommufd == VIR_TRISTATE_BOOL_ABSENT) ++ pcisrc->driver.iommufd = def->iommufd; ++ + return 0; + } + + + int +-qemuDomainPrepareHostdev(virDomainHostdevDef *hostdev, ++qemuDomainPrepareHostdev(const virDomainDef *def, ++ virDomainHostdevDef *hostdev, + qemuDomainObjPrivate *priv) + { + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) +@@ -10175,7 +10181,7 @@ qemuDomainPrepareHostdev(virDomainHostdevDef *hostdev, + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: + return qemuDomainPrepareHostdevSCSI(hostdev, priv); + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: +- return qemuDomainPrepareHostdevPCI(hostdev, priv->qemuCaps); ++ return qemuDomainPrepareHostdevPCI(def, hostdev, priv->qemuCaps); + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST: + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV: +diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h +index 62c5252b9f..8cd221062c 100644 +--- a/src/qemu/qemu_domain.h ++++ b/src/qemu/qemu_domain.h +@@ -1048,7 +1048,8 @@ qemuDomainDiskCachemodeFlags(virDomainDiskCache cachemode, + bool *noflush); + + int +-qemuDomainPrepareHostdev(virDomainHostdevDef *hostdev, ++qemuDomainPrepareHostdev(const virDomainDef *def, ++ virDomainHostdevDef *hostdev, + qemuDomainObjPrivate *priv); + + char * qemuDomainGetManagedPRSocketPath(qemuDomainObjPrivate *priv); +diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c +index 994cc749f6..25fe699bb3 100644 +--- a/src/qemu/qemu_hotplug.c ++++ b/src/qemu/qemu_hotplug.c +@@ -2900,7 +2900,7 @@ qemuDomainAttachHostDevice(virQEMUDriver *driver, + return -1; + } + +- if (qemuDomainPrepareHostdev(hostdev, vm->privateData) < 0) ++ if (qemuDomainPrepareHostdev(vm->def, hostdev, vm->privateData) < 0) + return -1; + + switch (hostdev->source.subsys.type) { +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 6a9625e283..5fe4a33944 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -6050,7 +6050,7 @@ qemuProcessPrepareDomainNetwork(virDomainObj *vm) + /* For hostdev present in qemuProcessPrepareDomain() phase this was + * done already, but this code runs after that, so we have to call + * it ourselves. */ +- if (qemuDomainPrepareHostdev(hostdev, priv) < 0) ++ if (qemuDomainPrepareHostdev(def, hostdev, priv) < 0) + return -1; + + virDomainHostdevInsert(def, hostdev); +@@ -6838,7 +6838,7 @@ qemuProcessPrepareDomainHostdevs(virDomainObj *vm, + for (i = 0; i < vm->def->nhostdevs; i++) { + virDomainHostdevDef *hostdev = vm->def->hostdevs[i]; + +- if (qemuDomainPrepareHostdev(hostdev, priv) < 0) ++ if (qemuDomainPrepareHostdev(vm->def, hostdev, priv) < 0) + return -1; + } + +-- +2.53.0 diff --git a/libvirt-qemu-Update-qemuDomainNeedsVFIO-to-ignore-PCI-hostdev-with-IOMMUFD.patch b/libvirt-qemu-Update-qemuDomainNeedsVFIO-to-ignore-PCI-hostdev-with-IOMMUFD.patch new file mode 100644 index 0000000..b081ba7 --- /dev/null +++ b/libvirt-qemu-Update-qemuDomainNeedsVFIO-to-ignore-PCI-hostdev-with-IOMMUFD.patch @@ -0,0 +1,109 @@ +From ba63f0bdc6a08aab9ff9217c6ad665b6a27ce738 Mon Sep 17 00:00:00 2001 +Message-ID: +From: Pavel Hrdina +Date: Wed, 18 Mar 2026 13:10:37 +0100 +Subject: [PATCH] qemu: Update qemuDomainNeedsVFIO to ignore PCI hostdev with + IOMMUFD + +From: Pavel Hrdina + +This function is used to figure out if VM needs access to /dev/vfio/vfio. +In case of PCI host devices that is true only if IOMMUFD is not enabled. + +This fixes error when hotplugging PCI host device with IOMMUFD disabled +to a VM that already has PCI host device with IOMMIFD enabled: + + Could not open '/dev/vfio/vfio': No such file or directory + +The function is used in this case to check if /dev/vfio/vfio was already +made available to QEMU or not. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Peter Krempa +(cherry picked from commit d1fb5cf127d7681fa6c27e5b163ef410132aea49) + +Resolves: https://redhat.atlassian.net/browse/VOYAGER-309 +Signed-off-by: Pavel Hrdina +--- + src/conf/domain_conf.c | 14 ++++++++++++++ + src/conf/domain_conf.h | 3 +++ + src/libvirt_private.syms | 1 + + src/qemu/qemu_domain.c | 9 ++++++++- + 4 files changed, 26 insertions(+), 1 deletion(-) + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index e8c4116fa0..6e49507e83 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -32621,6 +32621,20 @@ virDomainDefHasPCIHostdevWithIOMMUFD(const virDomainDef *def) + } + + ++bool ++virDomainDefHasPCIHostdevWithoutIOMMUFD(const virDomainDef *def) ++{ ++ size_t i; ++ ++ for (i = 0; i < def->nhostdevs; i++) { ++ if (virHostdevIsPCIDeviceWithoutIOMMUFD(def->hostdevs[i])) ++ return true; ++ } ++ ++ return false; ++} ++ ++ + bool + virDomainDefHasMdevHostdev(const virDomainDef *def) + { +diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h +index 36e69ad6fd..de803d0dcc 100644 +--- a/src/conf/domain_conf.h ++++ b/src/conf/domain_conf.h +@@ -4665,6 +4665,9 @@ virDomainDefHasPCIHostdev(const virDomainDef *def); + bool + virDomainDefHasPCIHostdevWithIOMMUFD(const virDomainDef *def); + ++bool ++virDomainDefHasPCIHostdevWithoutIOMMUFD(const virDomainDef *def); ++ + bool + virDomainDefHasMdevHostdev(const virDomainDef *def); + +diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms +index ea1e2d8586..d2563e587a 100644 +--- a/src/libvirt_private.syms ++++ b/src/libvirt_private.syms +@@ -349,6 +349,7 @@ virDomainDefHasOldStyleROUEFI; + virDomainDefHasOldStyleUEFI; + virDomainDefHasPCIHostdev; + virDomainDefHasPCIHostdevWithIOMMUFD; ++virDomainDefHasPCIHostdevWithoutIOMMUFD; + virDomainDefHasTimer; + virDomainDefHasUSB; + virDomainDefHasVcpusOffline; +diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c +index 57f18a02b6..a61939aa15 100644 +--- a/src/qemu/qemu_domain.c ++++ b/src/qemu/qemu_domain.c +@@ -9284,10 +9284,17 @@ qemuDomainSupportsVideoVga(const virDomainVideoDef *video, + } + + ++/** ++ * qemuDomainNeedsVFIO: ++ * @def: domain definition to check ++ * ++ * Check the domain definition to figure out if QEMU needs access ++ * to /dev/vfio/vfio. It's not required if IOMMUFD is used. ++ */ + bool + qemuDomainNeedsVFIO(const virDomainDef *def) + { +- return virDomainDefHasPCIHostdev(def) || ++ return virDomainDefHasPCIHostdevWithoutIOMMUFD(def) || + virDomainDefHasMdevHostdev(def) || + virDomainDefHasNVMeDisk(def); + } +-- +2.53.0 diff --git a/libvirt-security-Cleanup-hostdev-label-error-logic.patch b/libvirt-security-Cleanup-hostdev-label-error-logic.patch new file mode 100644 index 0000000..ba4ddde --- /dev/null +++ b/libvirt-security-Cleanup-hostdev-label-error-logic.patch @@ -0,0 +1,613 @@ +From 0c3734057bd0fa76b475f9ad38d836c8a2b5e454 Mon Sep 17 00:00:00 2001 +Message-ID: <0c3734057bd0fa76b475f9ad38d836c8a2b5e454.1774023916.git.phrdina@redhat.com> +From: Pavel Hrdina +Date: Mon, 2 Mar 2026 12:46:00 +0100 +Subject: [PATCH] security: Cleanup hostdev label error logic +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Pavel Hrdina + +Current code used mix of return, goto, break and setting ret variable. +Simplify the logic to just return -1 on error. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Ján Tomko +(cherry picked from commit b7483e6558acbb0d80e2ff2c3648ca63cb7f41f9) + +Resolves: https://redhat.atlassian.net/browse/VOYAGER-309 +Signed-off-by: Pavel Hrdina +--- + src/security/security_apparmor.c | 56 +++++++++-------- + src/security/security_dac.c | 103 ++++++++++++++++++------------- + src/security/security_selinux.c | 87 ++++++++++++++------------ + 3 files changed, 139 insertions(+), 107 deletions(-) + +diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c +index 74c5b10063..1c3496893c 100644 +--- a/src/security/security_apparmor.c ++++ b/src/security/security_apparmor.c +@@ -800,7 +800,6 @@ AppArmorSetSecurityHostdevLabel(virSecurityManager *mgr, + const char *vroot) + { + g_autofree struct SDPDOP *ptr = NULL; +- int ret = -1; + virSecurityLabelDef *secdef = + virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME); + virDomainHostdevSubsysUSB *usbsrc = &dev->source.subsys.u.usb; +@@ -834,9 +833,10 @@ AppArmorSetSecurityHostdevLabel(virSecurityManager *mgr, + g_autoptr(virUSBDevice) usb = + virUSBDeviceNew(usbsrc->bus, usbsrc->device, vroot); + if (!usb) +- goto done; ++ return -1; + +- ret = virUSBDeviceFileIterate(usb, AppArmorSetSecurityUSBLabel, ptr); ++ if (virUSBDeviceFileIterate(usb, AppArmorSetSecurityUSBLabel, ptr) < 0) ++ return -1; + break; + } + +@@ -845,30 +845,32 @@ AppArmorSetSecurityHostdevLabel(virSecurityManager *mgr, + virPCIDeviceNew(&pcisrc->addr); + + if (!pci) +- goto done; ++ return -1; + + if (pcisrc->driver.name == VIR_DEVICE_HOSTDEV_PCI_DRIVER_NAME_VFIO) { + if (dev->source.subsys.u.pci.driver.iommufd != VIR_TRISTATE_BOOL_YES) { + g_autofree char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci); + +- if (!vfioGroupDev) { +- goto done; +- } +- ret = AppArmorSetSecurityPCILabel(pci, vfioGroupDev, ptr); ++ if (!vfioGroupDev) ++ return -1; ++ ++ if (AppArmorSetSecurityPCILabel(pci, vfioGroupDev, ptr) < 0) ++ return -1; + } else { + g_autofree char *vfiofdDev = NULL; + + if (virPCIDeviceGetVfioPath(pci, &vfiofdDev) < 0) +- goto done; ++ return -1; + +- ret = AppArmorSetSecurityPCILabel(pci, vfiofdDev, ptr); +- if (ret < 0) +- goto done; ++ if (AppArmorSetSecurityPCILabel(pci, vfiofdDev, ptr) < 0) ++ return -1; + +- ret = AppArmorSetSecurityPCILabel(pci, VIR_IOMMU_DEV_PATH, ptr); ++ if (AppArmorSetSecurityPCILabel(pci, VIR_IOMMU_DEV_PATH, ptr) < 0) ++ return -1; + } + } else { +- ret = virPCIDeviceFileIterate(pci, AppArmorSetSecurityPCILabel, ptr); ++ if (virPCIDeviceFileIterate(pci, AppArmorSetSecurityPCILabel, ptr) < 0) ++ return -1; + } + break; + } +@@ -881,10 +883,11 @@ AppArmorSetSecurityHostdevLabel(virSecurityManager *mgr, + scsihostsrc->target, scsihostsrc->unit, + dev->readonly, dev->shareable); + +- if (!scsi) +- goto done; ++ if (!scsi) ++ return -1; + +- ret = virSCSIDeviceFileIterate(scsi, AppArmorSetSecuritySCSILabel, ptr); ++ if (virSCSIDeviceFileIterate(scsi, AppArmorSetSecuritySCSILabel, ptr) < 0) ++ return -1; + break; + } + +@@ -892,11 +895,13 @@ AppArmorSetSecurityHostdevLabel(virSecurityManager *mgr, + g_autoptr(virSCSIVHostDevice) host = virSCSIVHostDeviceNew(hostsrc->wwpn); + + if (!host) +- goto done; ++ return -1; + +- ret = virSCSIVHostDeviceFileIterate(host, +- AppArmorSetSecurityHostLabel, +- ptr); ++ if (virSCSIVHostDeviceFileIterate(host, ++ AppArmorSetSecurityHostLabel, ++ ptr) < 0) { ++ return -1; ++ } + break; + } + +@@ -904,19 +909,18 @@ AppArmorSetSecurityHostdevLabel(virSecurityManager *mgr, + g_autofree char *vfiodev = NULL; + + if (!(vfiodev = virMediatedDeviceGetIOMMUGroupDev(mdevsrc->uuidstr))) +- goto done; ++ return -1; + +- ret = AppArmorSetSecurityHostdevLabelHelper(vfiodev, ptr); ++ if (AppArmorSetSecurityHostdevLabelHelper(vfiodev, ptr) < 0) ++ return -1; + break; + } + + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: +- ret = 0; + break; + } + +- done: +- return ret; ++ return 0; + } + + +diff --git a/src/security/security_dac.c b/src/security/security_dac.c +index 704c8dbfec..2a4c7f6a3c 100644 +--- a/src/security/security_dac.c ++++ b/src/security/security_dac.c +@@ -1234,7 +1234,6 @@ virSecurityDACSetHostdevLabel(virSecurityManager *mgr, + virDomainHostdevSubsysSCSI *scsisrc = &dev->source.subsys.u.scsi; + virDomainHostdevSubsysSCSIVHost *hostsrc = &dev->source.subsys.u.scsi_host; + virDomainHostdevSubsysMediatedDev *mdevsrc = &dev->source.subsys.u.mdev; +- int ret = -1; + + if (!priv->dynamicOwnership) + return 0; +@@ -1265,9 +1264,11 @@ virSecurityDACSetHostdevLabel(virSecurityManager *mgr, + if (!(usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, vroot))) + return -1; + +- ret = virUSBDeviceFileIterate(usb, +- virSecurityDACSetUSBLabel, +- &cbdata); ++ if (virUSBDeviceFileIterate(usb, ++ virSecurityDACSetUSBLabel, ++ &cbdata) < 0) { ++ return -1; ++ } + break; + } + +@@ -1275,7 +1276,7 @@ virSecurityDACSetHostdevLabel(virSecurityManager *mgr, + g_autoptr(virPCIDevice) pci = NULL; + + if (!virPCIDeviceExists(&pcisrc->addr)) +- break; ++ return -1; + + pci = virPCIDeviceNew(&pcisrc->addr); + +@@ -1289,25 +1290,29 @@ virSecurityDACSetHostdevLabel(virSecurityManager *mgr, + if (!vfioGroupDev) + return -1; + +- ret = virSecurityDACSetHostdevLabelHelper(vfioGroupDev, +- false, +- &cbdata); ++ if (virSecurityDACSetHostdevLabelHelper(vfioGroupDev, ++ false, ++ &cbdata) < 0) { ++ return -1; ++ } + } else { + g_autofree char *vfiofdDev = NULL; + + if (virPCIDeviceGetVfioPath(pci, &vfiofdDev) < 0) + return -1; + +- ret = virSecurityDACSetHostdevLabelHelper(vfiofdDev, false, &cbdata); +- if (ret < 0) +- break; ++ if (virSecurityDACSetHostdevLabelHelper(vfiofdDev, false, &cbdata) < 0) ++ return -1; + +- ret = virSecurityDACSetHostdevLabelHelper(VIR_IOMMU_DEV_PATH, false, &cbdata); ++ if (virSecurityDACSetHostdevLabelHelper(VIR_IOMMU_DEV_PATH, false, &cbdata) < 0) ++ return -1; + } + } else { +- ret = virPCIDeviceFileIterate(pci, +- virSecurityDACSetPCILabel, +- &cbdata); ++ if (virPCIDeviceFileIterate(pci, ++ virSecurityDACSetPCILabel, ++ &cbdata) < 0) { ++ return -1; ++ } + } + break; + } +@@ -1323,9 +1328,11 @@ virSecurityDACSetHostdevLabel(virSecurityManager *mgr, + if (!scsi) + return -1; + +- ret = virSCSIDeviceFileIterate(scsi, +- virSecurityDACSetSCSILabel, +- &cbdata); ++ if (virSCSIDeviceFileIterate(scsi, ++ virSecurityDACSetSCSILabel, ++ &cbdata) < 0) { ++ return -1; ++ } + break; + } + +@@ -1335,9 +1342,11 @@ virSecurityDACSetHostdevLabel(virSecurityManager *mgr, + if (!host) + return -1; + +- ret = virSCSIVHostDeviceFileIterate(host, +- virSecurityDACSetHostLabel, +- &cbdata); ++ if (virSCSIVHostDeviceFileIterate(host, ++ virSecurityDACSetHostLabel, ++ &cbdata) < 0) { ++ return -1; ++ } + break; + } + +@@ -1347,16 +1356,16 @@ virSecurityDACSetHostdevLabel(virSecurityManager *mgr, + if (!(vfiodev = virMediatedDeviceGetIOMMUGroupDev(mdevsrc->uuidstr))) + return -1; + +- ret = virSecurityDACSetHostdevLabelHelper(vfiodev, false, &cbdata); ++ if (virSecurityDACSetHostdevLabelHelper(vfiodev, false, &cbdata) < 0) ++ return -1; + break; + } + + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: +- ret = 0; + break; + } + +- return ret; ++ return 0; + } + + +@@ -1414,7 +1423,6 @@ virSecurityDACRestoreHostdevLabel(virSecurityManager *mgr, + virDomainHostdevSubsysSCSI *scsisrc = &dev->source.subsys.u.scsi; + virDomainHostdevSubsysSCSIVHost *hostsrc = &dev->source.subsys.u.scsi_host; + virDomainHostdevSubsysMediatedDev *mdevsrc = &dev->source.subsys.u.mdev; +- int ret = -1; + + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME); + +@@ -1441,7 +1449,8 @@ virSecurityDACRestoreHostdevLabel(virSecurityManager *mgr, + if (!(usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, vroot))) + return -1; + +- ret = virUSBDeviceFileIterate(usb, virSecurityDACRestoreUSBLabel, mgr); ++ if (virUSBDeviceFileIterate(usb, virSecurityDACRestoreUSBLabel, mgr) < 0) ++ return -1; + break; + } + +@@ -1449,7 +1458,7 @@ virSecurityDACRestoreHostdevLabel(virSecurityManager *mgr, + g_autoptr(virPCIDevice) pci = NULL; + + if (!virPCIDeviceExists(&pcisrc->addr)) +- break; ++ return -1; + + pci = virPCIDeviceNew(&pcisrc->addr); + +@@ -1463,24 +1472,29 @@ virSecurityDACRestoreHostdevLabel(virSecurityManager *mgr, + if (!vfioGroupDev) + return -1; + +- ret = virSecurityDACRestoreFileLabelInternal(mgr, NULL, +- vfioGroupDev, false); ++ if (virSecurityDACRestoreFileLabelInternal(mgr, NULL, ++ vfioGroupDev, false) < 0) { ++ return -1; ++ } + } else { + g_autofree char *vfiofdDev = NULL; + + if (virPCIDeviceGetVfioPath(pci, &vfiofdDev) < 0) + return -1; + +- ret = virSecurityDACRestoreFileLabelInternal(mgr, NULL, +- vfiofdDev, false); +- if (ret < 0) +- break; ++ if (virSecurityDACRestoreFileLabelInternal(mgr, NULL, ++ vfiofdDev, false) < 0) { ++ return -1; ++ } + +- ret = virSecurityDACRestoreFileLabelInternal(mgr, NULL, +- VIR_IOMMU_DEV_PATH, false); ++ if (virSecurityDACRestoreFileLabelInternal(mgr, NULL, ++ VIR_IOMMU_DEV_PATH, false) < 0) { ++ return -1; ++ } + } + } else { +- ret = virPCIDeviceFileIterate(pci, virSecurityDACRestorePCILabel, mgr); ++ if (virPCIDeviceFileIterate(pci, virSecurityDACRestorePCILabel, mgr) < 0) ++ return -1; + } + break; + } +@@ -1496,7 +1510,8 @@ virSecurityDACRestoreHostdevLabel(virSecurityManager *mgr, + if (!scsi) + return -1; + +- ret = virSCSIDeviceFileIterate(scsi, virSecurityDACRestoreSCSILabel, mgr); ++ if (virSCSIDeviceFileIterate(scsi, virSecurityDACRestoreSCSILabel, mgr) < 0) ++ return -1; + break; + } + +@@ -1506,9 +1521,11 @@ virSecurityDACRestoreHostdevLabel(virSecurityManager *mgr, + if (!host) + return -1; + +- ret = virSCSIVHostDeviceFileIterate(host, +- virSecurityDACRestoreHostLabel, +- mgr); ++ if (virSCSIVHostDeviceFileIterate(host, ++ virSecurityDACRestoreHostLabel, ++ mgr) < 0) { ++ return -1; ++ } + break; + } + +@@ -1518,16 +1535,16 @@ virSecurityDACRestoreHostdevLabel(virSecurityManager *mgr, + if (!(vfiodev = virMediatedDeviceGetIOMMUGroupDev(mdevsrc->uuidstr))) + return -1; + +- ret = virSecurityDACRestoreFileLabelInternal(mgr, NULL, vfiodev, false); ++ if (virSecurityDACRestoreFileLabelInternal(mgr, NULL, vfiodev, false) < 0) ++ return -1; + break; + } + + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: +- ret = 0; + break; + } + +- return ret; ++ return 0; + } + + +diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c +index 4a5f61d16b..96ca59a7a4 100644 +--- a/src/security/security_selinux.c ++++ b/src/security/security_selinux.c +@@ -2219,8 +2219,6 @@ virSecuritySELinuxSetHostdevSubsysLabel(virSecurityManager *mgr, + virDomainHostdevSubsysMediatedDev *mdevsrc = &dev->source.subsys.u.mdev; + virSecuritySELinuxCallbackData data = {.mgr = mgr, .def = def}; + +- int ret = -1; +- + /* Like virSecuritySELinuxSetImageLabelInternal() for a networked + * disk, do nothing for an iSCSI hostdev + */ +@@ -2241,7 +2239,8 @@ virSecuritySELinuxSetHostdevSubsysLabel(virSecurityManager *mgr, + if (!usb) + return -1; + +- ret = virUSBDeviceFileIterate(usb, virSecuritySELinuxSetUSBLabel, &data); ++ if (virUSBDeviceFileIterate(usb, virSecuritySELinuxSetUSBLabel, &data) < 0) ++ return -1; + break; + } + +@@ -2249,7 +2248,7 @@ virSecuritySELinuxSetHostdevSubsysLabel(virSecurityManager *mgr, + g_autoptr(virPCIDevice) pci = NULL; + + if (!virPCIDeviceExists(&pcisrc->addr)) +- break; ++ return -1; + + pci = virPCIDeviceNew(&pcisrc->addr); + +@@ -2263,23 +2262,26 @@ virSecuritySELinuxSetHostdevSubsysLabel(virSecurityManager *mgr, + if (!vfioGroupDev) + return -1; + +- ret = virSecuritySELinuxSetHostdevLabelHelper(vfioGroupDev, +- false, +- &data); ++ if (virSecuritySELinuxSetHostdevLabelHelper(vfioGroupDev, ++ false, ++ &data) < 0) { ++ return -1; ++ } + } else { + g_autofree char *vfiofdDev = NULL; + + if (virPCIDeviceGetVfioPath(pci, &vfiofdDev) < 0) + return -1; + +- ret = virSecuritySELinuxSetHostdevLabelHelper(vfiofdDev, false, &data); +- if (ret) +- break; ++ if (virSecuritySELinuxSetHostdevLabelHelper(vfiofdDev, false, &data) < 0) ++ return -1; + +- ret = virSecuritySELinuxSetHostdevLabelHelper(VIR_IOMMU_DEV_PATH, false, &data); ++ if (virSecuritySELinuxSetHostdevLabelHelper(VIR_IOMMU_DEV_PATH, false, &data) < 0) ++ return -1; + } + } else { +- ret = virPCIDeviceFileIterate(pci, virSecuritySELinuxSetPCILabel, &data); ++ if (virPCIDeviceFileIterate(pci, virSecuritySELinuxSetPCILabel, &data) < 0) ++ return -1; + } + break; + } +@@ -2296,9 +2298,11 @@ virSecuritySELinuxSetHostdevSubsysLabel(virSecurityManager *mgr, + if (!scsi) + return -1; + +- ret = virSCSIDeviceFileIterate(scsi, +- virSecuritySELinuxSetSCSILabel, +- &data); ++ if (virSCSIDeviceFileIterate(scsi, ++ virSecuritySELinuxSetSCSILabel, ++ &data) < 0) { ++ return -1; ++ } + break; + } + +@@ -2308,9 +2312,11 @@ virSecuritySELinuxSetHostdevSubsysLabel(virSecurityManager *mgr, + if (!host) + return -1; + +- ret = virSCSIVHostDeviceFileIterate(host, +- virSecuritySELinuxSetHostLabel, +- &data); ++ if (virSCSIVHostDeviceFileIterate(host, ++ virSecuritySELinuxSetHostLabel, ++ &data) < 0) { ++ return -1; ++ } + break; + } + +@@ -2318,18 +2324,18 @@ virSecuritySELinuxSetHostdevSubsysLabel(virSecurityManager *mgr, + g_autofree char *vfiodev = NULL; + + if (!(vfiodev = virMediatedDeviceGetIOMMUGroupDev(mdevsrc->uuidstr))) +- return ret; ++ return -1; + +- ret = virSecuritySELinuxSetHostdevLabelHelper(vfiodev, false, &data); ++ if (virSecuritySELinuxSetHostdevLabelHelper(vfiodev, false, &data) < 0) ++ return -1; + break; + } + + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: +- ret = 0; + break; + } + +- return ret; ++ return 0; + } + + +@@ -2467,7 +2473,6 @@ virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManager *mgr, + virDomainHostdevSubsysSCSI *scsisrc = &dev->source.subsys.u.scsi; + virDomainHostdevSubsysSCSIVHost *hostsrc = &dev->source.subsys.u.scsi_host; + virDomainHostdevSubsysMediatedDev *mdevsrc = &dev->source.subsys.u.mdev; +- int ret = -1; + + /* Like virSecuritySELinuxRestoreImageLabelInt() for a networked + * disk, do nothing for an iSCSI hostdev +@@ -2489,7 +2494,8 @@ virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManager *mgr, + if (!usb) + return -1; + +- ret = virUSBDeviceFileIterate(usb, virSecuritySELinuxRestoreUSBLabel, mgr); ++ if (virUSBDeviceFileIterate(usb, virSecuritySELinuxRestoreUSBLabel, mgr) < 0) ++ return -1; + break; + } + +@@ -2497,7 +2503,7 @@ virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManager *mgr, + g_autoptr(virPCIDevice) pci = NULL; + + if (!virPCIDeviceExists(&pcisrc->addr)) +- break; ++ return -1; + + pci = virPCIDeviceNew(&pcisrc->addr); + +@@ -2511,21 +2517,23 @@ virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManager *mgr, + if (!vfioGroupDev) + return -1; + +- ret = virSecuritySELinuxRestoreFileLabel(mgr, vfioGroupDev, false, false); ++ if (virSecuritySELinuxRestoreFileLabel(mgr, vfioGroupDev, false, false) < 0) ++ return -1; + } else { + g_autofree char *vfiofdDev = NULL; + + if (virPCIDeviceGetVfioPath(pci, &vfiofdDev) < 0) + return -1; + +- ret = virSecuritySELinuxRestoreFileLabel(mgr, vfiofdDev, false, false); +- if (ret < 0) +- break; ++ if (virSecuritySELinuxRestoreFileLabel(mgr, vfiofdDev, false, false) < 0) ++ return -1; + +- ret = virSecuritySELinuxRestoreFileLabel(mgr, VIR_IOMMU_DEV_PATH, false, false); ++ if (virSecuritySELinuxRestoreFileLabel(mgr, VIR_IOMMU_DEV_PATH, false, false) < 0) ++ return -1; + } + } else { +- ret = virPCIDeviceFileIterate(pci, virSecuritySELinuxRestorePCILabel, mgr); ++ if (virPCIDeviceFileIterate(pci, virSecuritySELinuxRestorePCILabel, mgr) < 0) ++ return -1; + } + break; + } +@@ -2541,7 +2549,8 @@ virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManager *mgr, + if (!scsi) + return -1; + +- ret = virSCSIDeviceFileIterate(scsi, virSecuritySELinuxRestoreSCSILabel, mgr); ++ if (virSCSIDeviceFileIterate(scsi, virSecuritySELinuxRestoreSCSILabel, mgr) < 0) ++ return -1; + break; + } + +@@ -2551,9 +2560,11 @@ virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManager *mgr, + if (!host) + return -1; + +- ret = virSCSIVHostDeviceFileIterate(host, +- virSecuritySELinuxRestoreHostLabel, +- mgr); ++ if (virSCSIVHostDeviceFileIterate(host, ++ virSecuritySELinuxRestoreHostLabel, ++ mgr) < 0) { ++ return -1; ++ } + break; + } + +@@ -2563,16 +2574,16 @@ virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManager *mgr, + if (!(vfiodev = virMediatedDeviceGetIOMMUGroupDev(mdevsrc->uuidstr))) + return -1; + +- ret = virSecuritySELinuxRestoreFileLabel(mgr, vfiodev, false, false); ++ if (virSecuritySELinuxRestoreFileLabel(mgr, vfiodev, false, false) < 0) ++ return -1; + break; + } + + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: +- ret = 0; + break; + } + +- return ret; ++ return 0; + } + + +-- +2.53.0 diff --git a/libvirt-security_apparmor-Use-g_auto-in-AppArmorSetSecurityHostdevLabel.patch b/libvirt-security_apparmor-Use-g_auto-in-AppArmorSetSecurityHostdevLabel.patch new file mode 100644 index 0000000..d7a7b1a --- /dev/null +++ b/libvirt-security_apparmor-Use-g_auto-in-AppArmorSetSecurityHostdevLabel.patch @@ -0,0 +1,120 @@ +From d3c83b7a546f63aec8d8a9b55f99a726b2988a4f Mon Sep 17 00:00:00 2001 +Message-ID: +From: Pavel Hrdina +Date: Mon, 2 Mar 2026 12:47:43 +0100 +Subject: [PATCH] security_apparmor: Use g_auto* in + AppArmorSetSecurityHostdevLabel +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Pavel Hrdina + +Signed-off-by: Pavel Hrdina +Reviewed-by: Ján Tomko +(cherry picked from commit 75f698c77f0705ae9793331eadb08fbbf89572f6) + +Resolves: https://redhat.atlassian.net/browse/VOYAGER-309 +Signed-off-by: Pavel Hrdina +--- + src/security/security_apparmor.c | 20 ++++++-------------- + 1 file changed, 6 insertions(+), 14 deletions(-) + +diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c +index 6c5da2a650..74c5b10063 100644 +--- a/src/security/security_apparmor.c ++++ b/src/security/security_apparmor.c +@@ -799,7 +799,7 @@ AppArmorSetSecurityHostdevLabel(virSecurityManager *mgr, + virDomainHostdevDef *dev, + const char *vroot) + { +- struct SDPDOP *ptr; ++ g_autofree struct SDPDOP *ptr = NULL; + int ret = -1; + virSecurityLabelDef *secdef = + virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME); +@@ -831,13 +831,12 @@ AppArmorSetSecurityHostdevLabel(virSecurityManager *mgr, + + switch (dev->source.subsys.type) { + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: { +- virUSBDevice *usb = ++ g_autoptr(virUSBDevice) usb = + virUSBDeviceNew(usbsrc->bus, usbsrc->device, vroot); + if (!usb) + goto done; + + ret = virUSBDeviceFileIterate(usb, AppArmorSetSecurityUSBLabel, ptr); +- virUSBDeviceFree(usb); + break; + } + +@@ -850,13 +849,12 @@ AppArmorSetSecurityHostdevLabel(virSecurityManager *mgr, + + if (pcisrc->driver.name == VIR_DEVICE_HOSTDEV_PCI_DRIVER_NAME_VFIO) { + if (dev->source.subsys.u.pci.driver.iommufd != VIR_TRISTATE_BOOL_YES) { +- char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci); ++ g_autofree char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci); + + if (!vfioGroupDev) { + goto done; + } + ret = AppArmorSetSecurityPCILabel(pci, vfioGroupDev, ptr); +- VIR_FREE(vfioGroupDev); + } else { + g_autofree char *vfiofdDev = NULL; + +@@ -877,7 +875,7 @@ AppArmorSetSecurityHostdevLabel(virSecurityManager *mgr, + + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: { + virDomainHostdevSubsysSCSIHost *scsihostsrc = &scsisrc->u.host; +- virSCSIDevice *scsi = ++ g_autoptr(virSCSIDevice) scsi = + virSCSIDeviceNew(NULL, + scsihostsrc->adapter, scsihostsrc->bus, + scsihostsrc->target, scsihostsrc->unit, +@@ -887,13 +885,11 @@ AppArmorSetSecurityHostdevLabel(virSecurityManager *mgr, + goto done; + + ret = virSCSIDeviceFileIterate(scsi, AppArmorSetSecuritySCSILabel, ptr); +- virSCSIDeviceFree(scsi); +- + break; + } + + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST: { +- virSCSIVHostDevice *host = virSCSIVHostDeviceNew(hostsrc->wwpn); ++ g_autoptr(virSCSIVHostDevice) host = virSCSIVHostDeviceNew(hostsrc->wwpn); + + if (!host) + goto done; +@@ -901,19 +897,16 @@ AppArmorSetSecurityHostdevLabel(virSecurityManager *mgr, + ret = virSCSIVHostDeviceFileIterate(host, + AppArmorSetSecurityHostLabel, + ptr); +- virSCSIVHostDeviceFree(host); + break; + } + + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV: { +- char *vfiodev = NULL; ++ g_autofree char *vfiodev = NULL; + + if (!(vfiodev = virMediatedDeviceGetIOMMUGroupDev(mdevsrc->uuidstr))) + goto done; + + ret = AppArmorSetSecurityHostdevLabelHelper(vfiodev, ptr); +- +- VIR_FREE(vfiodev); + break; + } + +@@ -923,7 +916,6 @@ AppArmorSetSecurityHostdevLabel(virSecurityManager *mgr, + } + + done: +- VIR_FREE(ptr); + return ret; + } + +-- +2.53.0 diff --git a/libvirt-src-Use-virHostdevIsPCIDeviceWith-to-check-for-IOMMUFD.patch b/libvirt-src-Use-virHostdevIsPCIDeviceWith-to-check-for-IOMMUFD.patch new file mode 100644 index 0000000..428369b --- /dev/null +++ b/libvirt-src-Use-virHostdevIsPCIDeviceWith-to-check-for-IOMMUFD.patch @@ -0,0 +1,154 @@ +From e8cc2fdb6f842c7e5b6f23ea4ccf54d553624e67 Mon Sep 17 00:00:00 2001 +Message-ID: +From: Pavel Hrdina +Date: Fri, 13 Mar 2026 12:25:13 +0100 +Subject: [PATCH] src: Use virHostdevIsPCIDeviceWith* to check for IOMMUFD + +From: Pavel Hrdina + +Use virHostdevIsPCIDeviceWithIOMMUFD where we need to check if hostdev +is PCI device using IOMMUFD and virHostdevIsPCIDeviceWithoutIOMMUFD +where we need to check if hostdev is PCI device not using IOMMUFD. + +Fixes: 7d2f91f9cb572ab95d0916bdd1a46dd198874529 +Signed-off-by: Pavel Hrdina +Reviewed-by: Peter Krempa +(cherry picked from commit c1d38e9428783730f063b59ad32f08d2e80aff9f) + +Resolves: https://redhat.atlassian.net/browse/VOYAGER-309 +Signed-off-by: Pavel Hrdina +--- + src/qemu/qemu_cgroup.c | 2 +- + src/qemu/qemu_command.c | 2 +- + src/qemu/qemu_namespace.c | 2 +- + src/qemu/qemu_validate.c | 2 +- + src/security/security_apparmor.c | 2 +- + src/security/security_dac.c | 4 ++-- + src/security/security_selinux.c | 4 ++-- + src/security/virt-aa-helper.c | 2 +- + 8 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c +index 6148990f19..0e1815f571 100644 +--- a/src/qemu/qemu_cgroup.c ++++ b/src/qemu/qemu_cgroup.c +@@ -479,7 +479,7 @@ qemuSetupHostdevCgroup(virDomainObj *vm, + g_autofree char *path = NULL; + int perms; + +- if (dev->source.subsys.u.pci.driver.iommufd == VIR_TRISTATE_BOOL_YES) ++ if (virHostdevIsPCIDeviceWithIOMMUFD(dev)) + return 0; + + if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) +diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c +index d419e92cdf..30bed14b0c 100644 +--- a/src/qemu/qemu_command.c ++++ b/src/qemu/qemu_command.c +@@ -5260,7 +5260,7 @@ qemuBuildHostdevCommandLine(virCommand *cmd, + if (qemuCommandAddExtDevice(cmd, hostdev->info, def, qemuCaps) < 0) + return -1; + +- if (subsys->u.pci.driver.iommufd == VIR_TRISTATE_BOOL_YES) { ++ if (virHostdevIsPCIDeviceWithIOMMUFD(hostdev)) { + qemuDomainHostdevPrivate *hostdevPriv = QEMU_DOMAIN_HOSTDEV_PRIVATE(hostdev); + + qemuFDPassDirectTransferCommand(hostdevPriv->vfioDeviceFd, cmd); +diff --git a/src/qemu/qemu_namespace.c b/src/qemu/qemu_namespace.c +index fb0734193d..4a063064f1 100644 +--- a/src/qemu/qemu_namespace.c ++++ b/src/qemu/qemu_namespace.c +@@ -345,7 +345,7 @@ qemuDomainSetupHostdev(virDomainObj *vm, + { + g_autofree char *path = NULL; + +- if (hostdev->source.subsys.u.pci.driver.iommufd == VIR_TRISTATE_BOOL_YES) ++ if (virHostdevIsPCIDeviceWithIOMMUFD(hostdev)) + return 0; + + if (qemuDomainGetHostdevPath(hostdev, &path, NULL) < 0) +diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c +index aa441188cb..c39d8c869f 100644 +--- a/src/qemu/qemu_validate.c ++++ b/src/qemu/qemu_validate.c +@@ -2725,7 +2725,7 @@ qemuValidateDomainDeviceDefHostdev(const virDomainHostdevDef *hostdev, + return -1; + } + +- if (hostdev->source.subsys.u.pci.driver.iommufd == VIR_TRISTATE_BOOL_YES) { ++ if (virHostdevIsPCIDeviceWithIOMMUFD(hostdev)) { + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_IOMMUFD)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("IOMMUFD is not supported by this version of qemu")); +diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c +index 40f13ec1a5..e53486ee0c 100644 +--- a/src/security/security_apparmor.c ++++ b/src/security/security_apparmor.c +@@ -847,7 +847,7 @@ AppArmorSetSecurityHostdevLabel(virSecurityManager *mgr, + return -1; + + if (pcisrc->driver.name == VIR_DEVICE_HOSTDEV_PCI_DRIVER_NAME_VFIO) { +- if (dev->source.subsys.u.pci.driver.iommufd != VIR_TRISTATE_BOOL_YES) { ++ if (virHostdevIsPCIDeviceWithoutIOMMUFD(dev)) { + g_autofree char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci); + + if (!vfioGroupDev) +diff --git a/src/security/security_dac.c b/src/security/security_dac.c +index d8cf117fc4..b891f6f121 100644 +--- a/src/security/security_dac.c ++++ b/src/security/security_dac.c +@@ -1283,7 +1283,7 @@ virSecurityDACSetHostdevLabel(virSecurityManager *mgr, + return -1; + + if (pcisrc->driver.name == VIR_DEVICE_HOSTDEV_PCI_DRIVER_NAME_VFIO) { +- if (dev->source.subsys.u.pci.driver.iommufd != VIR_TRISTATE_BOOL_YES) { ++ if (virHostdevIsPCIDeviceWithoutIOMMUFD(dev)) { + g_autofree char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci); + + if (!vfioGroupDev) +@@ -1454,7 +1454,7 @@ virSecurityDACRestoreHostdevLabel(virSecurityManager *mgr, + return -1; + + if (pcisrc->driver.name == VIR_DEVICE_HOSTDEV_PCI_DRIVER_NAME_VFIO) { +- if (dev->source.subsys.u.pci.driver.iommufd != VIR_TRISTATE_BOOL_YES) { ++ if (virHostdevIsPCIDeviceWithoutIOMMUFD(dev)) { + g_autofree char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci); + + if (!vfioGroupDev) +diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c +index 0fa50630f7..2b801aecd5 100644 +--- a/src/security/security_selinux.c ++++ b/src/security/security_selinux.c +@@ -2255,7 +2255,7 @@ virSecuritySELinuxSetHostdevSubsysLabel(virSecurityManager *mgr, + return -1; + + if (pcisrc->driver.name == VIR_DEVICE_HOSTDEV_PCI_DRIVER_NAME_VFIO) { +- if (dev->source.subsys.u.pci.driver.iommufd != VIR_TRISTATE_BOOL_YES) { ++ if (virHostdevIsPCIDeviceWithoutIOMMUFD(dev)) { + g_autofree char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci); + + if (!vfioGroupDev) +@@ -2499,7 +2499,7 @@ virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManager *mgr, + return -1; + + if (pcisrc->driver.name == VIR_DEVICE_HOSTDEV_PCI_DRIVER_NAME_VFIO) { +- if (dev->source.subsys.u.pci.driver.iommufd != VIR_TRISTATE_BOOL_YES) { ++ if (virHostdevIsPCIDeviceWithoutIOMMUFD(dev)) { + g_autofree char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci); + + if (!vfioGroupDev) +diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c +index 29e844c7ff..af95a64c42 100644 +--- a/src/security/virt-aa-helper.c ++++ b/src/security/virt-aa-helper.c +@@ -1117,7 +1117,7 @@ get_files(vahControl * ctl) + + if ((driverName == VIR_DEVICE_HOSTDEV_PCI_DRIVER_NAME_VFIO || + driverName == VIR_DEVICE_HOSTDEV_PCI_DRIVER_NAME_DEFAULT) && +- dev->source.subsys.u.pci.driver.iommufd != VIR_TRISTATE_BOOL_YES) { ++ virHostdevIsPCIDeviceWithoutIOMMUFD(dev)) { + needsVfio = true; + } + +-- +2.53.0 diff --git a/libvirt-tests-Add-iommufd-fdgroup-test.patch b/libvirt-tests-Add-iommufd-fdgroup-test.patch new file mode 100644 index 0000000..44f62de --- /dev/null +++ b/libvirt-tests-Add-iommufd-fdgroup-test.patch @@ -0,0 +1,268 @@ +From 12ee11bc8ea918b8c7c15e52b4bbbd09e2e95fb0 Mon Sep 17 00:00:00 2001 +Message-ID: <12ee11bc8ea918b8c7c15e52b4bbbd09e2e95fb0.1774023916.git.phrdina@redhat.com> +From: Pavel Hrdina +Date: Mon, 16 Mar 2026 15:30:18 +0100 +Subject: [PATCH] tests: Add iommufd fdgroup test + +From: Pavel Hrdina + +Signed-off-by: Pavel Hrdina +Reviewed-by: Peter Krempa +(cherry picked from commit 406b7fb0bd82251d94ce1fcb5fd7e35d51e1a1b7) + +Conflicts: + - tests/qemuxmlconftest.c + missing upstream commit 6d6da1cbac4f0194ca257c8ff8f5038a96791a62 + +Resolves: https://redhat.atlassian.net/browse/VOYAGER-309 +Signed-off-by: Pavel Hrdina +--- + src/qemu/qemu_process.c | 14 +++-- + src/qemu/qemu_processpriv.h | 2 + + .../iommufd-q35-fd.x86_64-latest.args | 41 +++++++++++++ + .../iommufd-q35-fd.x86_64-latest.xml | 60 +++++++++++++++++++ + tests/qemuxmlconfdata/iommufd-q35-fd.xml | 38 ++++++++++++ + tests/qemuxmlconftest.c | 9 ++- + 6 files changed, 159 insertions(+), 5 deletions(-) + create mode 100644 tests/qemuxmlconfdata/iommufd-q35-fd.x86_64-latest.args + create mode 100644 tests/qemuxmlconfdata/iommufd-q35-fd.x86_64-latest.xml + create mode 100644 tests/qemuxmlconfdata/iommufd-q35-fd.xml + +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 2b1d47ed86..10a4a70f1c 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -7706,9 +7706,11 @@ qemuProcessOpenIommuFd(virDomainObj *vm) + * + * Find passed FD via virDomainFDAssociate() API for the VM. + * ++ * Exported only to be used in tests. ++ * + * Returns: 0 on success, -1 on failure + */ +-static int ++int + qemuProcessGetPassedIommuFd(virDomainObj *vm) + { + qemuDomainObjPrivate *priv = vm->privateData; +@@ -7728,10 +7730,14 @@ qemuProcessGetPassedIommuFd(virDomainObj *vm) + return -1; + } + +- iommufd = dup(fdt->fds[0]); ++ if (fdt->testfds) { ++ iommufd = dup2(fdt->fds[0], fdt->testfds[0]); ++ } else { ++ iommufd = dup(fdt->fds[0]); + +- if (qemuSecuritySetImageFDLabel(priv->driver->securityManager, vm->def, iommufd) < 0) +- return -1; ++ if (qemuSecuritySetImageFDLabel(priv->driver->securityManager, vm->def, iommufd) < 0) ++ return -1; ++ } + + priv->iommufd = qemuFDPassDirectNew("iommufd", &iommufd); + +diff --git a/src/qemu/qemu_processpriv.h b/src/qemu/qemu_processpriv.h +index 0ba5897f40..4bef5025b9 100644 +--- a/src/qemu/qemu_processpriv.h ++++ b/src/qemu/qemu_processpriv.h +@@ -37,3 +37,5 @@ void qemuProcessHandleDeviceDeleted(qemuMonitor *mon, + const char *devAlias); + + int qemuProcessQMPInitMonitor(qemuMonitor *mon); ++ ++int qemuProcessGetPassedIommuFd(virDomainObj *vm); +diff --git a/tests/qemuxmlconfdata/iommufd-q35-fd.x86_64-latest.args b/tests/qemuxmlconfdata/iommufd-q35-fd.x86_64-latest.args +new file mode 100644 +index 0000000000..7df3d173f3 +--- /dev/null ++++ b/tests/qemuxmlconfdata/iommufd-q35-fd.x86_64-latest.args +@@ -0,0 +1,41 @@ ++LC_ALL=C \ ++PATH=/bin \ ++HOME=/var/lib/libvirt/qemu/domain--1-q35-test \ ++USER=test \ ++LOGNAME=test \ ++XDG_DATA_HOME=/var/lib/libvirt/qemu/domain--1-q35-test/.local/share \ ++XDG_CACHE_HOME=/var/lib/libvirt/qemu/domain--1-q35-test/.cache \ ++XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-q35-test/.config \ ++/usr/bin/qemu-system-x86_64 \ ++-name guest=q35-test,debug-threads=on \ ++-S \ ++-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/lib/libvirt/qemu/domain--1-q35-test/master-key.aes"}' \ ++-machine q35,usb=off,dump-guest-core=off,memory-backend=pc.ram,acpi=off \ ++-accel tcg \ ++-cpu qemu64 \ ++-m size=2097152k \ ++-object '{"qom-type":"memory-backend-ram","id":"pc.ram","size":2147483648}' \ ++-overcommit mem-lock=off \ ++-smp 2,sockets=2,cores=1,threads=1 \ ++-uuid 11dbdcdd-4c3b-482b-8903-9bdb8c0a2774 \ ++-display none \ ++-no-user-config \ ++-nodefaults \ ++-chardev socket,id=charmonitor,fd=1729,server=on,wait=off \ ++-mon chardev=charmonitor,id=monitor,mode=control \ ++-rtc base=utc \ ++-no-shutdown \ ++-boot strict=on \ ++-device '{"driver":"pcie-root-port","port":16,"chassis":1,"id":"pci.1","bus":"pcie.0","multifunction":true,"addr":"0x2"}' \ ++-device '{"driver":"pcie-root-port","port":17,"chassis":2,"id":"pci.2","bus":"pcie.0","addr":"0x2.0x1"}' \ ++-device '{"driver":"qemu-xhci","id":"usb","bus":"pci.1","addr":"0x0"}' \ ++-blockdev '{"driver":"host_device","filename":"/dev/HostVG/QEMUGuest1","node-name":"libvirt-1-storage","read-only":false}' \ ++-device '{"driver":"ide-hd","bus":"ide.0","drive":"libvirt-1-storage","id":"sata0-0-0","bootindex":1}' \ ++-audiodev '{"id":"audio1","driver":"none"}' \ ++-device '{"driver":"qxl-vga","id":"video0","max_outputs":1,"ram_size":67108864,"vram_size":33554432,"vram64_size_mb":0,"vgamem_mb":8,"bus":"pcie.0","addr":"0x1"}' \ ++-global ICH9-LPC.noreboot=off \ ++-watchdog-action reset \ ++-object '{"qom-type":"iommufd","id":"iommufd0","fd":"20"}' \ ++-device '{"driver":"vfio-pci","id":"hostdev0","iommufd":"iommufd0","fd":"0","bus":"pcie.0","addr":"0x3"}' \ ++-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \ ++-msg timestamp=on +diff --git a/tests/qemuxmlconfdata/iommufd-q35-fd.x86_64-latest.xml b/tests/qemuxmlconfdata/iommufd-q35-fd.x86_64-latest.xml +new file mode 100644 +index 0000000000..a6be49cbb3 +--- /dev/null ++++ b/tests/qemuxmlconfdata/iommufd-q35-fd.x86_64-latest.xml +@@ -0,0 +1,60 @@ ++ ++ q35-test ++ 11dbdcdd-4c3b-482b-8903-9bdb8c0a2774 ++ 2097152 ++ 2097152 ++ 2 ++ ++ ++ hvm ++ ++ ++ ++ qemu64 ++ ++ ++ destroy ++ restart ++ destroy ++ ++ /usr/bin/qemu-system-x86_64 ++ ++ ++ ++ ++
++ ++ ++ ++ ++ ++
++ ++ ++ ++ ++
++ ++ ++
++ ++ ++
++ ++ ++ ++