diff options
-rw-r--r-- | arch/x86/kernel/amd_iommu.c | 110 |
1 files changed, 49 insertions, 61 deletions
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 405f8dad7c77..d10195b685a7 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c | |||
@@ -111,6 +111,33 @@ static struct dma_ops_domain *find_protection_domain(u16 devid) | |||
111 | return ret; | 111 | return ret; |
112 | } | 112 | } |
113 | 113 | ||
114 | /* | ||
115 | * This function checks if the driver got a valid device from the caller to | ||
116 | * avoid dereferencing invalid pointers. | ||
117 | */ | ||
118 | static bool check_device(struct device *dev) | ||
119 | { | ||
120 | u16 devid; | ||
121 | |||
122 | if (!dev || !dev->dma_mask) | ||
123 | return false; | ||
124 | |||
125 | /* No device or no PCI device */ | ||
126 | if (!dev || dev->bus != &pci_bus_type) | ||
127 | return false; | ||
128 | |||
129 | devid = get_device_id(dev); | ||
130 | |||
131 | /* Out of our scope? */ | ||
132 | if (devid > amd_iommu_last_bdf) | ||
133 | return false; | ||
134 | |||
135 | if (amd_iommu_rlookup_table[devid] == NULL) | ||
136 | return false; | ||
137 | |||
138 | return true; | ||
139 | } | ||
140 | |||
114 | #ifdef CONFIG_AMD_IOMMU_STATS | 141 | #ifdef CONFIG_AMD_IOMMU_STATS |
115 | 142 | ||
116 | /* | 143 | /* |
@@ -1386,22 +1413,17 @@ static int device_change_notifier(struct notifier_block *nb, | |||
1386 | unsigned long action, void *data) | 1413 | unsigned long action, void *data) |
1387 | { | 1414 | { |
1388 | struct device *dev = data; | 1415 | struct device *dev = data; |
1389 | struct pci_dev *pdev = to_pci_dev(dev); | 1416 | u16 devid; |
1390 | u16 devid = calc_devid(pdev->bus->number, pdev->devfn); | ||
1391 | struct protection_domain *domain; | 1417 | struct protection_domain *domain; |
1392 | struct dma_ops_domain *dma_domain; | 1418 | struct dma_ops_domain *dma_domain; |
1393 | struct amd_iommu *iommu; | 1419 | struct amd_iommu *iommu; |
1394 | unsigned long flags; | 1420 | unsigned long flags; |
1395 | 1421 | ||
1396 | if (devid > amd_iommu_last_bdf) | 1422 | if (!check_device(dev)) |
1397 | goto out; | 1423 | return 0; |
1398 | |||
1399 | devid = amd_iommu_alias_table[devid]; | ||
1400 | |||
1401 | iommu = amd_iommu_rlookup_table[devid]; | ||
1402 | if (iommu == NULL) | ||
1403 | goto out; | ||
1404 | 1424 | ||
1425 | devid = get_device_id(dev); | ||
1426 | iommu = amd_iommu_rlookup_table[devid]; | ||
1405 | domain = domain_for_device(dev); | 1427 | domain = domain_for_device(dev); |
1406 | 1428 | ||
1407 | if (domain && !dma_ops_domain(domain)) | 1429 | if (domain && !dma_ops_domain(domain)) |
@@ -1453,36 +1475,6 @@ static struct notifier_block device_nb = { | |||
1453 | *****************************************************************************/ | 1475 | *****************************************************************************/ |
1454 | 1476 | ||
1455 | /* | 1477 | /* |
1456 | * This function checks if the driver got a valid device from the caller to | ||
1457 | * avoid dereferencing invalid pointers. | ||
1458 | */ | ||
1459 | static bool check_device(struct device *dev) | ||
1460 | { | ||
1461 | u16 bdf; | ||
1462 | struct pci_dev *pcidev; | ||
1463 | |||
1464 | if (!dev || !dev->dma_mask) | ||
1465 | return false; | ||
1466 | |||
1467 | /* No device or no PCI device */ | ||
1468 | if (!dev || dev->bus != &pci_bus_type) | ||
1469 | return false; | ||
1470 | |||
1471 | pcidev = to_pci_dev(dev); | ||
1472 | |||
1473 | bdf = calc_devid(pcidev->bus->number, pcidev->devfn); | ||
1474 | |||
1475 | /* Out of our scope? */ | ||
1476 | if (bdf > amd_iommu_last_bdf) | ||
1477 | return false; | ||
1478 | |||
1479 | if (amd_iommu_rlookup_table[bdf] == NULL) | ||
1480 | return false; | ||
1481 | |||
1482 | return true; | ||
1483 | } | ||
1484 | |||
1485 | /* | ||
1486 | * In the dma_ops path we only have the struct device. This function | 1478 | * In the dma_ops path we only have the struct device. This function |
1487 | * finds the corresponding IOMMU, the protection domain and the | 1479 | * finds the corresponding IOMMU, the protection domain and the |
1488 | * requestor id for a given device. | 1480 | * requestor id for a given device. |
@@ -2094,15 +2086,20 @@ static void prealloc_protection_domains(void) | |||
2094 | struct pci_dev *dev = NULL; | 2086 | struct pci_dev *dev = NULL; |
2095 | struct dma_ops_domain *dma_dom; | 2087 | struct dma_ops_domain *dma_dom; |
2096 | struct amd_iommu *iommu; | 2088 | struct amd_iommu *iommu; |
2097 | u16 devid, __devid; | 2089 | u16 devid; |
2098 | 2090 | ||
2099 | while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { | 2091 | while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { |
2100 | __devid = devid = calc_devid(dev->bus->number, dev->devfn); | 2092 | |
2101 | if (devid > amd_iommu_last_bdf) | 2093 | /* Do we handle this device? */ |
2094 | if (!check_device(&dev->dev)) | ||
2102 | continue; | 2095 | continue; |
2103 | devid = amd_iommu_alias_table[devid]; | 2096 | |
2097 | /* Is there already any domain for it? */ | ||
2104 | if (domain_for_device(&dev->dev)) | 2098 | if (domain_for_device(&dev->dev)) |
2105 | continue; | 2099 | continue; |
2100 | |||
2101 | devid = get_device_id(&dev->dev); | ||
2102 | |||
2106 | iommu = amd_iommu_rlookup_table[devid]; | 2103 | iommu = amd_iommu_rlookup_table[devid]; |
2107 | if (!iommu) | 2104 | if (!iommu) |
2108 | continue; | 2105 | continue; |
@@ -2294,17 +2291,14 @@ static void amd_iommu_detach_device(struct iommu_domain *dom, | |||
2294 | struct device *dev) | 2291 | struct device *dev) |
2295 | { | 2292 | { |
2296 | struct amd_iommu *iommu; | 2293 | struct amd_iommu *iommu; |
2297 | struct pci_dev *pdev; | ||
2298 | u16 devid; | 2294 | u16 devid; |
2299 | 2295 | ||
2300 | if (dev->bus != &pci_bus_type) | 2296 | if (!check_device(dev)) |
2301 | return; | 2297 | return; |
2302 | 2298 | ||
2303 | pdev = to_pci_dev(dev); | 2299 | devid = get_device_id(dev); |
2304 | |||
2305 | devid = calc_devid(pdev->bus->number, pdev->devfn); | ||
2306 | 2300 | ||
2307 | if (devid > 0) | 2301 | if (amd_iommu_pd_table[devid] != NULL) |
2308 | detach_device(dev); | 2302 | detach_device(dev); |
2309 | 2303 | ||
2310 | iommu = amd_iommu_rlookup_table[devid]; | 2304 | iommu = amd_iommu_rlookup_table[devid]; |
@@ -2321,20 +2315,13 @@ static int amd_iommu_attach_device(struct iommu_domain *dom, | |||
2321 | struct protection_domain *domain = dom->priv; | 2315 | struct protection_domain *domain = dom->priv; |
2322 | struct protection_domain *old_domain; | 2316 | struct protection_domain *old_domain; |
2323 | struct amd_iommu *iommu; | 2317 | struct amd_iommu *iommu; |
2324 | struct pci_dev *pdev; | ||
2325 | int ret; | 2318 | int ret; |
2326 | u16 devid; | 2319 | u16 devid; |
2327 | 2320 | ||
2328 | if (dev->bus != &pci_bus_type) | 2321 | if (!check_device(dev)) |
2329 | return -EINVAL; | 2322 | return -EINVAL; |
2330 | 2323 | ||
2331 | pdev = to_pci_dev(dev); | 2324 | devid = get_device_id(dev); |
2332 | |||
2333 | devid = calc_devid(pdev->bus->number, pdev->devfn); | ||
2334 | |||
2335 | if (devid >= amd_iommu_last_bdf || | ||
2336 | devid != amd_iommu_alias_table[devid]) | ||
2337 | return -EINVAL; | ||
2338 | 2325 | ||
2339 | iommu = amd_iommu_rlookup_table[devid]; | 2326 | iommu = amd_iommu_rlookup_table[devid]; |
2340 | if (!iommu) | 2327 | if (!iommu) |
@@ -2458,10 +2445,11 @@ int __init amd_iommu_init_passthrough(void) | |||
2458 | 2445 | ||
2459 | while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { | 2446 | while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { |
2460 | 2447 | ||
2461 | devid = calc_devid(dev->bus->number, dev->devfn); | 2448 | if (!check_device(&dev->dev)) |
2462 | if (devid > amd_iommu_last_bdf) | ||
2463 | continue; | 2449 | continue; |
2464 | 2450 | ||
2451 | devid = get_device_id(&dev->dev); | ||
2452 | |||
2465 | iommu = amd_iommu_rlookup_table[devid]; | 2453 | iommu = amd_iommu_rlookup_table[devid]; |
2466 | if (!iommu) | 2454 | if (!iommu) |
2467 | continue; | 2455 | continue; |