[PATCH RFC 00/17] Solve iommu probe races around iommu_fwspec
Jason Gunthorpe
jgg at nvidia.com
Fri Nov 3 09:44:45 PDT 2023
This is a more complete solution that the first attempt here:
https://lore.kernel.org/r/1698825902-10685-1-git-send-email-quic_zhenhuah@quicinc.com
I haven't been able to test this on any HW that touches these paths, so if
some people with HW can help get it in shape it can become non-RFC.
The iommu subsystem uses dev->iommu to store bits of information about the
attached iommu driver. This has been co-opted by the ACPI/OF code to also
be a place to pass around the iommu_fwspec before a driver is probed.
Since both are using the same pointers without any locking it triggers
races if there is concurrent driver loading:
CPU0 CPU1
of_iommu_configure() iommu_device_register()
.. bus_iommu_probe()
iommu_fwspec_of_xlate() __iommu_probe_device()
iommu_init_device()
dev_iommu_get()
.. ops->probe fails, no fwspec ..
dev_iommu_free()
dev->iommu->fwspec *crash*
My first attempt get correct locking here was to use the device_lock to
protect the entire *_iommu_configure() and iommu_probe() paths. This
allowed safe use of dev->iommu within those paths. Unfortuately enough
drivers abuse the of_iommu_configure() flow without proper locking and
this approach failed.
This approach removes touches of dev->iommu from the *_iommu_configure()
code. The few remaining required touches are moved into iommu.c and
protected with the existing iommu_probe_device_lock.
To do this we change *_iommu_configure() to hold the iommu_fwspec on the
stack while it is being built. Once it is fully formed the core code will
install it into the dev->iommu when it calls probe.
This also removes all the touches of iommu_ops from
the *_iommu_configure() paths and makes that mechanism private to the
iommu core.
A few more lockdep assertions are added to discourage future mis-use.
This is on github: https://github.com/jgunthorpe/linux/commits/iommu_fwspec
Jason Gunthorpe (17):
iommu: Remove struct iommu_ops *iommu from arch_setup_dma_ops()
of: Do not return struct iommu_ops from of_iommu_configure()
of: Use -ENODEV consistently in of_iommu_configure()
acpi: Do not return struct iommu_ops from acpi_iommu_configure_id()
iommu: Make iommu_fwspec->ids a distinct allocation
iommu: Add iommu_fwspec_alloc/dealloc()
iommu: Add iommu_probe_device_fwspec()
of: Do not use dev->iommu within of_iommu_configure()
iommu: Add iommu_fwspec_append_ids()
acpi: Do not use dev->iommu within acpi_iommu_configure()
iommu: Hold iommu_probe_device_lock while calling ops->of_xlate
iommu: Make iommu_ops_from_fwnode() static
iommu: Remove dev_iommu_fwspec_set()
iommu: Remove pointless iommu_fwspec_free()
iommu: Add ops->of_xlate_fwspec()
iommu: Mark dev_iommu_get() with lockdep
iommu: Mark dev_iommu_priv_set() with a lockdep
arch/arc/mm/dma.c | 2 +-
arch/arm/mm/dma-mapping-nommu.c | 2 +-
arch/arm/mm/dma-mapping.c | 10 +-
arch/arm64/mm/dma-mapping.c | 4 +-
arch/mips/mm/dma-noncoherent.c | 2 +-
arch/riscv/mm/dma-noncoherent.c | 2 +-
drivers/acpi/arm64/iort.c | 39 ++--
drivers/acpi/scan.c | 104 +++++----
drivers/acpi/viot.c | 44 ++--
drivers/hv/hv_common.c | 2 +-
drivers/iommu/amd/iommu.c | 2 -
drivers/iommu/apple-dart.c | 1 -
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 9 +-
drivers/iommu/arm/arm-smmu/arm-smmu.c | 23 +-
drivers/iommu/intel/iommu.c | 2 -
drivers/iommu/iommu.c | 227 +++++++++++++++-----
drivers/iommu/of_iommu.c | 129 +++++------
drivers/iommu/omap-iommu.c | 1 -
drivers/iommu/tegra-smmu.c | 1 -
drivers/iommu/virtio-iommu.c | 8 +-
drivers/of/device.c | 24 ++-
include/acpi/acpi_bus.h | 8 +-
include/linux/acpi_iort.h | 3 +-
include/linux/acpi_viot.h | 5 +-
include/linux/dma-map-ops.h | 4 +-
include/linux/iommu.h | 46 ++--
include/linux/of_iommu.h | 13 +-
27 files changed, 417 insertions(+), 300 deletions(-)
base-commit: ab41f1aafb43c2555b358147b14b4d7b8105b452
--
2.42.0
More information about the linux-arm-kernel
mailing list