Commit 53d0584e authored by Jason Gunthorpe's avatar Jason Gunthorpe
Browse files

iommufd: WARN if an object is aborted with an elevated refcount

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.

Link: https://patch.msgid.link/r/2-v1-02cd136829df+31-iommufd_syz_fput_jgg@nvidia.com


Reviewed-by: default avatarKevin Tian <kevin.tian@intel.com>
Reviewed-by: default avatarNicolin Chen <nicolinc@nvidia.com>
Tested-by: default avatarNicolin Chen <nicolinc@nvidia.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
parent 4e034bf0
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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");
+1 −2
Original line number Diff line number Diff line
@@ -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;
		}
+4 −0
Original line number Diff line number Diff line
@@ -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);
}