On Thu, Dec 18, 2025 at 06:19:24PM -0800, Nathan Chen via Devel wrote:
> From: Nathan Chen <[email protected]>
>
> When launching a qemu VM with the iommufd feature enabled for VFIO
> hostdevs:
> - Do not allow cgroup, namespace, and seclabel access to VFIO
> paths (/dev/vfio/vfio and /dev/vfio/<iommugroup>)
> - Allow access to iommufd paths (/dev/iommu and
> /dev/vfio/devices/vfio*) for AppArmor, SELinux, and DAC
>
> Signed-off-by: Nathan Chen <[email protected]>
> ---
> src/qemu/qemu_cgroup.c | 26 +++++++-------
> src/qemu/qemu_namespace.c | 16 +++++----
> src/security/security_apparmor.c | 33 ++++++++++++++----
> src/security/security_dac.c | 60 ++++++++++++++++++++++++++------
> src/security/security_selinux.c | 58 ++++++++++++++++++++++++------
> src/security/virt-aa-helper.c | 32 +++++++++++++----
> 6 files changed, 172 insertions(+), 53 deletions(-)
snip
> diff --git a/src/security/security_apparmor.c
> b/src/security/security_apparmor.c
> index 68ac39611f..999275dac1 100644
> --- a/src/security/security_apparmor.c
> +++ b/src/security/security_apparmor.c
> @@ -848,14 +848,33 @@ AppArmorSetSecurityHostdevLabel(virSecurityManager *mgr,
> goto done;
>
> if (pcisrc->driver.name == VIR_DEVICE_HOSTDEV_PCI_DRIVER_NAME_VFIO) {
> - char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci);
> -
> - if (!vfioGroupDev) {
> - virPCIDeviceFree(pci);
> - goto done;
> + if (dev->source.subsys.u.pci.driver.iommufd !=
> VIR_TRISTATE_BOOL_YES) {
> + char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci);
> +
> + if (!vfioGroupDev) {
> + virPCIDeviceFree(pci);
> + goto done;
> + }
> + ret = AppArmorSetSecurityPCILabel(pci, vfioGroupDev, ptr);
> + VIR_FREE(vfioGroupDev);
> + } else {
> + g_autofree char *vfiofdDev = NULL;
> + const char *iommufdDir = "/dev/iommu";
So we declare / use this path 11 times by the end of this series
$ git grep /dev/iommu src/
src/qemu/qemu_process.c: * Opens /dev/iommu file descriptor for the VM.
src/qemu/qemu_process.c: if ((fd = open("/dev/iommu", O_RDWR | O_CLOEXEC)) <
0) {
src/qemu/qemu_process.c: _("IOMMU FD support requires
/dev/iommu device"));
src/qemu/qemu_process.c: _("cannot open
/dev/iommu"));
src/security/security_apparmor.c: const char *iommufdDir =
"/dev/iommu";
src/security/security_dac.c: const char *iommufdDir =
"/dev/iommu";
src/security/security_dac.c: const char *iommufdDir =
"/dev/iommu";
src/security/security_selinux.c: const char *iommufdDir =
"/dev/iommu";
src/security/security_selinux.c: const char *iommufdDir =
"/dev/iommu";
src/security/virt-aa-helper.c: STREQ(ctl->newfile, "/dev/iommu")) {
src/security/virt-aa-helper.c: STREQ(ctl->newfile,
"/dev/iommu")) {
how about we declare VIR_IOMMU_DEV_PATH in src/util/viriommu.h and
use that throughout.
> +
> + if (virPCIDeviceGetVfioPath(&dev->source.subsys.u.pci.addr,
> &vfiofdDev) < 0)
> + return -1;
> +
> + if (!virFileExists(iommufdDir))
> + return -1;
...and even add 'bool virIOMMUFDSupported(void)' that does this
virFileExists check.
> +
> + ret = AppArmorSetSecurityPCILabel(pci, vfiofdDev, ptr);
> + if (ret)
> + return ret;
> +
> + ret = AppArmorSetSecurityPCILabel(pci, iommufdDir, ptr);
> + if (ret)
> + return ret;
> }
> - ret = AppArmorSetSecurityPCILabel(pci, vfioGroupDev, ptr);
> - VIR_FREE(vfioGroupDev);
> } else {
> ret = virPCIDeviceFileIterate(pci, AppArmorSetSecurityPCILabel,
> ptr);
> }
> diff --git a/src/security/security_dac.c b/src/security/security_dac.c
> index 2f788b872a..09e26033ac 100644
> --- a/src/security/security_dac.c
> +++ b/src/security/security_dac.c
> @@ -1282,14 +1282,33 @@ virSecurityDACSetHostdevLabel(virSecurityManager *mgr,
> return -1;
>
> if (pcisrc->driver.name == VIR_DEVICE_HOSTDEV_PCI_DRIVER_NAME_VFIO) {
> - g_autofree char *vfioGroupDev =
> virPCIDeviceGetIOMMUGroupDev(pci);
> + if (dev->source.subsys.u.pci.driver.iommufd !=
> VIR_TRISTATE_BOOL_YES) {
> + g_autofree char *vfioGroupDev =
> virPCIDeviceGetIOMMUGroupDev(pci);
>
> - if (!vfioGroupDev)
> - return -1;
> + if (!vfioGroupDev)
> + return -1;
> +
> + ret = virSecurityDACSetHostdevLabelHelper(vfioGroupDev,
> + false,
> + &cbdata);
> + } else {
> + g_autofree char *vfiofdDev = NULL;
> + const char *iommufdDir = "/dev/iommu";
> +
> + if (virPCIDeviceGetVfioPath(&dev->source.subsys.u.pci.addr,
> &vfiofdDev) < 0)
> + return -1;
>
> - ret = virSecurityDACSetHostdevLabelHelper(vfioGroupDev,
> - false,
> - &cbdata);
> + if (!virFileExists(iommufdDir))
> + return -1;
> +
> + ret = virSecurityDACSetHostdevLabelHelper(vfiofdDev, false,
> &cbdata);
> + if (ret)
> + return ret;
> +
> + ret = virSecurityDACSetHostdevLabelHelper(iommufdDir, false,
> &cbdata);
> + if (ret)
> + return ret;
> + }
> } else {
> ret = virPCIDeviceFileIterate(pci,
> virSecurityDACSetPCILabel,
> @@ -1443,13 +1462,34 @@ virSecurityDACRestoreHostdevLabel(virSecurityManager
> *mgr,
> return -1;
>
> if (pcisrc->driver.name == VIR_DEVICE_HOSTDEV_PCI_DRIVER_NAME_VFIO) {
> - g_autofree char *vfioGroupDev =
> virPCIDeviceGetIOMMUGroupDev(pci);
> + if (dev->source.subsys.u.pci.driver.iommufd !=
> VIR_TRISTATE_BOOL_YES) {
> + g_autofree char *vfioGroupDev =
> virPCIDeviceGetIOMMUGroupDev(pci);
>
> - if (!vfioGroupDev)
> - return -1;
> + if (!vfioGroupDev)
> + return -1;
>
> - ret = virSecurityDACRestoreFileLabelInternal(mgr, NULL,
> + ret = virSecurityDACRestoreFileLabelInternal(mgr, NULL,
> vfioGroupDev,
> false);
> + } else {
> + g_autofree char *vfiofdDev = NULL;
> + const char *iommufdDir = "/dev/iommu";
> +
> + if (virPCIDeviceGetVfioPath(&dev->source.subsys.u.pci.addr,
> &vfiofdDev) < 0)
> + return -1;
> +
> + if (!virFileExists(iommufdDir))
> + return -1;
> +
> + ret = virSecurityDACRestoreFileLabelInternal(mgr, NULL,
> + vfiofdDev,
> false);
> + if (ret)
> + return ret;
> +
> + ret = virSecurityDACRestoreFileLabelInternal(mgr, NULL,
> + iommufdDir,
> false);
> + if (ret)
> + return ret;
> + }
> } else {
> ret = virPCIDeviceFileIterate(pci,
> virSecurityDACRestorePCILabel, mgr);
> }
> diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
> index 2f3cc274a5..1dd0a9706a 100644
> --- a/src/security/security_selinux.c
> +++ b/src/security/security_selinux.c
> @@ -2256,14 +2256,33 @@
> virSecuritySELinuxSetHostdevSubsysLabel(virSecurityManager *mgr,
> return -1;
>
> if (pcisrc->driver.name == VIR_DEVICE_HOSTDEV_PCI_DRIVER_NAME_VFIO) {
> - g_autofree char *vfioGroupDev =
> virPCIDeviceGetIOMMUGroupDev(pci);
> + if (dev->source.subsys.u.pci.driver.iommufd !=
> VIR_TRISTATE_BOOL_YES) {
> + g_autofree char *vfioGroupDev =
> virPCIDeviceGetIOMMUGroupDev(pci);
>
> - if (!vfioGroupDev)
> - return -1;
> + if (!vfioGroupDev)
> + return -1;
> +
> + ret = virSecuritySELinuxSetHostdevLabelHelper(vfioGroupDev,
> + false,
> + &data);
> + } else {
> + g_autofree char *vfiofdDev = NULL;
> + const char *iommufdDir = "/dev/iommu";
> +
> + if (virPCIDeviceGetVfioPath(&dev->source.subsys.u.pci.addr,
> &vfiofdDev) < 0)
> + return -1;
>
> - ret = virSecuritySELinuxSetHostdevLabelHelper(vfioGroupDev,
> - false,
> - &data);
> + if (!virFileExists(iommufdDir))
> + return -1;
> +
> + ret = virSecuritySELinuxSetHostdevLabelHelper(vfiofdDev,
> false, &data);
> + if (ret)
> + return ret;
> +
> + ret = virSecuritySELinuxSetHostdevLabelHelper(iommufdDir,
> false, &data);
> + if (ret)
> + return ret;
> + }
> } else {
> ret = virPCIDeviceFileIterate(pci,
> virSecuritySELinuxSetPCILabel, &data);
> }
> @@ -2491,12 +2510,31 @@
> virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManager *mgr,
> return -1;
>
> if (pcisrc->driver.name == VIR_DEVICE_HOSTDEV_PCI_DRIVER_NAME_VFIO) {
> - g_autofree char *vfioGroupDev =
> virPCIDeviceGetIOMMUGroupDev(pci);
> + if (dev->source.subsys.u.pci.driver.iommufd !=
> VIR_TRISTATE_BOOL_YES) {
> + g_autofree char *vfioGroupDev =
> virPCIDeviceGetIOMMUGroupDev(pci);
>
> - if (!vfioGroupDev)
> - return -1;
> + if (!vfioGroupDev)
> + return -1;
> +
> + ret = virSecuritySELinuxRestoreFileLabel(mgr, vfioGroupDev,
> false, false);
> + } else {
> + g_autofree char *vfiofdDev = NULL;
> + const char *iommufdDir = "/dev/iommu";
> +
> + if (virPCIDeviceGetVfioPath(&dev->source.subsys.u.pci.addr,
> &vfiofdDev) < 0)
> + return -1;
>
> - ret = virSecuritySELinuxRestoreFileLabel(mgr, vfioGroupDev,
> false, false);
> + if (!virFileExists(iommufdDir))
> + return -1;
> +
> + ret = virSecuritySELinuxRestoreFileLabel(mgr, vfiofdDev,
> false, false);
> + if (ret)
> + return ret;
> +
> + ret = virSecuritySELinuxRestoreFileLabel(mgr, iommufdDir,
> false, false);
> + if (ret)
> + return ret;
> + }
> } else {
> ret = virPCIDeviceFileIterate(pci,
> virSecuritySELinuxRestorePCILabel, mgr);
> }
> diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c
> index de0a826063..5b320fbc89 100644
> --- a/src/security/virt-aa-helper.c
> +++ b/src/security/virt-aa-helper.c
> @@ -1114,8 +1114,9 @@ get_files(vahControl * ctl)
>
> virDeviceHostdevPCIDriverName driverName =
> dev->source.subsys.u.pci.driver.name;
>
> - if (driverName == VIR_DEVICE_HOSTDEV_PCI_DRIVER_NAME_VFIO ||
> - driverName == VIR_DEVICE_HOSTDEV_PCI_DRIVER_NAME_DEFAULT) {
> + 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) {
> needsVfio = true;
> }
>
> @@ -1348,6 +1349,7 @@ get_files(vahControl * ctl)
> virBufferAddLit(&buf, " \"/dev/vfio/vfio\" rw,\n");
> virBufferAddLit(&buf, " \"/dev/vfio/[0-9]*\" rw,\n");
> }
> +
> if (needsgl) {
> /* if using gl all sorts of further dri related paths will be needed
> */
> virBufferAddLit(&buf, " # DRI/Mesa/(e)GL config and driver
> paths\n");
> @@ -1385,9 +1387,18 @@ get_files(vahControl * ctl)
> }
> }
>
> - if (ctl->newfile &&
> - vah_add_file(&buf, ctl->newfile, "rwk") != 0) {
> - return -1;
> + if (ctl->newfile) {
> + const char *perms = "rwk";
> +
> + /* VFIO and iommufd devices need mmap permission */
> + if (STRPREFIX(ctl->newfile, "/dev/vfio/devices/vfio") ||
> + STREQ(ctl->newfile, "/dev/iommu")) {
> + perms = "rwm";
> + }
> +
> + if (vah_add_file(&buf, ctl->newfile, perms) != 0) {
> + return -1;
> + }
> }
>
> ctl->files = virBufferContentAndReset(&buf);
> @@ -1561,8 +1572,15 @@ main(int argc, char **argv)
> }
> }
> if (ctl->append && ctl->newfile) {
> - if (vah_add_file(&buf, ctl->newfile, "rwk") != 0)
> - goto cleanup;
> + const char *perms = "rwk";
> +
> + if (STRPREFIX(ctl->newfile, "/dev/vfio/devices/vfio") ||
> + STREQ(ctl->newfile, "/dev/iommu")) {
> + perms = "rwm";
> + }
> +
> + if (vah_add_file(&buf, ctl->newfile, perms) != 0)
> + return -1;
> } else {
> if (ctl->def->virtType == VIR_DOMAIN_VIRT_QEMU ||
> ctl->def->virtType == VIR_DOMAIN_VIRT_KQEMU ||
> --
> 2.43.0
>
With regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|