iommu/arm-smmu-v3-sva: Fix mm use-after-free
authorJean-Philippe Brucker <jean-philippe@linaro.org>
Tue, 26 Apr 2022 13:04:45 +0000 (14:04 +0100)
committerWill Deacon <will@kernel.org>
Fri, 6 May 2022 15:25:39 +0000 (16:25 +0100)
We currently call arm64_mm_context_put() without holding a reference to
the mm, which can result in use-after-free. Call mmgrab()/mmdrop() to
ensure the mm only gets freed after we unpinned the ASID.

Fixes: 32784a9562fb ("iommu/arm-smmu-v3: Implement iommu_sva_bind/unbind()")
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Tested-by: Zhangfei Gao <zhangfei.gao@linaro.org>
Link: https://lore.kernel.org/r/20220426130444.300556-1-jean-philippe@linaro.org
Signed-off-by: Will Deacon <will@kernel.org>
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c

index c623dae..1ef7bbb 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/mm.h>
 #include <linux/mmu_context.h>
 #include <linux/mmu_notifier.h>
+#include <linux/sched/mm.h>
 #include <linux/slab.h>
 
 #include "arm-smmu-v3.h"
@@ -96,9 +97,14 @@ static struct arm_smmu_ctx_desc *arm_smmu_alloc_shared_cd(struct mm_struct *mm)
        struct arm_smmu_ctx_desc *cd;
        struct arm_smmu_ctx_desc *ret = NULL;
 
+       /* Don't free the mm until we release the ASID */
+       mmgrab(mm);
+
        asid = arm64_mm_context_get(mm);
-       if (!asid)
-               return ERR_PTR(-ESRCH);
+       if (!asid) {
+               err = -ESRCH;
+               goto out_drop_mm;
+       }
 
        cd = kzalloc(sizeof(*cd), GFP_KERNEL);
        if (!cd) {
@@ -165,6 +171,8 @@ out_free_cd:
        kfree(cd);
 out_put_context:
        arm64_mm_context_put(mm);
+out_drop_mm:
+       mmdrop(mm);
        return err < 0 ? ERR_PTR(err) : ret;
 }
 
@@ -173,6 +181,7 @@ static void arm_smmu_free_shared_cd(struct arm_smmu_ctx_desc *cd)
        if (arm_smmu_free_asid(cd)) {
                /* Unpin ASID */
                arm64_mm_context_put(cd->mm);
+               mmdrop(cd->mm);
                kfree(cd);
        }
 }