Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2490e55f authored by Robin Murphy's avatar Robin Murphy Committed by Srinivasarao Pathipati
Browse files

BACKPORT: iommu: Avoid races around device probe



We currently have 3 different ways that __iommu_probe_device() may be
called, but no real guarantee that multiple callers can't tread on each
other, especially once asynchronous driver probe gets involved. It would
likely have taken a fair bit of luck to hit this previously, but commit
57365a04c921 ("iommu: Move bus setup to IOMMU device registration") ups
the odds since now it's not just omap-iommu that may trigger multiple
bus_iommu_probe() calls in parallel if probing asynchronously.

Add a lock to ensure we can't try to double-probe a device, and also
close some possible race windows to make sure we're truly robust against
trying to double-initialise a group via two different member devices.

Reported-by: default avatarBrian Norris <briannorris@chromium.org>
Signed-off-by: default avatarRobin Murphy <robin.murphy@arm.com>
Tested-by: default avatarBrian Norris <briannorris@chromium.org>
Fixes: 57365a04c921 ("iommu: Move bus setup to IOMMU device registration")
Link: https://lore.kernel.org/r/1946ef9f774851732eed78760a78ec40dbc6d178.1667591503.git.robin.murphy@arm.com


Signed-off-by: default avatarJoerg Roedel <jroedel@suse.de>

Bug: 269232600
(cherry picked from commit 01657bc14a3990c665375f77978631fee77b1fce)
Change-Id: Ie87f8f7a7b90431c3a2682923961885ce7b239f3
Signed-off-by: default avatarZhenhua Huang <quic_zhenhuah@quicinc.com>
Signed-off-by: default avatarSrinivasarao Pathipati <quic_spathi@quicinc.com>
parent 3daec397
Loading
Loading
Loading
Loading
+18 −2
Original line number Diff line number Diff line
@@ -177,14 +177,25 @@ static void iommu_free_dev_param(struct device *dev)
int iommu_probe_device(struct device *dev)
{
	const struct iommu_ops *ops = dev->bus->iommu_ops;
	static DEFINE_MUTEX(iommu_probe_device_lock);
	int ret;

	WARN_ON(dev->iommu_group);
	if (!ops)
		return -EINVAL;

	if (!iommu_get_dev_param(dev))
		return -ENOMEM;
	/*
	 * Serialise to avoid races between IOMMU drivers registering in
	 * parallel and/or the "replay" calls from ACPI/OF code via client
	 * driver probe. Once the latter have been cleaned up we should
	 * probably be able to use device_lock() here to minimise the scope,
	 * but for now enforcing a simple global ordering is fine.
	 */
	mutex_lock(&iommu_probe_device_lock);
	if (!iommu_get_dev_param(dev)) {
		ret = -ENOMEM;
		goto err_unlock;
	}

	if (!try_module_get(ops->owner)) {
		ret = -EINVAL;
@@ -195,12 +206,17 @@ int iommu_probe_device(struct device *dev)
	if (ret)
		goto err_module_put;

	mutex_unlock(&iommu_probe_device_lock);

	return 0;

err_module_put:
	module_put(ops->owner);
err_free_dev_param:
	iommu_free_dev_param(dev);
err_unlock:
	mutex_unlock(&iommu_probe_device_lock);

	return ret;
}