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 'vfio-v6.18-rc4' of https://github.com/awilliam/linux-vfio

Pull VFIO fixes from Alex Williamson:

- Fix overflows in vfio type1 backend for mappings at the end of the
64-bit address space, resulting in leaked pinned memory.

New selftest support included to avoid such issues in the future
(Alex Mastro)

* tag 'vfio-v6.18-rc4' of https://github.com/awilliam/linux-vfio:
vfio: selftests: add end of address space DMA map/unmap tests
vfio: selftests: update DMA map/unmap helpers to support more test kinds
vfio/type1: handle DMA map/unmap up to the addressable limit
vfio/type1: move iova increment to unmap_unpin_*() caller
vfio/type1: sanitize for overflow using check_*_overflow()

+310 -93
+110 -63
drivers/vfio/vfio_iommu_type1.c
··· 38 38 #include <linux/workqueue.h> 39 39 #include <linux/notifier.h> 40 40 #include <linux/mm_inline.h> 41 + #include <linux/overflow.h> 41 42 #include "vfio.h" 42 43 43 44 #define DRIVER_VERSION "0.2" ··· 168 167 { 169 168 struct rb_node *node = iommu->dma_list.rb_node; 170 169 170 + WARN_ON(!size); 171 + 171 172 while (node) { 172 173 struct vfio_dma *dma = rb_entry(node, struct vfio_dma, node); 173 174 174 - if (start + size <= dma->iova) 175 + if (start + size - 1 < dma->iova) 175 176 node = node->rb_left; 176 - else if (start >= dma->iova + dma->size) 177 + else if (start > dma->iova + dma->size - 1) 177 178 node = node->rb_right; 178 179 else 179 180 return dma; ··· 185 182 } 186 183 187 184 static struct rb_node *vfio_find_dma_first_node(struct vfio_iommu *iommu, 188 - dma_addr_t start, u64 size) 185 + dma_addr_t start, 186 + dma_addr_t end) 189 187 { 190 188 struct rb_node *res = NULL; 191 189 struct rb_node *node = iommu->dma_list.rb_node; 192 190 struct vfio_dma *dma_res = NULL; 193 191 192 + WARN_ON(end < start); 193 + 194 194 while (node) { 195 195 struct vfio_dma *dma = rb_entry(node, struct vfio_dma, node); 196 196 197 - if (start < dma->iova + dma->size) { 197 + if (start <= dma->iova + dma->size - 1) { 198 198 res = node; 199 199 dma_res = dma; 200 200 if (start >= dma->iova) ··· 207 201 node = node->rb_right; 208 202 } 209 203 } 210 - if (res && size && dma_res->iova >= start + size) 204 + if (res && dma_res->iova > end) 211 205 res = NULL; 212 206 return res; 213 207 } ··· 217 211 struct rb_node **link = &iommu->dma_list.rb_node, *parent = NULL; 218 212 struct vfio_dma *dma; 219 213 214 + WARN_ON(new->size != 0); 215 + 220 216 while (*link) { 221 217 parent = *link; 222 218 dma = rb_entry(parent, struct vfio_dma, node); 223 219 224 - if (new->iova + new->size <= dma->iova) 220 + if (new->iova <= dma->iova) 225 221 link = &(*link)->rb_left; 226 222 else 227 223 link = &(*link)->rb_right; ··· 903 895 unsigned long remote_vaddr; 904 896 struct vfio_dma *dma; 905 897 bool do_accounting; 898 + dma_addr_t iova_end; 899 + size_t iova_size; 906 900 907 - if (!iommu || !pages) 901 + if (!iommu || !pages || npage <= 0) 908 902 return -EINVAL; 909 903 910 904 /* Supported for v2 version only */ 911 905 if (!iommu->v2) 912 906 return -EACCES; 907 + 908 + if (check_mul_overflow(npage, PAGE_SIZE, &iova_size) || 909 + check_add_overflow(user_iova, iova_size - 1, &iova_end)) 910 + return -EOVERFLOW; 913 911 914 912 mutex_lock(&iommu->lock); 915 913 ··· 1022 1008 { 1023 1009 struct vfio_iommu *iommu = iommu_data; 1024 1010 bool do_accounting; 1011 + dma_addr_t iova_end; 1012 + size_t iova_size; 1025 1013 int i; 1026 1014 1027 1015 /* Supported for v2 version only */ 1028 1016 if (WARN_ON(!iommu->v2)) 1017 + return; 1018 + 1019 + if (WARN_ON(npage <= 0)) 1020 + return; 1021 + 1022 + if (WARN_ON(check_mul_overflow(npage, PAGE_SIZE, &iova_size) || 1023 + check_add_overflow(user_iova, iova_size - 1, &iova_end))) 1029 1024 return; 1030 1025 1031 1026 mutex_lock(&iommu->lock); ··· 1090 1067 #define VFIO_IOMMU_TLB_SYNC_MAX 512 1091 1068 1092 1069 static size_t unmap_unpin_fast(struct vfio_domain *domain, 1093 - struct vfio_dma *dma, dma_addr_t *iova, 1070 + struct vfio_dma *dma, dma_addr_t iova, 1094 1071 size_t len, phys_addr_t phys, long *unlocked, 1095 1072 struct list_head *unmapped_list, 1096 1073 int *unmapped_cnt, ··· 1100 1077 struct vfio_regions *entry = kzalloc(sizeof(*entry), GFP_KERNEL); 1101 1078 1102 1079 if (entry) { 1103 - unmapped = iommu_unmap_fast(domain->domain, *iova, len, 1080 + unmapped = iommu_unmap_fast(domain->domain, iova, len, 1104 1081 iotlb_gather); 1105 1082 1106 1083 if (!unmapped) { 1107 1084 kfree(entry); 1108 1085 } else { 1109 - entry->iova = *iova; 1086 + entry->iova = iova; 1110 1087 entry->phys = phys; 1111 1088 entry->len = unmapped; 1112 1089 list_add_tail(&entry->list, unmapped_list); 1113 1090 1114 - *iova += unmapped; 1115 1091 (*unmapped_cnt)++; 1116 1092 } 1117 1093 } ··· 1129 1107 } 1130 1108 1131 1109 static size_t unmap_unpin_slow(struct vfio_domain *domain, 1132 - struct vfio_dma *dma, dma_addr_t *iova, 1110 + struct vfio_dma *dma, dma_addr_t iova, 1133 1111 size_t len, phys_addr_t phys, 1134 1112 long *unlocked) 1135 1113 { 1136 - size_t unmapped = iommu_unmap(domain->domain, *iova, len); 1114 + size_t unmapped = iommu_unmap(domain->domain, iova, len); 1137 1115 1138 1116 if (unmapped) { 1139 - *unlocked += vfio_unpin_pages_remote(dma, *iova, 1117 + *unlocked += vfio_unpin_pages_remote(dma, iova, 1140 1118 phys >> PAGE_SHIFT, 1141 1119 unmapped >> PAGE_SHIFT, 1142 1120 false); 1143 - *iova += unmapped; 1144 1121 cond_resched(); 1145 1122 } 1146 1123 return unmapped; ··· 1148 1127 static long vfio_unmap_unpin(struct vfio_iommu *iommu, struct vfio_dma *dma, 1149 1128 bool do_accounting) 1150 1129 { 1151 - dma_addr_t iova = dma->iova, end = dma->iova + dma->size; 1152 1130 struct vfio_domain *domain, *d; 1153 1131 LIST_HEAD(unmapped_region_list); 1154 1132 struct iommu_iotlb_gather iotlb_gather; 1155 1133 int unmapped_region_cnt = 0; 1156 1134 long unlocked = 0; 1135 + size_t pos = 0; 1157 1136 1158 1137 if (!dma->size) 1159 1138 return 0; ··· 1177 1156 } 1178 1157 1179 1158 iommu_iotlb_gather_init(&iotlb_gather); 1180 - while (iova < end) { 1159 + while (pos < dma->size) { 1181 1160 size_t unmapped, len; 1182 1161 phys_addr_t phys, next; 1162 + dma_addr_t iova = dma->iova + pos; 1183 1163 1184 1164 phys = iommu_iova_to_phys(domain->domain, iova); 1185 1165 if (WARN_ON(!phys)) { 1186 - iova += PAGE_SIZE; 1166 + pos += PAGE_SIZE; 1187 1167 continue; 1188 1168 } 1189 1169 ··· 1193 1171 * may require hardware cache flushing, try to find the 1194 1172 * largest contiguous physical memory chunk to unmap. 1195 1173 */ 1196 - for (len = PAGE_SIZE; iova + len < end; len += PAGE_SIZE) { 1174 + for (len = PAGE_SIZE; pos + len < dma->size; len += PAGE_SIZE) { 1197 1175 next = iommu_iova_to_phys(domain->domain, iova + len); 1198 1176 if (next != phys + len) 1199 1177 break; ··· 1203 1181 * First, try to use fast unmap/unpin. In case of failure, 1204 1182 * switch to slow unmap/unpin path. 1205 1183 */ 1206 - unmapped = unmap_unpin_fast(domain, dma, &iova, len, phys, 1184 + unmapped = unmap_unpin_fast(domain, dma, iova, len, phys, 1207 1185 &unlocked, &unmapped_region_list, 1208 1186 &unmapped_region_cnt, 1209 1187 &iotlb_gather); 1210 1188 if (!unmapped) { 1211 - unmapped = unmap_unpin_slow(domain, dma, &iova, len, 1189 + unmapped = unmap_unpin_slow(domain, dma, iova, len, 1212 1190 phys, &unlocked); 1213 1191 if (WARN_ON(!unmapped)) 1214 1192 break; 1215 1193 } 1194 + 1195 + pos += unmapped; 1216 1196 } 1217 1197 1218 1198 dma->iommu_mapped = false; ··· 1306 1282 } 1307 1283 1308 1284 static int vfio_iova_dirty_bitmap(u64 __user *bitmap, struct vfio_iommu *iommu, 1309 - dma_addr_t iova, size_t size, size_t pgsize) 1285 + dma_addr_t iova, dma_addr_t iova_end, size_t pgsize) 1310 1286 { 1311 1287 struct vfio_dma *dma; 1312 1288 struct rb_node *n; ··· 1323 1299 if (dma && dma->iova != iova) 1324 1300 return -EINVAL; 1325 1301 1326 - dma = vfio_find_dma(iommu, iova + size - 1, 0); 1327 - if (dma && dma->iova + dma->size != iova + size) 1302 + dma = vfio_find_dma(iommu, iova_end, 1); 1303 + if (dma && dma->iova + dma->size - 1 != iova_end) 1328 1304 return -EINVAL; 1329 1305 1330 1306 for (n = rb_first(&iommu->dma_list); n; n = rb_next(n)) { ··· 1333 1309 if (dma->iova < iova) 1334 1310 continue; 1335 1311 1336 - if (dma->iova > iova + size - 1) 1312 + if (dma->iova > iova_end) 1337 1313 break; 1338 1314 1339 1315 ret = update_user_bitmap(bitmap, iommu, dma, iova, pgsize); ··· 1398 1374 int ret = -EINVAL, retries = 0; 1399 1375 unsigned long pgshift; 1400 1376 dma_addr_t iova = unmap->iova; 1401 - u64 size = unmap->size; 1377 + dma_addr_t iova_end; 1378 + size_t size = unmap->size; 1402 1379 bool unmap_all = unmap->flags & VFIO_DMA_UNMAP_FLAG_ALL; 1403 1380 bool invalidate_vaddr = unmap->flags & VFIO_DMA_UNMAP_FLAG_VADDR; 1404 1381 struct rb_node *n, *first_n; ··· 1412 1387 goto unlock; 1413 1388 } 1414 1389 1390 + if (iova != unmap->iova || size != unmap->size) { 1391 + ret = -EOVERFLOW; 1392 + goto unlock; 1393 + } 1394 + 1415 1395 pgshift = __ffs(iommu->pgsize_bitmap); 1416 1396 pgsize = (size_t)1 << pgshift; 1417 1397 ··· 1426 1396 if (unmap_all) { 1427 1397 if (iova || size) 1428 1398 goto unlock; 1429 - size = U64_MAX; 1430 - } else if (!size || size & (pgsize - 1) || 1431 - iova + size - 1 < iova || size > SIZE_MAX) { 1432 - goto unlock; 1399 + iova_end = ~(dma_addr_t)0; 1400 + } else { 1401 + if (!size || size & (pgsize - 1)) 1402 + goto unlock; 1403 + 1404 + if (check_add_overflow(iova, size - 1, &iova_end)) { 1405 + ret = -EOVERFLOW; 1406 + goto unlock; 1407 + } 1433 1408 } 1434 1409 1435 1410 /* When dirty tracking is enabled, allow only min supported pgsize */ ··· 1481 1446 if (dma && dma->iova != iova) 1482 1447 goto unlock; 1483 1448 1484 - dma = vfio_find_dma(iommu, iova + size - 1, 0); 1485 - if (dma && dma->iova + dma->size != iova + size) 1449 + dma = vfio_find_dma(iommu, iova_end, 1); 1450 + if (dma && dma->iova + dma->size - 1 != iova_end) 1486 1451 goto unlock; 1487 1452 } 1488 1453 1489 1454 ret = 0; 1490 - n = first_n = vfio_find_dma_first_node(iommu, iova, size); 1455 + n = first_n = vfio_find_dma_first_node(iommu, iova, iova_end); 1491 1456 1492 1457 while (n) { 1493 1458 dma = rb_entry(n, struct vfio_dma, node); 1494 - if (dma->iova >= iova + size) 1459 + if (dma->iova > iova_end) 1495 1460 break; 1496 1461 1497 1462 if (!iommu->v2 && iova > dma->iova) ··· 1683 1648 { 1684 1649 bool set_vaddr = map->flags & VFIO_DMA_MAP_FLAG_VADDR; 1685 1650 dma_addr_t iova = map->iova; 1651 + dma_addr_t iova_end; 1686 1652 unsigned long vaddr = map->vaddr; 1653 + unsigned long vaddr_end; 1687 1654 size_t size = map->size; 1688 1655 int ret = 0, prot = 0; 1689 1656 size_t pgsize; ··· 1693 1656 1694 1657 /* Verify that none of our __u64 fields overflow */ 1695 1658 if (map->size != size || map->vaddr != vaddr || map->iova != iova) 1659 + return -EOVERFLOW; 1660 + 1661 + if (!size) 1696 1662 return -EINVAL; 1663 + 1664 + if (check_add_overflow(iova, size - 1, &iova_end) || 1665 + check_add_overflow(vaddr, size - 1, &vaddr_end)) 1666 + return -EOVERFLOW; 1697 1667 1698 1668 /* READ/WRITE from device perspective */ 1699 1669 if (map->flags & VFIO_DMA_MAP_FLAG_WRITE) ··· 1717 1673 1718 1674 WARN_ON((pgsize - 1) & PAGE_MASK); 1719 1675 1720 - if (!size || (size | iova | vaddr) & (pgsize - 1)) { 1721 - ret = -EINVAL; 1722 - goto out_unlock; 1723 - } 1724 - 1725 - /* Don't allow IOVA or virtual address wrap */ 1726 - if (iova + size - 1 < iova || vaddr + size - 1 < vaddr) { 1676 + if ((size | iova | vaddr) & (pgsize - 1)) { 1727 1677 ret = -EINVAL; 1728 1678 goto out_unlock; 1729 1679 } ··· 1748 1710 goto out_unlock; 1749 1711 } 1750 1712 1751 - if (!vfio_iommu_iova_dma_valid(iommu, iova, iova + size - 1)) { 1713 + if (!vfio_iommu_iova_dma_valid(iommu, iova, iova_end)) { 1752 1714 ret = -EINVAL; 1753 1715 goto out_unlock; 1754 1716 } ··· 1821 1783 1822 1784 for (; n; n = rb_next(n)) { 1823 1785 struct vfio_dma *dma; 1824 - dma_addr_t iova; 1786 + size_t pos = 0; 1825 1787 1826 1788 dma = rb_entry(n, struct vfio_dma, node); 1827 - iova = dma->iova; 1828 1789 1829 - while (iova < dma->iova + dma->size) { 1790 + while (pos < dma->size) { 1791 + dma_addr_t iova = dma->iova + pos; 1830 1792 phys_addr_t phys; 1831 1793 size_t size; 1832 1794 ··· 1842 1804 phys = iommu_iova_to_phys(d->domain, iova); 1843 1805 1844 1806 if (WARN_ON(!phys)) { 1845 - iova += PAGE_SIZE; 1807 + pos += PAGE_SIZE; 1846 1808 continue; 1847 1809 } 1848 1810 1849 1811 size = PAGE_SIZE; 1850 1812 p = phys + size; 1851 1813 i = iova + size; 1852 - while (i < dma->iova + dma->size && 1814 + while (pos + size < dma->size && 1853 1815 p == iommu_iova_to_phys(d->domain, i)) { 1854 1816 size += PAGE_SIZE; 1855 1817 p += PAGE_SIZE; ··· 1857 1819 } 1858 1820 } else { 1859 1821 unsigned long pfn; 1860 - unsigned long vaddr = dma->vaddr + 1861 - (iova - dma->iova); 1862 - size_t n = dma->iova + dma->size - iova; 1822 + unsigned long vaddr = dma->vaddr + pos; 1823 + size_t n = dma->size - pos; 1863 1824 long npage; 1864 1825 1865 1826 npage = vfio_pin_pages_remote(dma, vaddr, ··· 1889 1852 goto unwind; 1890 1853 } 1891 1854 1892 - iova += size; 1855 + pos += size; 1893 1856 } 1894 1857 } 1895 1858 ··· 1906 1869 unwind: 1907 1870 for (; n; n = rb_prev(n)) { 1908 1871 struct vfio_dma *dma = rb_entry(n, struct vfio_dma, node); 1909 - dma_addr_t iova; 1872 + size_t pos = 0; 1910 1873 1911 1874 if (dma->iommu_mapped) { 1912 1875 iommu_unmap(domain->domain, dma->iova, dma->size); 1913 1876 continue; 1914 1877 } 1915 1878 1916 - iova = dma->iova; 1917 - while (iova < dma->iova + dma->size) { 1879 + while (pos < dma->size) { 1880 + dma_addr_t iova = dma->iova + pos; 1918 1881 phys_addr_t phys, p; 1919 1882 size_t size; 1920 1883 dma_addr_t i; 1921 1884 1922 1885 phys = iommu_iova_to_phys(domain->domain, iova); 1923 1886 if (!phys) { 1924 - iova += PAGE_SIZE; 1887 + pos += PAGE_SIZE; 1925 1888 continue; 1926 1889 } 1927 1890 1928 1891 size = PAGE_SIZE; 1929 1892 p = phys + size; 1930 1893 i = iova + size; 1931 - while (i < dma->iova + dma->size && 1894 + while (pos + size < dma->size && 1932 1895 p == iommu_iova_to_phys(domain->domain, i)) { 1933 1896 size += PAGE_SIZE; 1934 1897 p += PAGE_SIZE; ··· 3014 2977 struct vfio_iommu_type1_dirty_bitmap_get range; 3015 2978 unsigned long pgshift; 3016 2979 size_t data_size = dirty.argsz - minsz; 3017 - size_t iommu_pgsize; 2980 + size_t size, iommu_pgsize; 2981 + dma_addr_t iova, iova_end; 3018 2982 3019 2983 if (!data_size || data_size < sizeof(range)) 3020 2984 return -EINVAL; ··· 3024 2986 sizeof(range))) 3025 2987 return -EFAULT; 3026 2988 3027 - if (range.iova + range.size < range.iova) 2989 + iova = range.iova; 2990 + size = range.size; 2991 + 2992 + if (iova != range.iova || size != range.size) 2993 + return -EOVERFLOW; 2994 + 2995 + if (!size) 3028 2996 return -EINVAL; 2997 + 2998 + if (check_add_overflow(iova, size - 1, &iova_end)) 2999 + return -EOVERFLOW; 3000 + 3029 3001 if (!access_ok((void __user *)range.bitmap.data, 3030 3002 range.bitmap.size)) 3031 3003 return -EINVAL; 3032 3004 3033 3005 pgshift = __ffs(range.bitmap.pgsize); 3034 - ret = verify_bitmap_size(range.size >> pgshift, 3006 + ret = verify_bitmap_size(size >> pgshift, 3035 3007 range.bitmap.size); 3036 3008 if (ret) 3037 3009 return ret; ··· 3055 3007 ret = -EINVAL; 3056 3008 goto out_unlock; 3057 3009 } 3058 - if (range.iova & (iommu_pgsize - 1)) { 3010 + if (iova & (iommu_pgsize - 1)) { 3059 3011 ret = -EINVAL; 3060 3012 goto out_unlock; 3061 3013 } 3062 - if (!range.size || range.size & (iommu_pgsize - 1)) { 3014 + if (size & (iommu_pgsize - 1)) { 3063 3015 ret = -EINVAL; 3064 3016 goto out_unlock; 3065 3017 } 3066 3018 3067 3019 if (iommu->dirty_page_tracking) 3068 3020 ret = vfio_iova_dirty_bitmap(range.bitmap.data, 3069 - iommu, range.iova, 3070 - range.size, 3021 + iommu, iova, iova_end, 3071 3022 range.bitmap.pgsize); 3072 3023 else 3073 3024 ret = -EINVAL;
+23 -4
tools/testing/selftests/vfio/lib/include/vfio_util.h
··· 206 206 void vfio_pci_device_cleanup(struct vfio_pci_device *device); 207 207 void vfio_pci_device_reset(struct vfio_pci_device *device); 208 208 209 - void vfio_pci_dma_map(struct vfio_pci_device *device, 210 - struct vfio_dma_region *region); 211 - void vfio_pci_dma_unmap(struct vfio_pci_device *device, 212 - struct vfio_dma_region *region); 209 + int __vfio_pci_dma_map(struct vfio_pci_device *device, 210 + struct vfio_dma_region *region); 211 + int __vfio_pci_dma_unmap(struct vfio_pci_device *device, 212 + struct vfio_dma_region *region, 213 + u64 *unmapped); 214 + int __vfio_pci_dma_unmap_all(struct vfio_pci_device *device, u64 *unmapped); 215 + 216 + static inline void vfio_pci_dma_map(struct vfio_pci_device *device, 217 + struct vfio_dma_region *region) 218 + { 219 + VFIO_ASSERT_EQ(__vfio_pci_dma_map(device, region), 0); 220 + } 221 + 222 + static inline void vfio_pci_dma_unmap(struct vfio_pci_device *device, 223 + struct vfio_dma_region *region) 224 + { 225 + VFIO_ASSERT_EQ(__vfio_pci_dma_unmap(device, region, NULL), 0); 226 + } 227 + 228 + static inline void vfio_pci_dma_unmap_all(struct vfio_pci_device *device) 229 + { 230 + VFIO_ASSERT_EQ(__vfio_pci_dma_unmap_all(device, NULL), 0); 231 + } 213 232 214 233 void vfio_pci_config_access(struct vfio_pci_device *device, bool write, 215 234 size_t config, size_t size, void *data);
+83 -25
tools/testing/selftests/vfio/lib/vfio_pci_device.c
··· 2 2 #include <dirent.h> 3 3 #include <fcntl.h> 4 4 #include <libgen.h> 5 + #include <stdint.h> 5 6 #include <stdlib.h> 6 7 #include <string.h> 7 8 #include <unistd.h> ··· 142 141 ioctl_assert(device->fd, VFIO_DEVICE_GET_IRQ_INFO, irq_info); 143 142 } 144 143 145 - static void vfio_iommu_dma_map(struct vfio_pci_device *device, 144 + static int vfio_iommu_dma_map(struct vfio_pci_device *device, 146 145 struct vfio_dma_region *region) 147 146 { 148 147 struct vfio_iommu_type1_dma_map args = { ··· 153 152 .size = region->size, 154 153 }; 155 154 156 - ioctl_assert(device->container_fd, VFIO_IOMMU_MAP_DMA, &args); 155 + if (ioctl(device->container_fd, VFIO_IOMMU_MAP_DMA, &args)) 156 + return -errno; 157 + 158 + return 0; 157 159 } 158 160 159 - static void iommufd_dma_map(struct vfio_pci_device *device, 161 + static int iommufd_dma_map(struct vfio_pci_device *device, 160 162 struct vfio_dma_region *region) 161 163 { 162 164 struct iommu_ioas_map args = { ··· 173 169 .ioas_id = device->ioas_id, 174 170 }; 175 171 176 - ioctl_assert(device->iommufd, IOMMU_IOAS_MAP, &args); 172 + if (ioctl(device->iommufd, IOMMU_IOAS_MAP, &args)) 173 + return -errno; 174 + 175 + return 0; 177 176 } 178 177 179 - void vfio_pci_dma_map(struct vfio_pci_device *device, 178 + int __vfio_pci_dma_map(struct vfio_pci_device *device, 180 179 struct vfio_dma_region *region) 181 180 { 181 + int ret; 182 + 182 183 if (device->iommufd) 183 - iommufd_dma_map(device, region); 184 + ret = iommufd_dma_map(device, region); 184 185 else 185 - vfio_iommu_dma_map(device, region); 186 + ret = vfio_iommu_dma_map(device, region); 187 + 188 + if (ret) 189 + return ret; 186 190 187 191 list_add(&region->link, &device->dma_regions); 192 + 193 + return 0; 188 194 } 189 195 190 - static void vfio_iommu_dma_unmap(struct vfio_pci_device *device, 191 - struct vfio_dma_region *region) 196 + static int vfio_iommu_dma_unmap(int fd, u64 iova, u64 size, u32 flags, 197 + u64 *unmapped) 192 198 { 193 199 struct vfio_iommu_type1_dma_unmap args = { 194 200 .argsz = sizeof(args), 195 - .iova = region->iova, 196 - .size = region->size, 201 + .iova = iova, 202 + .size = size, 203 + .flags = flags, 197 204 }; 198 205 199 - ioctl_assert(device->container_fd, VFIO_IOMMU_UNMAP_DMA, &args); 206 + if (ioctl(fd, VFIO_IOMMU_UNMAP_DMA, &args)) 207 + return -errno; 208 + 209 + if (unmapped) 210 + *unmapped = args.size; 211 + 212 + return 0; 200 213 } 201 214 202 - static void iommufd_dma_unmap(struct vfio_pci_device *device, 203 - struct vfio_dma_region *region) 215 + static int iommufd_dma_unmap(int fd, u64 iova, u64 length, u32 ioas_id, 216 + u64 *unmapped) 204 217 { 205 218 struct iommu_ioas_unmap args = { 206 219 .size = sizeof(args), 207 - .iova = region->iova, 208 - .length = region->size, 209 - .ioas_id = device->ioas_id, 220 + .iova = iova, 221 + .length = length, 222 + .ioas_id = ioas_id, 210 223 }; 211 224 212 - ioctl_assert(device->iommufd, IOMMU_IOAS_UNMAP, &args); 225 + if (ioctl(fd, IOMMU_IOAS_UNMAP, &args)) 226 + return -errno; 227 + 228 + if (unmapped) 229 + *unmapped = args.length; 230 + 231 + return 0; 213 232 } 214 233 215 - void vfio_pci_dma_unmap(struct vfio_pci_device *device, 216 - struct vfio_dma_region *region) 234 + int __vfio_pci_dma_unmap(struct vfio_pci_device *device, 235 + struct vfio_dma_region *region, u64 *unmapped) 217 236 { 218 - if (device->iommufd) 219 - iommufd_dma_unmap(device, region); 220 - else 221 - vfio_iommu_dma_unmap(device, region); 237 + int ret; 222 238 223 - list_del(&region->link); 239 + if (device->iommufd) 240 + ret = iommufd_dma_unmap(device->iommufd, region->iova, 241 + region->size, device->ioas_id, 242 + unmapped); 243 + else 244 + ret = vfio_iommu_dma_unmap(device->container_fd, region->iova, 245 + region->size, 0, unmapped); 246 + 247 + if (ret) 248 + return ret; 249 + 250 + list_del_init(&region->link); 251 + 252 + return 0; 253 + } 254 + 255 + int __vfio_pci_dma_unmap_all(struct vfio_pci_device *device, u64 *unmapped) 256 + { 257 + int ret; 258 + struct vfio_dma_region *curr, *next; 259 + 260 + if (device->iommufd) 261 + ret = iommufd_dma_unmap(device->iommufd, 0, UINT64_MAX, 262 + device->ioas_id, unmapped); 263 + else 264 + ret = vfio_iommu_dma_unmap(device->container_fd, 0, 0, 265 + VFIO_DMA_UNMAP_FLAG_ALL, unmapped); 266 + 267 + if (ret) 268 + return ret; 269 + 270 + list_for_each_entry_safe(curr, next, &device->dma_regions, link) 271 + list_del_init(&curr->link); 272 + 273 + return 0; 224 274 } 225 275 226 276 static void vfio_pci_region_get(struct vfio_pci_device *device, int index,
+94 -1
tools/testing/selftests/vfio/vfio_dma_mapping_test.c
··· 112 112 FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous_hugetlb_2mb, SZ_2M, MAP_HUGETLB | MAP_HUGE_2MB); 113 113 FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous_hugetlb_1gb, SZ_1G, MAP_HUGETLB | MAP_HUGE_1GB); 114 114 115 + #undef FIXTURE_VARIANT_ADD_IOMMU_MODE 116 + 115 117 FIXTURE_SETUP(vfio_dma_mapping_test) 116 118 { 117 119 self->device = vfio_pci_device_init(device_bdf, variant->iommu_mode); ··· 131 129 struct vfio_dma_region region; 132 130 struct iommu_mapping mapping; 133 131 u64 mapping_size = size; 132 + u64 unmapped; 134 133 int rc; 135 134 136 135 region.vaddr = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); ··· 187 184 } 188 185 189 186 unmap: 190 - vfio_pci_dma_unmap(self->device, &region); 187 + rc = __vfio_pci_dma_unmap(self->device, &region, &unmapped); 188 + ASSERT_EQ(rc, 0); 189 + ASSERT_EQ(unmapped, region.size); 191 190 printf("Unmapped IOVA 0x%lx\n", region.iova); 192 191 ASSERT_EQ(INVALID_IOVA, __to_iova(self->device, region.vaddr)); 193 192 ASSERT_NE(0, iommu_mapping_get(device_bdf, region.iova, &mapping)); 194 193 195 194 ASSERT_TRUE(!munmap(region.vaddr, size)); 195 + } 196 + 197 + FIXTURE(vfio_dma_map_limit_test) { 198 + struct vfio_pci_device *device; 199 + struct vfio_dma_region region; 200 + size_t mmap_size; 201 + }; 202 + 203 + FIXTURE_VARIANT(vfio_dma_map_limit_test) { 204 + const char *iommu_mode; 205 + }; 206 + 207 + #define FIXTURE_VARIANT_ADD_IOMMU_MODE(_iommu_mode) \ 208 + FIXTURE_VARIANT_ADD(vfio_dma_map_limit_test, _iommu_mode) { \ 209 + .iommu_mode = #_iommu_mode, \ 210 + } 211 + 212 + FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(); 213 + 214 + #undef FIXTURE_VARIANT_ADD_IOMMU_MODE 215 + 216 + FIXTURE_SETUP(vfio_dma_map_limit_test) 217 + { 218 + struct vfio_dma_region *region = &self->region; 219 + u64 region_size = getpagesize(); 220 + 221 + /* 222 + * Over-allocate mmap by double the size to provide enough backing vaddr 223 + * for overflow tests 224 + */ 225 + self->mmap_size = 2 * region_size; 226 + 227 + self->device = vfio_pci_device_init(device_bdf, variant->iommu_mode); 228 + region->vaddr = mmap(NULL, self->mmap_size, PROT_READ | PROT_WRITE, 229 + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 230 + ASSERT_NE(region->vaddr, MAP_FAILED); 231 + 232 + /* One page prior to the end of address space */ 233 + region->iova = ~(iova_t)0 & ~(region_size - 1); 234 + region->size = region_size; 235 + } 236 + 237 + FIXTURE_TEARDOWN(vfio_dma_map_limit_test) 238 + { 239 + vfio_pci_device_cleanup(self->device); 240 + ASSERT_EQ(munmap(self->region.vaddr, self->mmap_size), 0); 241 + } 242 + 243 + TEST_F(vfio_dma_map_limit_test, unmap_range) 244 + { 245 + struct vfio_dma_region *region = &self->region; 246 + u64 unmapped; 247 + int rc; 248 + 249 + vfio_pci_dma_map(self->device, region); 250 + ASSERT_EQ(region->iova, to_iova(self->device, region->vaddr)); 251 + 252 + rc = __vfio_pci_dma_unmap(self->device, region, &unmapped); 253 + ASSERT_EQ(rc, 0); 254 + ASSERT_EQ(unmapped, region->size); 255 + } 256 + 257 + TEST_F(vfio_dma_map_limit_test, unmap_all) 258 + { 259 + struct vfio_dma_region *region = &self->region; 260 + u64 unmapped; 261 + int rc; 262 + 263 + vfio_pci_dma_map(self->device, region); 264 + ASSERT_EQ(region->iova, to_iova(self->device, region->vaddr)); 265 + 266 + rc = __vfio_pci_dma_unmap_all(self->device, &unmapped); 267 + ASSERT_EQ(rc, 0); 268 + ASSERT_EQ(unmapped, region->size); 269 + } 270 + 271 + TEST_F(vfio_dma_map_limit_test, overflow) 272 + { 273 + struct vfio_dma_region *region = &self->region; 274 + int rc; 275 + 276 + region->size = self->mmap_size; 277 + 278 + rc = __vfio_pci_dma_map(self->device, region); 279 + ASSERT_EQ(rc, -EOVERFLOW); 280 + 281 + rc = __vfio_pci_dma_unmap(self->device, region, NULL); 282 + ASSERT_EQ(rc, -EOVERFLOW); 196 283 } 197 284 198 285 int main(int argc, char *argv[])