On 8/19/26 3:35 AM, Martin Kletzander via Devel wrote:
On Tue, Aug 18, 2026 at 12:21:03PM -0400, Omar Elghoul wrote:
Hi,
This patchset proposes a fix for what I believe is a bug in libvirt when
using iommufd under SELinux enforcing. It is an RFC because I cannot yet
vouch for its correctness -- the goal is not to merge this code as is,
but rather start a discussion on how we should go about things.
When using iommufd, libvirt opens the vfio cdev corresponding to the
device (e.g. /dev/vfio/devices/{n}) and the IOMMU device (/dev/iommu)
and passes the file descriptors to qemu. The cdev is a device-specific
resource, and thus a per-domain resource. The IOMMU on the other hand is
a shared resource between all domains.
Using the SELinux driver, libvirt relabels and assigns MCS categories to
domain-specific devices to isolate from other domains. However, it also
incorrectly assigns these categories to the IOMMU device. This can make
subsequent domains unable to create DMA mappings. On my s390x host, I've
repeatedly observed this problem showing up as PCI error events that
show a DMA attempt to a non-present page.
This problem is reproducible by running `setenforce 1` and then starting
two domains, each with a PCI passthrough device using iommufd, and then
performing actions that initiate PCI DMA transactions from within the
guests. Launching qemu manually from the command-line does not produce
these errors.
There is also an additional cleanup problem that is not addressed in
libvirt today, nor in my patches. When libvirt relabels a device, it
doesn't restore the default label after the domain is destroyed. This is
fine for the vfio cdevs, because they will disappear anyway as they get
unbound from the vfio driver and rebind their default driver, but again
is problematic for /dev/iommu because the inode is never unlinked.
For example, the good state before starting a domain:
root in ~/libvirt λ matchpathcon /dev/iommu
/dev/iommu system_u:object_r:iommu_device_t:s0
root in ~/libvirt λ ls -Z /dev/iommu
system_u:object_r:iommu_device_t:s0 /dev/iommu
After starting and ending all domains (without my patches):
root in ~/libvirt λ ls -Z /dev/iommu
system_u:object_r:svirt_image_t:s0:c614,c980 /dev/iommu
My patches remove the per-domain MCS categories (i.e., c614,c980) from
the IOMMU, but they do NOT clean up the inode relabel. For the domain's
lifetime, a relabel from iommu_device_t to svirt_image_t is correct. But
I'm skeptical of whether we should clean that up at all when no domains
are running, so that's another point I hope to get sorted out.
I'd be happy to hear any feedback or thoughts on resolving this issue.
If there's more questions or anyone needs more details, I'm available
to answer those too.
It "makes sense" what libvirt does, or rather "why" it does it, but you
are correct it is not correct. Sure, there are many ways this could get
fixed, but what I immediately thought of was a completely different
solution. I am also not sure what all the implications are and whether
it is correct or not, but similarly to NFS, I feel like there could be a
SELinux boolean (NFS access from virtual machines has virt_use_nfs)
which would allow svirt_t to access ipmmu_device_t and with that we
could stop labelling the /dev/iommu file. That would solve both of the
reported issues. On the other hand, I must say I am not sure what else
it would allow.
I actually thought of this and did exactly that as an experiment to
verify my hypothesis prior to writing up these patches. I tested it by
making a SELinux module to override the default policy, letting svirt_t
access iommu_device_t with the relevant syscalls/ioctls/etc.
That said, I personally didn't like that approach because I feel like
making a change to SELinux policy is much more likely to raise eyebrows,
and rightfully so especially when it requires a libvirt change anyway to
drop the relabeling. Not to mention the relabeling to svirt_image_t on
its own makes sense and is consistent with how libvirt labels other
devices. I also feel like this can potentially leave us with weird cases
where qemu cannot access the IOMMU at all, e.g. on a system where the
IOMMU doesn't have the iommu_device_t label at all by default and then
libvirt doesn't add it.
Thanks
Thanks in advance.
Omar Elghoul (2):
security: add SetSharedImageFDLabel() for shared image FDs
qemu: drop per-domain MCS categories from IOMMU device
src/libvirt_private.syms | 1 +
src/qemu/qemu_process.c | 4 +-
src/qemu/qemu_security.h | 1 +
src/security/security_apparmor.c | 1 +
src/security/security_dac.c | 1 +
src/security/security_driver.h | 4 ++
src/security/security_manager.c | 16 ++++++++
src/security/security_manager.h | 3 ++
src/security/security_nop.c | 1 +
src/security/security_selinux.c | 63 ++++++++++++++++++++++++++++++++
src/security/security_stack.c | 18 +++++++++
11 files changed, 111 insertions(+), 2 deletions(-)
--
2.55.0