diff options
| author | Jason Gunthorpe <jgg@nvidia.com> | 2023-01-23 14:24:04 -0400 |
|---|---|---|
| committer | Jason Gunthorpe <jgg@nvidia.com> | 2023-01-23 14:24:04 -0400 |
| commit | fc3873095a09ce969543fa4a17fee271c8ca3566 (patch) | |
| tree | db46969d11afe94250112f72f178d6dae3bfccaa /drivers/iommu | |
| parent | b7bfaa761d760e72a969d116517eaa12e404c262 (diff) | |
| parent | b062007c63eb4452f1122384e86d402531fb1d52 (diff) | |
| download | linux-fc3873095a09ce969543fa4a17fee271c8ca3566.tar.gz linux-fc3873095a09ce969543fa4a17fee271c8ca3566.tar.bz2 linux-fc3873095a09ce969543fa4a17fee271c8ca3566.zip | |
Merge branch 'isolated_msi' into iommufd.git for-next
Jason Gunthorpe says:
====================
Harmonize these into a single irq_domain based check under
msi_device_has_isolated_msi().
In real HW "isolated MSI" is implemented in a few different ways:
- x86 uses "interrupt remapping" which is a block that sits between
the device and APIC, that can "remap" the MSI MemWr. AMD uses per-RID
tables to implement isolation while Intel stores the authorized RID in
each IRTE entry. Part of the remapping is discarding, HW will not
forward MSIs that don't positively match the tables.
- ARM GICv3 ITS integrates the concept of an out-of-band "device ID"
directly into the interrupt controller logic. The tables the GIC checks
that determine how to deliver the interrupt through the ITS device table
and interrupt translation tables allow limiting which interrupts device
IDs can trigger.
- S390 has unconditionally claimed it has isolated MSI through the iommu
driver. This is a weaker version of the other arches in that it only
works between "gisa" domains. See zpci_set_airq() and
https://lore.kernel.org/r/31af8174-35e9-ebeb-b9ef-74c90d4bfd93@linux.ibm.com/
After this series the "isolated MSI" is tagged based only on the
irq_domains that the interrupt travels through. For x86 enabling interrupt
remapping causes IR irq_domains to be installed in the path, and they can
carry the IRQ_DOMAIN_FLAG_ISOLATED_MSI. For ARM the GICv3 ITS itself
already sets the flag when it is running in a isolated mode, and S390
simply sets it always through an arch hook since it doesn't use
irq_domains at all.
This removes the intrusion of IRQ subsystem information into the iommu
drivers. Linux's iommu_domains abstraction has no bearing at all on the
security of MSI. Even if HW linked to the IOMMU may implement the security
on x86 implementations, Linux models that HW through the irq_domain, not
the iommu_domain.
====================
* branch 'isolated_msi':
iommu: Remove IOMMU_CAP_INTR_REMAP
irq/s390: Add arch_is_isolated_msi() for s390
iommu/x86: Replace IOMMU_CAP_INTR_REMAP with IRQ_DOMAIN_FLAG_ISOLATED_MSI
genirq/msi: Rename IRQ_DOMAIN_MSI_REMAP to IRQ_DOMAIN_ISOLATED_MSI
genirq/irqdomain: Remove unused irq_domain_check_msi_remap() code
iommufd: Convert to msi_device_has_isolated_msi()
vfio/type1: Convert to iommu_group_has_isolated_msi()
iommu: Add iommu_group_has_isolated_msi()
genirq/msi: Add msi_device_has_isolated_msi()
Link: https://lore.kernel.org/r/0-v3-3313bb5dd3a3+10f11-secure_msi_jgg@nvidia.com
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Diffstat (limited to 'drivers/iommu')
| -rw-r--r-- | drivers/iommu/amd/iommu.c | 5 | ||||
| -rw-r--r-- | drivers/iommu/intel/iommu.c | 2 | ||||
| -rw-r--r-- | drivers/iommu/intel/irq_remapping.c | 3 | ||||
| -rw-r--r-- | drivers/iommu/iommu.c | 24 | ||||
| -rw-r--r-- | drivers/iommu/iommufd/device.c | 4 | ||||
| -rw-r--r-- | drivers/iommu/s390-iommu.c | 2 |
6 files changed, 29 insertions, 11 deletions
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index cbeaab55c0db..321d50e9df5b 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -2271,8 +2271,6 @@ static bool amd_iommu_capable(struct device *dev, enum iommu_cap cap) switch (cap) { case IOMMU_CAP_CACHE_COHERENCY: return true; - case IOMMU_CAP_INTR_REMAP: - return (irq_remapping_enabled == 1); case IOMMU_CAP_NOEXEC: return false; case IOMMU_CAP_PRE_BOOT_PROTECTION: @@ -3671,7 +3669,8 @@ int amd_iommu_create_irq_domain(struct amd_iommu *iommu) } irq_domain_update_bus_token(iommu->ir_domain, DOMAIN_BUS_AMDVI); - iommu->ir_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT; + iommu->ir_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT | + IRQ_DOMAIN_FLAG_ISOLATED_MSI; if (amd_iommu_np_cache) iommu->ir_domain->msi_parent_ops = &virt_amdvi_msi_parent_ops; diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index 59df7e42fd53..7cfab5fd5e59 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -4464,8 +4464,6 @@ static bool intel_iommu_capable(struct device *dev, enum iommu_cap cap) switch (cap) { case IOMMU_CAP_CACHE_COHERENCY: return true; - case IOMMU_CAP_INTR_REMAP: - return irq_remapping_enabled == 1; case IOMMU_CAP_PRE_BOOT_PROTECTION: return dmar_platform_optin(); case IOMMU_CAP_ENFORCE_CACHE_COHERENCY: diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c index f58f5f57af78..6d01fa078c36 100644 --- a/drivers/iommu/intel/irq_remapping.c +++ b/drivers/iommu/intel/irq_remapping.c @@ -573,7 +573,8 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu) } irq_domain_update_bus_token(iommu->ir_domain, DOMAIN_BUS_DMAR); - iommu->ir_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT; + iommu->ir_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT | + IRQ_DOMAIN_FLAG_ISOLATED_MSI; if (cap_caching_mode(iommu->cap)) iommu->ir_domain->msi_parent_ops = &virt_dmar_msi_parent_ops; diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index de91dd88705b..834e6ecf3e51 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -30,6 +30,7 @@ #include <linux/cc_platform.h> #include <trace/events/iommu.h> #include <linux/sched/mm.h> +#include <linux/msi.h> #include "dma-iommu.h" @@ -1898,6 +1899,29 @@ bool device_iommu_capable(struct device *dev, enum iommu_cap cap) EXPORT_SYMBOL_GPL(device_iommu_capable); /** + * iommu_group_has_isolated_msi() - Compute msi_device_has_isolated_msi() + * for a group + * @group: Group to query + * + * IOMMU groups should not have differing values of + * msi_device_has_isolated_msi() for devices in a group. However nothing + * directly prevents this, so ensure mistakes don't result in isolation failures + * by checking that all the devices are the same. + */ +bool iommu_group_has_isolated_msi(struct iommu_group *group) +{ + struct group_device *group_dev; + bool ret = true; + + mutex_lock(&group->mutex); + list_for_each_entry(group_dev, &group->devices, list) + ret &= msi_device_has_isolated_msi(group_dev->dev); + mutex_unlock(&group->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(iommu_group_has_isolated_msi); + +/** * iommu_set_fault_handler() - set a fault handler for an iommu domain * @domain: iommu domain * @handler: fault handler diff --git a/drivers/iommu/iommufd/device.c b/drivers/iommu/iommufd/device.c index d81f93a321af..9f3b9674d72e 100644 --- a/drivers/iommu/iommufd/device.c +++ b/drivers/iommu/iommufd/device.c @@ -4,7 +4,6 @@ #include <linux/iommufd.h> #include <linux/slab.h> #include <linux/iommu.h> -#include <linux/irqdomain.h> #include "io_pagetable.h" #include "iommufd_private.h" @@ -169,8 +168,7 @@ static int iommufd_device_setup_msi(struct iommufd_device *idev, * operation from the device (eg a simple DMA) cannot trigger an * interrupt outside this iommufd context. */ - if (!device_iommu_capable(idev->dev, IOMMU_CAP_INTR_REMAP) && - !irq_domain_check_msi_remap()) { + if (!iommu_group_has_isolated_msi(idev->group)) { if (!allow_unsafe_interrupts) return -EPERM; diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c index ed33c6cce083..bb00580a30d8 100644 --- a/drivers/iommu/s390-iommu.c +++ b/drivers/iommu/s390-iommu.c @@ -34,8 +34,6 @@ static bool s390_iommu_capable(struct device *dev, enum iommu_cap cap) switch (cap) { case IOMMU_CAP_CACHE_COHERENCY: return true; - case IOMMU_CAP_INTR_REMAP: - return true; default: return false; } |
