Skip to content

Commit ecda483

Browse files
rosatomjjoergroedel
authored andcommitted
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: c76c067 ("s390/pci: Use dma-iommu layer") Co-developed-by: Niklas Schnelle <[email protected]> Signed-off-by: Niklas Schnelle <[email protected]> Signed-off-by: Matthew Rosato <[email protected]> Reviewed-by: Niklas Schnelle <[email protected]> Reviewed-by: Jason Gunthorpe <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent 8e929cb commit ecda483

File tree

4 files changed

+59
-31
lines changed

4 files changed

+59
-31
lines changed

arch/s390/include/asm/pci.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ struct zpci_bar_struct {
9696
u8 size; /* order 2 exponent */
9797
};
9898

99-
struct s390_domain;
10099
struct kvm_zdev;
101100

102101
#define ZPCI_FUNCTIONS_PER_BUS 256
@@ -181,9 +180,10 @@ struct zpci_dev {
181180
struct dentry *debugfs_dev;
182181

183182
/* IOMMU and passthrough */
184-
struct s390_domain *s390_domain; /* s390 IOMMU domain data */
183+
struct iommu_domain *s390_domain; /* attached IOMMU domain */
185184
struct kvm_zdev *kzdev;
186185
struct mutex kzdev_lock;
186+
spinlock_t dom_lock; /* protect s390_domain change */
187187
};
188188

189189
static inline bool zdev_enabled(struct zpci_dev *zdev)

arch/s390/pci/pci.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ int zpci_fmb_enable_device(struct zpci_dev *zdev)
160160
u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_SET_MEASURE);
161161
struct zpci_iommu_ctrs *ctrs;
162162
struct zpci_fib fib = {0};
163+
unsigned long flags;
163164
u8 cc, status;
164165

165166
if (zdev->fmb || sizeof(*zdev->fmb) < zdev->fmb_length)
@@ -171,6 +172,7 @@ int zpci_fmb_enable_device(struct zpci_dev *zdev)
171172
WARN_ON((u64) zdev->fmb & 0xf);
172173

173174
/* reset software counters */
175+
spin_lock_irqsave(&zdev->dom_lock, flags);
174176
ctrs = zpci_get_iommu_ctrs(zdev);
175177
if (ctrs) {
176178
atomic64_set(&ctrs->mapped_pages, 0);
@@ -179,6 +181,7 @@ int zpci_fmb_enable_device(struct zpci_dev *zdev)
179181
atomic64_set(&ctrs->sync_map_rpcits, 0);
180182
atomic64_set(&ctrs->sync_rpcits, 0);
181183
}
184+
spin_unlock_irqrestore(&zdev->dom_lock, flags);
182185

183186

184187
fib.fmb_addr = virt_to_phys(zdev->fmb);

arch/s390/pci/pci_debug.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,17 +71,23 @@ static void pci_fmb_show(struct seq_file *m, char *name[], int length,
7171

7272
static void pci_sw_counter_show(struct seq_file *m)
7373
{
74-
struct zpci_iommu_ctrs *ctrs = zpci_get_iommu_ctrs(m->private);
74+
struct zpci_dev *zdev = m->private;
75+
struct zpci_iommu_ctrs *ctrs;
7576
atomic64_t *counter;
77+
unsigned long flags;
7678
int i;
7779

80+
spin_lock_irqsave(&zdev->dom_lock, flags);
81+
ctrs = zpci_get_iommu_ctrs(m->private);
7882
if (!ctrs)
79-
return;
83+
goto unlock;
8084

8185
counter = &ctrs->mapped_pages;
8286
for (i = 0; i < ARRAY_SIZE(pci_sw_names); i++, counter++)
8387
seq_printf(m, "%26s:\t%llu\n", pci_sw_names[i],
8488
atomic64_read(counter));
89+
unlock:
90+
spin_unlock_irqrestore(&zdev->dom_lock, flags);
8591
}
8692

8793
static int pci_perf_show(struct seq_file *m, void *v)

drivers/iommu/s390-iommu.c

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ struct s390_domain {
3333
struct rcu_head rcu;
3434
};
3535

36+
static struct iommu_domain blocking_domain;
37+
3638
static inline unsigned int calc_rtx(dma_addr_t ptr)
3739
{
3840
return ((unsigned long)ptr >> ZPCI_RT_SHIFT) & ZPCI_INDEX_MASK;
@@ -369,20 +371,36 @@ static void s390_domain_free(struct iommu_domain *domain)
369371
call_rcu(&s390_domain->rcu, s390_iommu_rcu_free_domain);
370372
}
371373

372-
static void s390_iommu_detach_device(struct iommu_domain *domain,
373-
struct device *dev)
374+
static void zdev_s390_domain_update(struct zpci_dev *zdev,
375+
struct iommu_domain *domain)
376+
{
377+
unsigned long flags;
378+
379+
spin_lock_irqsave(&zdev->dom_lock, flags);
380+
zdev->s390_domain = domain;
381+
spin_unlock_irqrestore(&zdev->dom_lock, flags);
382+
}
383+
384+
static int blocking_domain_attach_device(struct iommu_domain *domain,
385+
struct device *dev)
374386
{
375-
struct s390_domain *s390_domain = to_s390_domain(domain);
376387
struct zpci_dev *zdev = to_zpci_dev(dev);
388+
struct s390_domain *s390_domain;
377389
unsigned long flags;
378390

391+
if (zdev->s390_domain->type == IOMMU_DOMAIN_BLOCKED)
392+
return 0;
393+
394+
s390_domain = to_s390_domain(zdev->s390_domain);
379395
spin_lock_irqsave(&s390_domain->list_lock, flags);
380396
list_del_rcu(&zdev->iommu_list);
381397
spin_unlock_irqrestore(&s390_domain->list_lock, flags);
382398

383399
zpci_unregister_ioat(zdev, 0);
384-
zdev->s390_domain = NULL;
385400
zdev->dma_table = NULL;
401+
zdev_s390_domain_update(zdev, domain);
402+
403+
return 0;
386404
}
387405

388406
static int s390_iommu_attach_device(struct iommu_domain *domain,
@@ -401,20 +419,15 @@ static int s390_iommu_attach_device(struct iommu_domain *domain,
401419
domain->geometry.aperture_end < zdev->start_dma))
402420
return -EINVAL;
403421

404-
if (zdev->s390_domain)
405-
s390_iommu_detach_device(&zdev->s390_domain->domain, dev);
422+
blocking_domain_attach_device(&blocking_domain, dev);
406423

424+
/* If we fail now DMA remains blocked via blocking domain */
407425
cc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
408426
virt_to_phys(s390_domain->dma_table), &status);
409-
/*
410-
* If the device is undergoing error recovery the reset code
411-
* will re-establish the new domain.
412-
*/
413427
if (cc && status != ZPCI_PCI_ST_FUNC_NOT_AVAIL)
414428
return -EIO;
415-
416429
zdev->dma_table = s390_domain->dma_table;
417-
zdev->s390_domain = s390_domain;
430+
zdev_s390_domain_update(zdev, domain);
418431

419432
spin_lock_irqsave(&s390_domain->list_lock, flags);
420433
list_add_rcu(&zdev->iommu_list, &s390_domain->devices);
@@ -466,19 +479,11 @@ static struct iommu_device *s390_iommu_probe_device(struct device *dev)
466479
if (zdev->tlb_refresh)
467480
dev->iommu->shadow_on_flush = 1;
468481

469-
return &zdev->iommu_dev;
470-
}
482+
/* Start with DMA blocked */
483+
spin_lock_init(&zdev->dom_lock);
484+
zdev_s390_domain_update(zdev, &blocking_domain);
471485

472-
static void s390_iommu_release_device(struct device *dev)
473-
{
474-
struct zpci_dev *zdev = to_zpci_dev(dev);
475-
476-
/*
477-
* release_device is expected to detach any domain currently attached
478-
* to the device, but keep it attached to other devices in the group.
479-
*/
480-
if (zdev)
481-
s390_iommu_detach_device(&zdev->s390_domain->domain, dev);
486+
return &zdev->iommu_dev;
482487
}
483488

484489
static int zpci_refresh_all(struct zpci_dev *zdev)
@@ -697,9 +702,15 @@ static size_t s390_iommu_unmap_pages(struct iommu_domain *domain,
697702

698703
struct zpci_iommu_ctrs *zpci_get_iommu_ctrs(struct zpci_dev *zdev)
699704
{
700-
if (!zdev || !zdev->s390_domain)
705+
struct s390_domain *s390_domain;
706+
707+
lockdep_assert_held(&zdev->dom_lock);
708+
709+
if (zdev->s390_domain->type == IOMMU_DOMAIN_BLOCKED)
701710
return NULL;
702-
return &zdev->s390_domain->ctrs;
711+
712+
s390_domain = to_s390_domain(zdev->s390_domain);
713+
return &s390_domain->ctrs;
703714
}
704715

705716
int zpci_init_iommu(struct zpci_dev *zdev)
@@ -776,11 +787,19 @@ static int __init s390_iommu_init(void)
776787
}
777788
subsys_initcall(s390_iommu_init);
778789

790+
static struct iommu_domain blocking_domain = {
791+
.type = IOMMU_DOMAIN_BLOCKED,
792+
.ops = &(const struct iommu_domain_ops) {
793+
.attach_dev = blocking_domain_attach_device,
794+
}
795+
};
796+
779797
static const struct iommu_ops s390_iommu_ops = {
798+
.blocked_domain = &blocking_domain,
799+
.release_domain = &blocking_domain,
780800
.capable = s390_iommu_capable,
781801
.domain_alloc_paging = s390_domain_alloc_paging,
782802
.probe_device = s390_iommu_probe_device,
783-
.release_device = s390_iommu_release_device,
784803
.device_group = generic_device_group,
785804
.pgsize_bitmap = SZ_4K,
786805
.get_resv_regions = s390_iommu_get_resv_regions,

0 commit comments

Comments
 (0)