]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
iommu/qcom: Fix bogus detach logic
authorRobin Murphy <robin.murphy@arm.com>
Tue, 18 Feb 2020 18:12:41 +0000 (18:12 +0000)
committerKleber Sacilotto de Souza <kleber.souza@canonical.com>
Tue, 7 Apr 2020 08:49:44 +0000 (10:49 +0200)
BugLink: https://bugs.launchpad.net/bugs/1867837
commit faf305c51aeabd1ea2d7131e798ef5f55f4a7750 upstream.

Currently, the implementation of qcom_iommu_domain_free() is guaranteed
to do one of two things: WARN() and leak everything, or dereference NULL
and crash. That alone is terrible, but in fact the whole idea of trying
to track the liveness of a domain via the qcom_domain->iommu pointer as
a sanity check is full of fundamentally flawed assumptions. Make things
robust and actually functional by not trying to be quite so clever.

Reported-by: Brian Masney <masneyb@onstation.org>
Tested-by: Brian Masney <masneyb@onstation.org>
Reported-by: Naresh Kamboju <naresh.kamboju@linaro.org>
Fixes: 0ae349a0f33f ("iommu/qcom: Add qcom_iommu")
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Tested-by: Stephan Gerhold <stephan@gerhold.net>
Cc: stable@vger.kernel.org # v4.14+
Signed-off-by: Joerg Roedel <jroedel@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com>
drivers/iommu/qcom_iommu.c

index e07f02d00c688f0b604c71f6531d83dc43a94ee2..780ee8c0cb65ba5f5be72b7751be249fbfa401da 100644 (file)
@@ -333,21 +333,19 @@ static void qcom_iommu_domain_free(struct iommu_domain *domain)
 {
        struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain);
 
-       if (WARN_ON(qcom_domain->iommu))    /* forgot to detach? */
-               return;
-
        iommu_put_dma_cookie(domain);
 
-       /* NOTE: unmap can be called after client device is powered off,
-        * for example, with GPUs or anything involving dma-buf.  So we
-        * cannot rely on the device_link.  Make sure the IOMMU is on to
-        * avoid unclocked accesses in the TLB inv path:
-        */
-       pm_runtime_get_sync(qcom_domain->iommu->dev);
-
-       free_io_pgtable_ops(qcom_domain->pgtbl_ops);
-
-       pm_runtime_put_sync(qcom_domain->iommu->dev);
+       if (qcom_domain->iommu) {
+               /*
+                * NOTE: unmap can be called after client device is powered
+                * off, for example, with GPUs or anything involving dma-buf.
+                * So we cannot rely on the device_link.  Make sure the IOMMU
+                * is on to avoid unclocked accesses in the TLB inv path:
+                */
+               pm_runtime_get_sync(qcom_domain->iommu->dev);
+               free_io_pgtable_ops(qcom_domain->pgtbl_ops);
+               pm_runtime_put_sync(qcom_domain->iommu->dev);
+       }
 
        kfree(qcom_domain);
 }
@@ -392,7 +390,7 @@ static void qcom_iommu_detach_dev(struct iommu_domain *domain, struct device *de
        struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain);
        unsigned i;
 
-       if (!qcom_domain->iommu)
+       if (WARN_ON(!qcom_domain->iommu))
                return;
 
        pm_runtime_get_sync(qcom_iommu->dev);
@@ -405,8 +403,6 @@ static void qcom_iommu_detach_dev(struct iommu_domain *domain, struct device *de
                ctx->domain = NULL;
        }
        pm_runtime_put_sync(qcom_iommu->dev);
-
-       qcom_domain->iommu = NULL;
 }
 
 static int qcom_iommu_map(struct iommu_domain *domain, unsigned long iova,