bus_find_device_by_fwnode() returns a device with its reference count
incremented. vsi_iommu_get_from_dev() drops that reference before
reading the driver data, which leaves the returned pointer derived from
a device after its reference has been released.
Read the driver data before put_device(). Also make
vsi_iommu_probe_device() fail with -ENODEV when the IOMMU cannot be
found instead of dereferencing a NULL pointer.
Signed-off-by: weimin xiong <redacted>
---
drivers/iommu/vsi-iommu.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/iommu/vsi-iommu.c b/drivers/iommu/vsi-iommu.c
index 42c424496..d19db561e 100644
--- a/drivers/iommu/vsi-iommu.c
+++ b/drivers/iommu/vsi-iommu.c
@@ -220,10 +220,15 @@ static struct vsi_iommu *vsi_iommu_get_from_dev(struct device *dev)
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
struct device *iommu_dev = bus_find_device_by_fwnode(&platform_bus_type,
fwspec->iommu_fwnode);
+ struct vsi_iommu *iommu;
+
+ if (!iommu_dev)
+ return NULL;
+ iommu = dev_get_drvdata(iommu_dev);
put_device(iommu_dev);
- return iommu_dev ? dev_get_drvdata(iommu_dev) : NULL;
+ return iommu;
}
static struct iommu_domain *vsi_iommu_domain_alloc_paging(struct device *dev)
@@ -619,6 +624,9 @@ static struct iommu_device *vsi_iommu_probe_device(struct device *dev)
struct vsi_iommu *iommu = vsi_iommu_get_from_dev(dev);
struct device_link *link;
+ if (!iommu)
+ return ERR_PTR(-ENODEV);
+
link = device_link_add(dev, iommu->dev,
DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME);
if (!link)
--
2.43.0