[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[patch-4.16] arm/smmuv1,v2: Protect smmu master list with a lock



If a device is added to SMMUv1/v2 from DT and PCI
at the same time, there is a concurrent access
to a smmu master list. This could lead to a
scenario where one is looking into a list that
is being modified at the same time. Add a lock
to prevent this issue.

Reuse the existing spinlock arm_smmu_devices_lock
as it is already protecting find_smmu_master.

ipmmu-smmu and smmuv3 are not impacted by this
issue as there is no access or modification of
a global resource during add_device.

Signed-off-by: Michal Orzel <michal.orzel@xxxxxxx>
---
This patch aims for 4.16 release.
Benefits:
Remove a bug that could lead to a corruption of the
smmu master list, which would be very hard to debug.
Risks:
Overall the risk is low as we are touching init code
rather than a runtime one. In case of any issue, the
problem would be catched during system boot or guest
start.
---
 xen/drivers/passthrough/arm/smmu.c | 25 +++++++++++++++++++------
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/xen/drivers/passthrough/arm/smmu.c 
b/xen/drivers/passthrough/arm/smmu.c
index c9dfc4caa0..be62a66a28 100644
--- a/xen/drivers/passthrough/arm/smmu.c
+++ b/xen/drivers/passthrough/arm/smmu.c
@@ -820,21 +820,25 @@ static int arm_smmu_dt_add_device_legacy(struct 
arm_smmu_device *smmu,
                                         struct device *dev,
                                         struct iommu_fwspec *fwspec)
 {
-       int i;
+       int i, ret;
        struct arm_smmu_master *master;
        struct device_node *dev_node = dev_get_dev_node(dev);
 
+       spin_lock(&arm_smmu_devices_lock);
        master = find_smmu_master(smmu, dev_node);
        if (master) {
                dev_err(dev,
                        "rejecting multiple registrations for master device 
%s\n",
                        dev_node->name);
-               return -EBUSY;
+               ret = -EBUSY;
+               goto out_unlock;
        }
 
        master = devm_kzalloc(dev, sizeof(*master), GFP_KERNEL);
-       if (!master)
-               return -ENOMEM;
+       if (!master) {
+               ret = -ENOMEM;
+               goto out_unlock;
+       }
        master->of_node = dev_node;
 
        /* Xen: Let Xen know that the device is protected by an SMMU */
@@ -846,11 +850,17 @@ static int arm_smmu_dt_add_device_legacy(struct 
arm_smmu_device *smmu,
                        dev_err(dev,
                                "stream ID for master device %s greater than 
maximum allowed (%d)\n",
                                dev_node->name, smmu->num_mapping_groups);
-                       return -ERANGE;
+                       ret = -ERANGE;
+                       goto out_unlock;
                }
                master->cfg.smendx[i] = INVALID_SMENDX;
        }
-       return insert_smmu_master(smmu, master);
+
+       ret = insert_smmu_master(smmu, master);
+
+out_unlock:
+       spin_unlock(&arm_smmu_devices_lock);
+       return ret;
 }
 
 static int register_smmu_master(struct arm_smmu_device *smmu,
@@ -2056,7 +2066,10 @@ static int arm_smmu_add_device(struct device *dev)
        } else {
                struct arm_smmu_master *master;
 
+               spin_lock(&arm_smmu_devices_lock);
                master = find_smmu_master(smmu, dev->of_node);
+               spin_unlock(&arm_smmu_devices_lock);
+
                if (!master) {
                        return -ENODEV;
                }
-- 
2.29.0




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.