If something holds a refcount then it is at risk of UAFing. For abort
paths we expect the caller to never share the object with a parallel
thread and to clean up any refcounts it obtained on its own.

Add the missing dec inside iommufd_hwpt_paging_alloc()during error unwind
by making iommufd_hw_pagetable_attach/detach() proper pairs.

Signed-off-by: Jason Gunthorpe <[email protected]>
---
 drivers/iommu/iommufd/device.c          | 3 ++-
 drivers/iommu/iommufd/iommufd_private.h | 3 +--
 drivers/iommu/iommufd/main.c            | 4 ++++
 3 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/iommufd/device.c b/drivers/iommu/iommufd/device.c
index 65fbd098f9e98f..4c842368289f08 100644
--- a/drivers/iommu/iommufd/device.c
+++ b/drivers/iommu/iommufd/device.c
@@ -711,6 +711,8 @@ iommufd_hw_pagetable_detach(struct iommufd_device *idev, 
ioasid_t pasid)
                iopt_remove_reserved_iova(&hwpt_paging->ioas->iopt, idev->dev);
        mutex_unlock(&igroup->lock);
 
+       iommufd_hw_pagetable_put(idev->ictx, hwpt);
+
        /* Caller must destroy hwpt */
        return hwpt;
 }
@@ -1057,7 +1059,6 @@ void iommufd_device_detach(struct iommufd_device *idev, 
ioasid_t pasid)
        hwpt = iommufd_hw_pagetable_detach(idev, pasid);
        if (!hwpt)
                return;
-       iommufd_hw_pagetable_put(idev->ictx, hwpt);
        refcount_dec(&idev->obj.users);
 }
 EXPORT_SYMBOL_NS_GPL(iommufd_device_detach, "IOMMUFD");
diff --git a/drivers/iommu/iommufd/iommufd_private.h 
b/drivers/iommu/iommufd/iommufd_private.h
index 0da2a81eedfa8b..627f9b78483a0e 100644
--- a/drivers/iommu/iommufd/iommufd_private.h
+++ b/drivers/iommu/iommufd/iommufd_private.h
@@ -454,9 +454,8 @@ static inline void iommufd_hw_pagetable_put(struct 
iommufd_ctx *ictx,
        if (hwpt->obj.type == IOMMUFD_OBJ_HWPT_PAGING) {
                struct iommufd_hwpt_paging *hwpt_paging = to_hwpt_paging(hwpt);
 
-               lockdep_assert_not_held(&hwpt_paging->ioas->mutex);
-
                if (hwpt_paging->auto_domain) {
+                       lockdep_assert_not_held(&hwpt_paging->ioas->mutex);
                        iommufd_object_put_and_try_destroy(ictx, &hwpt->obj);
                        return;
                }
diff --git a/drivers/iommu/iommufd/main.c b/drivers/iommu/iommufd/main.c
index b8475194279a9a..3454b49cc58dcf 100644
--- a/drivers/iommu/iommufd/main.c
+++ b/drivers/iommu/iommufd/main.c
@@ -122,6 +122,10 @@ void iommufd_object_abort(struct iommufd_ctx *ictx, struct 
iommufd_object *obj)
        old = xas_store(&xas, NULL);
        xa_unlock(&ictx->objects);
        WARN_ON(old != XA_ZERO_ENTRY);
+
+       if (WARN_ON(!refcount_dec_and_test(&obj->users)))
+               return;
+
        kfree(obj);
 }
 
-- 
2.43.0


Reply via email to