diff options
author | Matthew Rosato <mjrosato@linux.ibm.com> | 2024-09-10 17:15:16 -0400 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2024-10-15 10:19:07 +0200 |
commit | ecda483339a5151e3ca30d6b82691ef6f1d17912 (patch) | |
tree | 77b0c4355a13b87d7b9dab0a8984e4f71952121e /arch/s390/pci/pci.c | |
parent | 8e929cb546ee42c9a61d24fae60605e9e3192354 (diff) | |
download | lwn-ecda483339a5151e3ca30d6b82691ef6f1d17912.tar.gz lwn-ecda483339a5151e3ca30d6b82691ef6f1d17912.zip |
iommu/s390: Implement blocking domain
This fixes a crash when surprise hot-unplugging a PCI device. This crash
happens because during hot-unplug __iommu_group_set_domain_nofail()
attaching the default domain fails when the platform no longer
recognizes the device as it has already been removed and we end up with
a NULL domain pointer and UAF. This is exactly the case referred to in
the second comment in __iommu_device_set_domain() and just as stated
there if we can instead attach the blocking domain the UAF is prevented
as this can handle the already removed device. Implement the blocking
domain to use this handling. With this change, the crash is fixed but
we still hit a warning attempting to change DMA ownership on a blocked
device.
Fixes: c76c067e488c ("s390/pci: Use dma-iommu layer")
Co-developed-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Reviewed-by: Niklas Schnelle <schnelle@linux.ibm.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Link: https://lore.kernel.org/r/20240910211516.137933-1-mjrosato@linux.ibm.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
Diffstat (limited to 'arch/s390/pci/pci.c')
-rw-r--r-- | arch/s390/pci/pci.c | 3 |
1 files changed, 3 insertions, 0 deletions
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index bd9624c20b80..be3299609f9b 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -160,6 +160,7 @@ int zpci_fmb_enable_device(struct zpci_dev *zdev) u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_SET_MEASURE); struct zpci_iommu_ctrs *ctrs; struct zpci_fib fib = {0}; + unsigned long flags; u8 cc, status; if (zdev->fmb || sizeof(*zdev->fmb) < zdev->fmb_length) @@ -171,6 +172,7 @@ int zpci_fmb_enable_device(struct zpci_dev *zdev) WARN_ON((u64) zdev->fmb & 0xf); /* reset software counters */ + spin_lock_irqsave(&zdev->dom_lock, flags); ctrs = zpci_get_iommu_ctrs(zdev); if (ctrs) { atomic64_set(&ctrs->mapped_pages, 0); @@ -179,6 +181,7 @@ int zpci_fmb_enable_device(struct zpci_dev *zdev) atomic64_set(&ctrs->sync_map_rpcits, 0); atomic64_set(&ctrs->sync_rpcits, 0); } + spin_unlock_irqrestore(&zdev->dom_lock, flags); fib.fmb_addr = virt_to_phys(zdev->fmb); |