mirror of
https://github.com/torvalds/linux.git
synced 2026-05-23 22:52:19 +02:00
iommufd: Fix refcounting race during mmap
The owner object of the imap can be destroyed while the imap remains in
the mtree. So access to the imap pointer without holding locks is racy
with destruction.
The imap is safe to access outside the lock once a users refcount is
obtained, the owner object cannot start destruction until users is 0.
Thus the users refcount should not be obtained at the end of
iommufd_fops_mmap() but instead inside the mtree lock held around the
mtree_load(). Move the refcount there and use refcount_inc_not_zero() as
we can have a 0 refcount inside the mtree during destruction races.
Link: https://patch.msgid.link/r/0-v1-e6faace50971+3cc-iommufd_mmap_fix_jgg@nvidia.com
Cc: stable@vger.kernel.org
Fixes: 56e9a0d8e5 ("iommufd: Add mmap interface")
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
This commit is contained in:
parent
f83ec76bf2
commit
7a425ec75d
|
|
@ -550,16 +550,23 @@ static int iommufd_fops_mmap(struct file *filp, struct vm_area_struct *vma)
|
|||
if (vma->vm_flags & VM_EXEC)
|
||||
return -EPERM;
|
||||
|
||||
mtree_lock(&ictx->mt_mmap);
|
||||
/* vma->vm_pgoff carries a page-shifted start position to an immap */
|
||||
immap = mtree_load(&ictx->mt_mmap, vma->vm_pgoff << PAGE_SHIFT);
|
||||
if (!immap)
|
||||
if (!immap || !refcount_inc_not_zero(&immap->owner->users)) {
|
||||
mtree_unlock(&ictx->mt_mmap);
|
||||
return -ENXIO;
|
||||
}
|
||||
mtree_unlock(&ictx->mt_mmap);
|
||||
|
||||
/*
|
||||
* mtree_load() returns the immap for any contained mmio_addr, so only
|
||||
* allow the exact immap thing to be mapped
|
||||
*/
|
||||
if (vma->vm_pgoff != immap->vm_pgoff || length != immap->length)
|
||||
return -ENXIO;
|
||||
if (vma->vm_pgoff != immap->vm_pgoff || length != immap->length) {
|
||||
rc = -ENXIO;
|
||||
goto err_refcount;
|
||||
}
|
||||
|
||||
vma->vm_pgoff = 0;
|
||||
vma->vm_private_data = immap;
|
||||
|
|
@ -570,10 +577,11 @@ static int iommufd_fops_mmap(struct file *filp, struct vm_area_struct *vma)
|
|||
immap->mmio_addr >> PAGE_SHIFT, length,
|
||||
vma->vm_page_prot);
|
||||
if (rc)
|
||||
return rc;
|
||||
goto err_refcount;
|
||||
return 0;
|
||||
|
||||
/* vm_ops.open won't be called for mmap itself. */
|
||||
refcount_inc(&immap->owner->users);
|
||||
err_refcount:
|
||||
refcount_dec(&immap->owner->users);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user