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:
"Four syzkaller found bugs:

- Corruption during error unwind in iommufd_access_change_ioas()

- Overlapping IDs in the test suite due to out of order destruction

- Missing locking for access->ioas in the test suite

- False failures in the test suite validation logic with huge pages"

* tag 'for-linus-iommufd' of git://git.kernel.org/pub/scm/linux/kernel/git/jgg/iommufd:
iommufd/selftest: Don't check map/unmap pairing with HUGE_PAGES
iommufd: Fix protection fault in iommufd_test_syz_conv_iova
iommufd/selftest: Fix mock_dev_num bug
iommufd: Fix iopt_access_list_id overwrite bug

+54 -24
+6 -3
drivers/iommu/iommufd/io_pagetable.c
··· 1330 1330 1331 1331 int iopt_add_access(struct io_pagetable *iopt, struct iommufd_access *access) 1332 1332 { 1333 + u32 new_id; 1333 1334 int rc; 1334 1335 1335 1336 down_write(&iopt->domains_rwsem); 1336 1337 down_write(&iopt->iova_rwsem); 1337 - rc = xa_alloc(&iopt->access_list, &access->iopt_access_list_id, access, 1338 - xa_limit_16b, GFP_KERNEL_ACCOUNT); 1338 + rc = xa_alloc(&iopt->access_list, &new_id, access, xa_limit_16b, 1339 + GFP_KERNEL_ACCOUNT); 1340 + 1339 1341 if (rc) 1340 1342 goto out_unlock; 1341 1343 1342 1344 rc = iopt_calculate_iova_alignment(iopt); 1343 1345 if (rc) { 1344 - xa_erase(&iopt->access_list, access->iopt_access_list_id); 1346 + xa_erase(&iopt->access_list, new_id); 1345 1347 goto out_unlock; 1346 1348 } 1349 + access->iopt_access_list_id = new_id; 1347 1350 1348 1351 out_unlock: 1349 1352 up_write(&iopt->iova_rwsem);
+48 -21
drivers/iommu/iommufd/selftest.c
··· 36 36 }, 37 37 }; 38 38 39 - static atomic_t mock_dev_num; 39 + static DEFINE_IDA(mock_dev_ida); 40 40 41 41 enum { 42 42 MOCK_DIRTY_TRACK = 1, ··· 63 63 * In syzkaller mode the 64 bit IOVA is converted into an nth area and offset 64 64 * value. This has a much smaller randomization space and syzkaller can hit it. 65 65 */ 66 - static unsigned long iommufd_test_syz_conv_iova(struct io_pagetable *iopt, 67 - u64 *iova) 66 + static unsigned long __iommufd_test_syz_conv_iova(struct io_pagetable *iopt, 67 + u64 *iova) 68 68 { 69 69 struct syz_layout { 70 70 __u32 nth_area; ··· 88 88 return 0; 89 89 } 90 90 91 + static unsigned long iommufd_test_syz_conv_iova(struct iommufd_access *access, 92 + u64 *iova) 93 + { 94 + unsigned long ret; 95 + 96 + mutex_lock(&access->ioas_lock); 97 + if (!access->ioas) { 98 + mutex_unlock(&access->ioas_lock); 99 + return 0; 100 + } 101 + ret = __iommufd_test_syz_conv_iova(&access->ioas->iopt, iova); 102 + mutex_unlock(&access->ioas_lock); 103 + return ret; 104 + } 105 + 91 106 void iommufd_test_syz_conv_iova_id(struct iommufd_ucmd *ucmd, 92 107 unsigned int ioas_id, u64 *iova, u32 *flags) 93 108 { ··· 115 100 ioas = iommufd_get_ioas(ucmd->ictx, ioas_id); 116 101 if (IS_ERR(ioas)) 117 102 return; 118 - *iova = iommufd_test_syz_conv_iova(&ioas->iopt, iova); 103 + *iova = __iommufd_test_syz_conv_iova(&ioas->iopt, iova); 119 104 iommufd_put_object(ucmd->ictx, &ioas->obj); 120 105 } 121 106 ··· 138 123 struct mock_dev { 139 124 struct device dev; 140 125 unsigned long flags; 126 + int id; 141 127 }; 142 128 143 129 struct selftest_obj { ··· 446 430 447 431 /* 448 432 * iommufd generates unmaps that must be a strict 449 - * superset of the map's performend So every starting 450 - * IOVA should have been an iova passed to map, and the 433 + * superset of the map's performend So every 434 + * starting/ending IOVA should have been an iova passed 435 + * to map. 451 436 * 452 - * First IOVA must be present and have been a first IOVA 453 - * passed to map_pages 437 + * This simple logic doesn't work when the HUGE_PAGE is 438 + * turned on since the core code will automatically 439 + * switch between the two page sizes creating a break in 440 + * the unmap calls. The break can land in the middle of 441 + * contiguous IOVA. 454 442 */ 455 - if (first) { 456 - WARN_ON(ent && !(xa_to_value(ent) & 457 - MOCK_PFN_START_IOVA)); 458 - first = false; 443 + if (!(domain->pgsize_bitmap & MOCK_HUGE_PAGE_SIZE)) { 444 + if (first) { 445 + WARN_ON(ent && !(xa_to_value(ent) & 446 + MOCK_PFN_START_IOVA)); 447 + first = false; 448 + } 449 + if (pgcount == 1 && 450 + cur + MOCK_IO_PAGE_SIZE == pgsize) 451 + WARN_ON(ent && !(xa_to_value(ent) & 452 + MOCK_PFN_LAST_IOVA)); 459 453 } 460 - if (pgcount == 1 && cur + MOCK_IO_PAGE_SIZE == pgsize) 461 - WARN_ON(ent && !(xa_to_value(ent) & 462 - MOCK_PFN_LAST_IOVA)); 463 454 464 455 iova += MOCK_IO_PAGE_SIZE; 465 456 ret += MOCK_IO_PAGE_SIZE; ··· 654 631 { 655 632 struct mock_dev *mdev = container_of(dev, struct mock_dev, dev); 656 633 657 - atomic_dec(&mock_dev_num); 634 + ida_free(&mock_dev_ida, mdev->id); 658 635 kfree(mdev); 659 636 } 660 637 ··· 676 653 mdev->dev.release = mock_dev_release; 677 654 mdev->dev.bus = &iommufd_mock_bus_type.bus; 678 655 679 - rc = dev_set_name(&mdev->dev, "iommufd_mock%u", 680 - atomic_inc_return(&mock_dev_num)); 656 + rc = ida_alloc(&mock_dev_ida, GFP_KERNEL); 657 + if (rc < 0) 658 + goto err_put; 659 + mdev->id = rc; 660 + 661 + rc = dev_set_name(&mdev->dev, "iommufd_mock%u", mdev->id); 681 662 if (rc) 682 663 goto err_put; 683 664 ··· 1183 1156 } 1184 1157 1185 1158 if (flags & MOCK_FLAGS_ACCESS_SYZ) 1186 - iova = iommufd_test_syz_conv_iova(&staccess->access->ioas->iopt, 1159 + iova = iommufd_test_syz_conv_iova(staccess->access, 1187 1160 &cmd->access_pages.iova); 1188 1161 1189 1162 npages = (ALIGN(iova + length, PAGE_SIZE) - ··· 1285 1258 } 1286 1259 1287 1260 if (flags & MOCK_FLAGS_ACCESS_SYZ) 1288 - iova = iommufd_test_syz_conv_iova(&staccess->access->ioas->iopt, 1289 - &cmd->access_rw.iova); 1261 + iova = iommufd_test_syz_conv_iova(staccess->access, 1262 + &cmd->access_rw.iova); 1290 1263 1291 1264 rc = iommufd_access_rw(staccess->access, iova, tmp, length, flags); 1292 1265 if (rc)