Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'for-linus-iommufd' of git://git.kernel.org/pub/scm/linux/kernel/git/jgg/iommufd

Pull iommufd fixes from Jason Gunthorpe:
"Fix two user triggerable use-after-free issues:

- Possible race UAF setting up mmaps

- Syzkaller found UAF when erroring an file descriptor creation ioctl
due to the fput() work queue"

* tag 'for-linus-iommufd' of git://git.kernel.org/pub/scm/linux/kernel/git/jgg/iommufd:
iommufd/selftest: Update the fail_nth limit
iommufd: WARN if an object is aborted with an elevated refcount
iommufd: Fix race during abort for file descriptors
iommufd: Fix refcounting race during mmap

+56 -20
+2 -1
drivers/iommu/iommufd/device.c
··· 711 711 iopt_remove_reserved_iova(&hwpt_paging->ioas->iopt, idev->dev); 712 712 mutex_unlock(&igroup->lock); 713 713 714 + iommufd_hw_pagetable_put(idev->ictx, hwpt); 715 + 714 716 /* Caller must destroy hwpt */ 715 717 return hwpt; 716 718 } ··· 1059 1057 hwpt = iommufd_hw_pagetable_detach(idev, pasid); 1060 1058 if (!hwpt) 1061 1059 return; 1062 - iommufd_hw_pagetable_put(idev->ictx, hwpt); 1063 1060 refcount_dec(&idev->obj.users); 1064 1061 } 1065 1062 EXPORT_SYMBOL_NS_GPL(iommufd_device_detach, "IOMMUFD");
+2 -7
drivers/iommu/iommufd/eventq.c
··· 393 393 const struct file_operations *fops) 394 394 { 395 395 struct file *filep; 396 - int fdno; 397 396 398 397 spin_lock_init(&eventq->lock); 399 398 INIT_LIST_HEAD(&eventq->deliver); 400 399 init_waitqueue_head(&eventq->wait_queue); 401 400 401 + /* The filep is fput() by the core code during failure */ 402 402 filep = anon_inode_getfile(name, fops, eventq, O_RDWR); 403 403 if (IS_ERR(filep)) 404 404 return PTR_ERR(filep); ··· 408 408 eventq->filep = filep; 409 409 refcount_inc(&eventq->obj.users); 410 410 411 - fdno = get_unused_fd_flags(O_CLOEXEC); 412 - if (fdno < 0) 413 - fput(filep); 414 - return fdno; 411 + return get_unused_fd_flags(O_CLOEXEC); 415 412 } 416 413 417 414 static const struct file_operations iommufd_fault_fops = ··· 449 452 return 0; 450 453 out_put_fdno: 451 454 put_unused_fd(fdno); 452 - fput(fault->common.filep); 453 455 return rc; 454 456 } 455 457 ··· 532 536 533 537 out_put_fdno: 534 538 put_unused_fd(fdno); 535 - fput(veventq->common.filep); 536 539 out_abort: 537 540 iommufd_object_abort_and_destroy(ucmd->ictx, &veventq->common.obj); 538 541 out_unlock_veventqs:
+1 -2
drivers/iommu/iommufd/iommufd_private.h
··· 454 454 if (hwpt->obj.type == IOMMUFD_OBJ_HWPT_PAGING) { 455 455 struct iommufd_hwpt_paging *hwpt_paging = to_hwpt_paging(hwpt); 456 456 457 - lockdep_assert_not_held(&hwpt_paging->ioas->mutex); 458 - 459 457 if (hwpt_paging->auto_domain) { 458 + lockdep_assert_not_held(&hwpt_paging->ioas->mutex); 460 459 iommufd_object_put_and_try_destroy(ictx, &hwpt->obj); 461 460 return; 462 461 }
+50 -9
drivers/iommu/iommufd/main.c
··· 23 23 #include "iommufd_test.h" 24 24 25 25 struct iommufd_object_ops { 26 + size_t file_offset; 26 27 void (*pre_destroy)(struct iommufd_object *obj); 27 28 void (*destroy)(struct iommufd_object *obj); 28 29 void (*abort)(struct iommufd_object *obj); ··· 122 121 old = xas_store(&xas, NULL); 123 122 xa_unlock(&ictx->objects); 124 123 WARN_ON(old != XA_ZERO_ENTRY); 124 + 125 + if (WARN_ON(!refcount_dec_and_test(&obj->users))) 126 + return; 127 + 125 128 kfree(obj); 126 129 } 127 130 ··· 136 131 void iommufd_object_abort_and_destroy(struct iommufd_ctx *ictx, 137 132 struct iommufd_object *obj) 138 133 { 139 - if (iommufd_object_ops[obj->type].abort) 140 - iommufd_object_ops[obj->type].abort(obj); 134 + const struct iommufd_object_ops *ops = &iommufd_object_ops[obj->type]; 135 + 136 + if (ops->file_offset) { 137 + struct file **filep = ((void *)obj) + ops->file_offset; 138 + 139 + /* 140 + * A file should hold a users refcount while the file is open 141 + * and put it back in its release. The file should hold a 142 + * pointer to obj in their private data. Normal fput() is 143 + * deferred to a workqueue and can get out of order with the 144 + * following kfree(obj). Using the sync version ensures the 145 + * release happens immediately. During abort we require the file 146 + * refcount is one at this point - meaning the object alloc 147 + * function cannot do anything to allow another thread to take a 148 + * refcount prior to a guaranteed success. 149 + */ 150 + if (*filep) 151 + __fput_sync(*filep); 152 + } 153 + 154 + if (ops->abort) 155 + ops->abort(obj); 141 156 else 142 - iommufd_object_ops[obj->type].destroy(obj); 157 + ops->destroy(obj); 143 158 iommufd_object_abort(ictx, obj); 144 159 } 145 160 ··· 575 550 if (vma->vm_flags & VM_EXEC) 576 551 return -EPERM; 577 552 553 + mtree_lock(&ictx->mt_mmap); 578 554 /* vma->vm_pgoff carries a page-shifted start position to an immap */ 579 555 immap = mtree_load(&ictx->mt_mmap, vma->vm_pgoff << PAGE_SHIFT); 580 - if (!immap) 556 + if (!immap || !refcount_inc_not_zero(&immap->owner->users)) { 557 + mtree_unlock(&ictx->mt_mmap); 581 558 return -ENXIO; 559 + } 560 + mtree_unlock(&ictx->mt_mmap); 561 + 582 562 /* 583 563 * mtree_load() returns the immap for any contained mmio_addr, so only 584 564 * allow the exact immap thing to be mapped 585 565 */ 586 - if (vma->vm_pgoff != immap->vm_pgoff || length != immap->length) 587 - return -ENXIO; 566 + if (vma->vm_pgoff != immap->vm_pgoff || length != immap->length) { 567 + rc = -ENXIO; 568 + goto err_refcount; 569 + } 588 570 589 571 vma->vm_pgoff = 0; 590 572 vma->vm_private_data = immap; ··· 602 570 immap->mmio_addr >> PAGE_SHIFT, length, 603 571 vma->vm_page_prot); 604 572 if (rc) 605 - return rc; 573 + goto err_refcount; 574 + return 0; 606 575 607 - /* vm_ops.open won't be called for mmap itself. */ 608 - refcount_inc(&immap->owner->users); 576 + err_refcount: 577 + refcount_dec(&immap->owner->users); 609 578 return rc; 610 579 } 611 580 ··· 684 651 } 685 652 EXPORT_SYMBOL_NS_GPL(iommufd_ctx_put, "IOMMUFD"); 686 653 654 + #define IOMMUFD_FILE_OFFSET(_struct, _filep, _obj) \ 655 + .file_offset = (offsetof(_struct, _filep) + \ 656 + BUILD_BUG_ON_ZERO(!__same_type( \ 657 + struct file *, ((_struct *)NULL)->_filep)) + \ 658 + BUILD_BUG_ON_ZERO(offsetof(_struct, _obj))) 659 + 687 660 static const struct iommufd_object_ops iommufd_object_ops[] = { 688 661 [IOMMUFD_OBJ_ACCESS] = { 689 662 .destroy = iommufd_access_destroy_object, ··· 700 661 }, 701 662 [IOMMUFD_OBJ_FAULT] = { 702 663 .destroy = iommufd_fault_destroy, 664 + IOMMUFD_FILE_OFFSET(struct iommufd_fault, common.filep, common.obj), 703 665 }, 704 666 [IOMMUFD_OBJ_HW_QUEUE] = { 705 667 .destroy = iommufd_hw_queue_destroy, ··· 723 683 [IOMMUFD_OBJ_VEVENTQ] = { 724 684 .destroy = iommufd_veventq_destroy, 725 685 .abort = iommufd_veventq_abort, 686 + IOMMUFD_FILE_OFFSET(struct iommufd_veventq, common.filep, common.obj), 726 687 }, 727 688 [IOMMUFD_OBJ_VIOMMU] = { 728 689 .destroy = iommufd_viommu_destroy,
+1 -1
tools/testing/selftests/iommu/iommufd_fail_nth.c
··· 113 113 * necessarily mean a test failure, just that the limit has to be made 114 114 * bigger. 115 115 */ 116 - ASSERT_GT(400, nth_state->iteration); 116 + ASSERT_GT(1000, nth_state->iteration); 117 117 if (nth_state->iteration != 0) { 118 118 ssize_t res; 119 119 ssize_t res2;