2323#include "iommufd_test.h"
2424
2525struct iommufd_object_ops {
26+ size_t file_offset ;
2627 void (* pre_destroy )(struct iommufd_object * obj );
2728 void (* destroy )(struct iommufd_object * obj );
2829 void (* abort )(struct iommufd_object * obj );
@@ -121,6 +122,10 @@ void iommufd_object_abort(struct iommufd_ctx *ictx, struct iommufd_object *obj)
121122 old = xas_store (& xas , NULL );
122123 xa_unlock (& ictx -> objects );
123124 WARN_ON (old != XA_ZERO_ENTRY );
125+
126+ if (WARN_ON (!refcount_dec_and_test (& obj -> users )))
127+ return ;
128+
124129 kfree (obj );
125130}
126131
@@ -131,10 +136,30 @@ void iommufd_object_abort(struct iommufd_ctx *ictx, struct iommufd_object *obj)
131136void iommufd_object_abort_and_destroy (struct iommufd_ctx * ictx ,
132137 struct iommufd_object * obj )
133138{
134- if (iommufd_object_ops [obj -> type ].abort )
135- iommufd_object_ops [obj -> type ].abort (obj );
139+ const struct iommufd_object_ops * ops = & iommufd_object_ops [obj -> type ];
140+
141+ if (ops -> file_offset ) {
142+ struct file * * filep = ((void * )obj ) + ops -> file_offset ;
143+
144+ /*
145+ * A file should hold a users refcount while the file is open
146+ * and put it back in its release. The file should hold a
147+ * pointer to obj in their private data. Normal fput() is
148+ * deferred to a workqueue and can get out of order with the
149+ * following kfree(obj). Using the sync version ensures the
150+ * release happens immediately. During abort we require the file
151+ * refcount is one at this point - meaning the object alloc
152+ * function cannot do anything to allow another thread to take a
153+ * refcount prior to a guaranteed success.
154+ */
155+ if (* filep )
156+ __fput_sync (* filep );
157+ }
158+
159+ if (ops -> abort )
160+ ops -> abort (obj );
136161 else
137- iommufd_object_ops [ obj -> type ]. destroy (obj );
162+ ops -> destroy (obj );
138163 iommufd_object_abort (ictx , obj );
139164}
140165
@@ -550,16 +575,23 @@ static int iommufd_fops_mmap(struct file *filp, struct vm_area_struct *vma)
550575 if (vma -> vm_flags & VM_EXEC )
551576 return - EPERM ;
552577
578+ mtree_lock (& ictx -> mt_mmap );
553579 /* vma->vm_pgoff carries a page-shifted start position to an immap */
554580 immap = mtree_load (& ictx -> mt_mmap , vma -> vm_pgoff << PAGE_SHIFT );
555- if (!immap )
581+ if (!immap || !refcount_inc_not_zero (& immap -> owner -> users )) {
582+ mtree_unlock (& ictx -> mt_mmap );
556583 return - ENXIO ;
584+ }
585+ mtree_unlock (& ictx -> mt_mmap );
586+
557587 /*
558588 * mtree_load() returns the immap for any contained mmio_addr, so only
559589 * allow the exact immap thing to be mapped
560590 */
561- if (vma -> vm_pgoff != immap -> vm_pgoff || length != immap -> length )
562- return - ENXIO ;
591+ if (vma -> vm_pgoff != immap -> vm_pgoff || length != immap -> length ) {
592+ rc = - ENXIO ;
593+ goto err_refcount ;
594+ }
563595
564596 vma -> vm_pgoff = 0 ;
565597 vma -> vm_private_data = immap ;
@@ -570,10 +602,11 @@ static int iommufd_fops_mmap(struct file *filp, struct vm_area_struct *vma)
570602 immap -> mmio_addr >> PAGE_SHIFT , length ,
571603 vma -> vm_page_prot );
572604 if (rc )
573- return rc ;
605+ goto err_refcount ;
606+ return 0 ;
574607
575- /* vm_ops.open won't be called for mmap itself. */
576- refcount_inc (& immap -> owner -> users );
608+ err_refcount :
609+ refcount_dec (& immap -> owner -> users );
577610 return rc ;
578611}
579612
@@ -651,6 +684,12 @@ void iommufd_ctx_put(struct iommufd_ctx *ictx)
651684}
652685EXPORT_SYMBOL_NS_GPL (iommufd_ctx_put , "IOMMUFD" );
653686
687+ #define IOMMUFD_FILE_OFFSET (_struct , _filep , _obj ) \
688+ .file_offset = (offsetof(_struct, _filep) + \
689+ BUILD_BUG_ON_ZERO(!__same_type( \
690+ struct file *, ((_struct *)NULL)->_filep)) + \
691+ BUILD_BUG_ON_ZERO(offsetof(_struct, _obj)))
692+
654693static const struct iommufd_object_ops iommufd_object_ops [] = {
655694 [IOMMUFD_OBJ_ACCESS ] = {
656695 .destroy = iommufd_access_destroy_object ,
@@ -661,6 +700,7 @@ static const struct iommufd_object_ops iommufd_object_ops[] = {
661700 },
662701 [IOMMUFD_OBJ_FAULT ] = {
663702 .destroy = iommufd_fault_destroy ,
703+ IOMMUFD_FILE_OFFSET (struct iommufd_fault , common .filep , common .obj ),
664704 },
665705 [IOMMUFD_OBJ_HW_QUEUE ] = {
666706 .destroy = iommufd_hw_queue_destroy ,
@@ -683,6 +723,7 @@ static const struct iommufd_object_ops iommufd_object_ops[] = {
683723 [IOMMUFD_OBJ_VEVENTQ ] = {
684724 .destroy = iommufd_veventq_destroy ,
685725 .abort = iommufd_veventq_abort ,
726+ IOMMUFD_FILE_OFFSET (struct iommufd_veventq , common .filep , common .obj ),
686727 },
687728 [IOMMUFD_OBJ_VIOMMU ] = {
688729 .destroy = iommufd_viommu_destroy ,
0 commit comments