git: c6dc9decd745 - stable/15 - iommu_get_requester(): make it more resilient against arbitrary dev arg
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 22 Sep 2025 04:57:59 UTC
The branch stable/15 has been updated by kib: URL: https://cgit.FreeBSD.org/src/commit/?id=c6dc9decd7455577528e198d13740bfd5216d015 commit c6dc9decd7455577528e198d13740bfd5216d015 Author: Konstantin Belousov <kib@FreeBSD.org> AuthorDate: 2025-09-05 23:06:18 +0000 Commit: Konstantin Belousov <kib@FreeBSD.org> CommitDate: 2025-09-22 04:56:13 +0000 iommu_get_requester(): make it more resilient against arbitrary dev arg PR: 289318 (cherry picked from commit c745a6818bcbf33cf7f59641c925d19b3f98cea8) --- sys/dev/iommu/busdma_iommu.c | 54 ++++++++++++++++++++++++++++++++----------- sys/dev/iommu/iommu.h | 2 +- sys/kern/subr_bus.c | 13 +++++++++-- sys/x86/iommu/amd_intrmap.c | 14 ++++++++--- sys/x86/iommu/intel_intrmap.c | 8 +++++-- 5 files changed, 70 insertions(+), 21 deletions(-) diff --git a/sys/dev/iommu/busdma_iommu.c b/sys/dev/iommu/busdma_iommu.c index 6856b0551dde..668ccf056463 100644 --- a/sys/dev/iommu/busdma_iommu.c +++ b/sys/dev/iommu/busdma_iommu.c @@ -114,8 +114,8 @@ iommu_bus_dma_is_dev_disabled(int domain, int bus, int slot, int func) * domain, and must collectively be assigned to use either IOMMU or * bounce mapping. */ -device_t -iommu_get_requester(device_t dev, uint16_t *rid) +int +iommu_get_requester(device_t dev, device_t *requesterp, uint16_t *rid) { devclass_t pci_class; device_t l, pci, pcib, pcip, pcibp, requester; @@ -129,7 +129,8 @@ iommu_get_requester(device_t dev, uint16_t *rid) pci = device_get_parent(dev); if (pci == NULL || device_get_devclass(pci) != pci_class) { *rid = 0; /* XXXKIB: Could be ACPI HID */ - return (requester); + *requesterp = NULL; + return (ENOTTY); } *rid = pci_get_rid(dev); @@ -141,16 +142,39 @@ iommu_get_requester(device_t dev, uint16_t *rid) */ for (;;) { pci = device_get_parent(l); - KASSERT(pci != NULL, ("iommu_get_requester(%s): NULL parent " - "for %s", device_get_name(dev), device_get_name(l))); - KASSERT(device_get_devclass(pci) == pci_class, - ("iommu_get_requester(%s): non-pci parent %s for %s", - device_get_name(dev), device_get_name(pci), - device_get_name(l))); + if (pci == NULL) { + if (bootverbose) { + printf( + "iommu_get_requester(%s): NULL parent for %s\n", + device_get_name(dev), device_get_name(l)); + } + *rid = 0; + *requesterp = NULL; + return (ENXIO); + } + if (device_get_devclass(pci) != pci_class) { + if (bootverbose) { + printf( + "iommu_get_requester(%s): non-pci parent %s for %s\n", + device_get_name(dev), device_get_name(pci), + device_get_name(l)); + } + *rid = 0; + *requesterp = NULL; + return (ENXIO); + } pcib = device_get_parent(pci); - KASSERT(pcib != NULL, ("iommu_get_requester(%s): NULL bridge " - "for %s", device_get_name(dev), device_get_name(pci))); + if (pcib == NULL) { + if (bootverbose) { + printf( + "iommu_get_requester(%s): NULL bridge for %s\n", + device_get_name(dev), device_get_name(pci)); + } + *rid = 0; + *requesterp = NULL; + return (ENXIO); + } /* * The parent of our "bridge" isn't another PCI bus, @@ -229,7 +253,8 @@ iommu_get_requester(device_t dev, uint16_t *rid) } } } - return (requester); + *requesterp = requester; + return (0); } struct iommu_ctx * @@ -237,10 +262,13 @@ iommu_instantiate_ctx(struct iommu_unit *unit, device_t dev, bool rmrr) { device_t requester; struct iommu_ctx *ctx; + int error; bool disabled; uint16_t rid; - requester = iommu_get_requester(dev, &rid); + error = iommu_get_requester(dev, &requester, &rid); + if (error != 0) + return (NULL); /* * If the user requested the IOMMU disabled for the device, we diff --git a/sys/dev/iommu/iommu.h b/sys/dev/iommu/iommu.h index b1858f0df9f7..55044042c5d2 100644 --- a/sys/dev/iommu/iommu.h +++ b/sys/dev/iommu/iommu.h @@ -170,7 +170,7 @@ void iommu_domain_unload(struct iommu_domain *domain, void iommu_unit_pre_instantiate_ctx(struct iommu_unit *iommu); struct iommu_ctx *iommu_instantiate_ctx(struct iommu_unit *iommu, device_t dev, bool rmrr); -device_t iommu_get_requester(device_t dev, uint16_t *rid); +int iommu_get_requester(device_t dev, device_t *requester, uint16_t *rid); int iommu_init_busdma(struct iommu_unit *unit); void iommu_fini_busdma(struct iommu_unit *unit); diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c index 62a3da964c37..bf5bda7e058d 100644 --- a/sys/kern/subr_bus.c +++ b/sys/kern/subr_bus.c @@ -280,6 +280,9 @@ device_sysctl_handler(SYSCTL_HANDLER_ARGS) struct sbuf sb; device_t dev = (device_t)arg1; device_t iommu; +#ifdef IOMMU + device_t requester; +#endif int error; uint16_t rid; const char *c; @@ -314,9 +317,15 @@ device_sysctl_handler(SYSCTL_HANDLER_ARGS) } rid = 0; #ifdef IOMMU - iommu_get_requester(dev, &rid); + error = iommu_get_requester(dev, &requester, &rid); + /* + * Do not return requester error from sysctl, iommu + * unit might be assigned by other means. + */ +#else + error = ENXIO; #endif - if (rid != 0) + if (error == 0) sbuf_printf(&sb, "%srid=%#x", c, rid); break; default: diff --git a/sys/x86/iommu/amd_intrmap.c b/sys/x86/iommu/amd_intrmap.c index a4c1a7836268..f8900fe0561f 100644 --- a/sys/x86/iommu/amd_intrmap.c +++ b/sys/x86/iommu/amd_intrmap.c @@ -112,6 +112,8 @@ amdiommu_map_msi_intr(device_t src, u_int cpu, u_int vector, { struct amdiommu_ctx *ctx; struct amdiommu_unit *unit; + device_t requester; + int error __diagused; uint16_t rid; bool is_iommu; @@ -180,7 +182,8 @@ amdiommu_map_msi_intr(device_t src, u_int cpu, u_int vector, *addr |= ((uint64_t)cpu & 0xffffff00) << 32; } - iommu_get_requester(src, &rid); + error = iommu_get_requester(src, &requester, &rid); + MPASS(error == 0); AMDIOMMU_LOCK(unit); amdiommu_qi_invalidate_ir_locked(unit, rid); AMDIOMMU_UNLOCK(unit); @@ -220,6 +223,7 @@ static struct amdiommu_ctx * amdiommu_ir_find(device_t src, uint16_t *ridp, bool *is_iommu) { devclass_t src_class; + device_t requester; struct amdiommu_unit *unit; struct amdiommu_ctx *ctx; uint32_t edte; @@ -251,7 +255,8 @@ amdiommu_ir_find(device_t src, uint16_t *ridp, bool *is_iommu) error = amdiommu_find_unit(src, &unit, &rid, &dte, &edte, bootverbose); if (error == 0) { - iommu_get_requester(src, &rid); + error = iommu_get_requester(src, &requester, &rid); + MPASS(error == 0); ctx = amdiommu_get_ctx_for_dev(unit, src, rid, 0, false /* XXXKIB */, false, dte, edte); } @@ -266,6 +271,8 @@ amdiommu_ir_free_irte(struct amdiommu_ctx *ctx, device_t src, u_int cookie) { struct amdiommu_unit *unit; + device_t requester; + int error __diagused; uint16_t rid; MPASS(ctx != NULL); @@ -291,7 +298,8 @@ amdiommu_ir_free_irte(struct amdiommu_ctx *ctx, device_t src, atomic_thread_fence_rel(); bzero(irte, sizeof(*irte)); } - iommu_get_requester(src, &rid); + error = iommu_get_requester(src, &requester, &rid); + MPASS(error == 0); AMDIOMMU_LOCK(unit); amdiommu_qi_invalidate_ir_locked(unit, rid); AMDIOMMU_UNLOCK(unit); diff --git a/sys/x86/iommu/intel_intrmap.c b/sys/x86/iommu/intel_intrmap.c index 06e41523624b..f12a0c9bae9b 100644 --- a/sys/x86/iommu/intel_intrmap.c +++ b/sys/x86/iommu/intel_intrmap.c @@ -234,6 +234,8 @@ dmar_ir_find(device_t src, uint16_t *rid, int *is_dmar) { devclass_t src_class; struct dmar_unit *unit; + device_t requester; + int error __diagused; /* * We need to determine if the interrupt source generates FSB @@ -253,8 +255,10 @@ dmar_ir_find(device_t src, uint16_t *rid, int *is_dmar) unit = dmar_find_hpet(src, rid); } else { unit = dmar_find(src, bootverbose); - if (unit != NULL && rid != NULL) - iommu_get_requester(src, rid); + if (unit != NULL && rid != NULL) { + error = iommu_get_requester(src, &requester, rid); + MPASS(error == 0); + } } return (unit); }