Skip to content

Commit 2d33b7d

Browse files
LuBaolujoergroedel
authored andcommitted
iommu/vt-d: Fix NULL pointer dereference in dev_iommu_priv_set()
The dev_iommu_priv_set() must be called after probe_device(). This fixes a NULL pointer deference bug when booting a system with kernel cmdline "intel_iommu=on,igfx_off", where the dev_iommu_priv_set() is abused. The following stacktrace was produced: Command line: BOOT_IMAGE=/isolinux/bzImage console=tty1 intel_iommu=on,igfx_off ... DMAR: Host address width 39 DMAR: DRHD base: 0x000000fed90000 flags: 0x0 DMAR: dmar0: reg_base_addr fed90000 ver 1:0 cap 1c0000c40660462 ecap 19e2ff0505e DMAR: DRHD base: 0x000000fed91000 flags: 0x1 DMAR: dmar1: reg_base_addr fed91000 ver 1:0 cap d2008c40660462 ecap f050da DMAR: RMRR base: 0x0000009aa9f000 end: 0x0000009aabefff DMAR: RMRR base: 0x0000009d000000 end: 0x0000009f7fffff DMAR: No ATSR found BUG: kernel NULL pointer dereference, address: 0000000000000038 #PF: supervisor write access in kernel mode #PF: error_code(0x0002) - not-present page PGD 0 P4D 0 Oops: 0002 [#1] SMP PTI CPU: 1 PID: 1 Comm: swapper/0 Not tainted 5.9.0-devel+ #2 Hardware name: LENOVO 20HGS0TW00/20HGS0TW00, BIOS N1WET46S (1.25s ) 03/30/2018 RIP: 0010:intel_iommu_init+0xed0/0x1136 Code: fe e9 61 02 00 00 bb f4 ff ff ff e9 57 02 00 00 48 63 d1 48 c1 e2 04 48 03 50 20 48 8b 12 48 85 d2 74 0b 48 8b 92 d0 02 00 00 48 89 7a 38 ff c1 e9 15 f5 ff ff 48 c7 c7 60 99 ac a7 49 c7 c7 a0 RSP: 0000:ffff96d180073dd0 EFLAGS: 00010282 RAX: ffff8c91037a7d20 RBX: 0000000000000000 RCX: 0000000000000000 RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffffffffffffffff RBP: ffff96d180073e90 R08: 0000000000000001 R09: ffff8c91039fe3c0 R10: 0000000000000226 R11: 0000000000000226 R12: 000000000000000b R13: ffff8c910367c650 R14: ffffffffa8426d60 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffff8c9107480000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000038 CR3: 00000004b100a001 CR4: 00000000003706e0 Call Trace: ? _raw_spin_unlock_irqrestore+0x1f/0x30 ? call_rcu+0x10e/0x320 ? trace_hardirqs_on+0x2c/0xd0 ? rdinit_setup+0x2c/0x2c ? e820__memblock_setup+0x8b/0x8b pci_iommu_init+0x16/0x3f do_one_initcall+0x46/0x1e4 kernel_init_freeable+0x169/0x1b2 ? rest_init+0x9f/0x9f kernel_init+0xa/0x101 ret_from_fork+0x22/0x30 Modules linked in: CR2: 0000000000000038 ---[ end trace 3653722a6f936f18 ]--- Fixes: 01b9d4e ("iommu/vt-d: Use dev_iommu_priv_get/set()") Reported-by: Torsten Hilbrich <[email protected]> Reported-by: Wendy Wang <[email protected]> Signed-off-by: Lu Baolu <[email protected]> Tested-by: Torsten Hilbrich <[email protected]> Link: https://lore.kernel.org/linux-iommu/[email protected]/ Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent 6e4e9ec commit 2d33b7d

File tree

1 file changed

+55
-45
lines changed

1 file changed

+55
-45
lines changed

drivers/iommu/intel/iommu.c

+55-45
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,6 @@ static int iommu_skip_te_disable;
364364
int intel_iommu_gfx_mapped;
365365
EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped);
366366

367-
#define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
368367
#define DEFER_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-2))
369368
struct device_domain_info *get_domain_info(struct device *dev)
370369
{
@@ -374,8 +373,7 @@ struct device_domain_info *get_domain_info(struct device *dev)
374373
return NULL;
375374

376375
info = dev_iommu_priv_get(dev);
377-
if (unlikely(info == DUMMY_DEVICE_DOMAIN_INFO ||
378-
info == DEFER_DEVICE_DOMAIN_INFO))
376+
if (unlikely(info == DEFER_DEVICE_DOMAIN_INFO))
379377
return NULL;
380378

381379
return info;
@@ -742,11 +740,6 @@ struct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus,
742740
return &context[devfn];
743741
}
744742

745-
static int iommu_dummy(struct device *dev)
746-
{
747-
return dev_iommu_priv_get(dev) == DUMMY_DEVICE_DOMAIN_INFO;
748-
}
749-
750743
static bool attach_deferred(struct device *dev)
751744
{
752745
return dev_iommu_priv_get(dev) == DEFER_DEVICE_DOMAIN_INFO;
@@ -779,6 +772,53 @@ is_downstream_to_pci_bridge(struct device *dev, struct device *bridge)
779772
return false;
780773
}
781774

775+
static bool quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
776+
{
777+
struct dmar_drhd_unit *drhd;
778+
u32 vtbar;
779+
int rc;
780+
781+
/* We know that this device on this chipset has its own IOMMU.
782+
* If we find it under a different IOMMU, then the BIOS is lying
783+
* to us. Hope that the IOMMU for this device is actually
784+
* disabled, and it needs no translation...
785+
*/
786+
rc = pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0xb0, &vtbar);
787+
if (rc) {
788+
/* "can't" happen */
789+
dev_info(&pdev->dev, "failed to run vt-d quirk\n");
790+
return false;
791+
}
792+
vtbar &= 0xffff0000;
793+
794+
/* we know that the this iommu should be at offset 0xa000 from vtbar */
795+
drhd = dmar_find_matched_drhd_unit(pdev);
796+
if (!drhd || drhd->reg_base_addr - vtbar != 0xa000) {
797+
pr_warn_once(FW_BUG "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n");
798+
add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
799+
return true;
800+
}
801+
802+
return false;
803+
}
804+
805+
static bool iommu_is_dummy(struct intel_iommu *iommu, struct device *dev)
806+
{
807+
if (!iommu || iommu->drhd->ignored)
808+
return true;
809+
810+
if (dev_is_pci(dev)) {
811+
struct pci_dev *pdev = to_pci_dev(dev);
812+
813+
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
814+
pdev->device == PCI_DEVICE_ID_INTEL_IOAT_SNB &&
815+
quirk_ioat_snb_local_iommu(pdev))
816+
return true;
817+
}
818+
819+
return false;
820+
}
821+
782822
struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn)
783823
{
784824
struct dmar_drhd_unit *drhd = NULL;
@@ -788,7 +828,7 @@ struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn)
788828
u16 segment = 0;
789829
int i;
790830

791-
if (!dev || iommu_dummy(dev))
831+
if (!dev)
792832
return NULL;
793833

794834
if (dev_is_pci(dev)) {
@@ -805,7 +845,7 @@ struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn)
805845
dev = &ACPI_COMPANION(dev)->dev;
806846

807847
rcu_read_lock();
808-
for_each_active_iommu(iommu, drhd) {
848+
for_each_iommu(iommu, drhd) {
809849
if (pdev && segment != drhd->segment)
810850
continue;
811851

@@ -841,6 +881,9 @@ struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn)
841881
}
842882
iommu = NULL;
843883
out:
884+
if (iommu_is_dummy(iommu, dev))
885+
iommu = NULL;
886+
844887
rcu_read_unlock();
845888

846889
return iommu;
@@ -2447,7 +2490,7 @@ struct dmar_domain *find_domain(struct device *dev)
24472490
{
24482491
struct device_domain_info *info;
24492492

2450-
if (unlikely(attach_deferred(dev) || iommu_dummy(dev)))
2493+
if (unlikely(attach_deferred(dev)))
24512494
return NULL;
24522495

24532496
/* No lock here, assumes no domain exit in normal case */
@@ -3989,35 +4032,6 @@ static void __init iommu_exit_mempool(void)
39894032
iova_cache_put();
39904033
}
39914034

3992-
static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
3993-
{
3994-
struct dmar_drhd_unit *drhd;
3995-
u32 vtbar;
3996-
int rc;
3997-
3998-
/* We know that this device on this chipset has its own IOMMU.
3999-
* If we find it under a different IOMMU, then the BIOS is lying
4000-
* to us. Hope that the IOMMU for this device is actually
4001-
* disabled, and it needs no translation...
4002-
*/
4003-
rc = pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0xb0, &vtbar);
4004-
if (rc) {
4005-
/* "can't" happen */
4006-
dev_info(&pdev->dev, "failed to run vt-d quirk\n");
4007-
return;
4008-
}
4009-
vtbar &= 0xffff0000;
4010-
4011-
/* we know that the this iommu should be at offset 0xa000 from vtbar */
4012-
drhd = dmar_find_matched_drhd_unit(pdev);
4013-
if (!drhd || drhd->reg_base_addr - vtbar != 0xa000) {
4014-
pr_warn_once(FW_BUG "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n");
4015-
add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
4016-
dev_iommu_priv_set(&pdev->dev, DUMMY_DEVICE_DOMAIN_INFO);
4017-
}
4018-
}
4019-
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quirk_ioat_snb_local_iommu);
4020-
40214035
static void __init init_no_remapping_devices(void)
40224036
{
40234037
struct dmar_drhd_unit *drhd;
@@ -4049,12 +4063,8 @@ static void __init init_no_remapping_devices(void)
40494063
/* This IOMMU has *only* gfx devices. Either bypass it or
40504064
set the gfx_mapped flag, as appropriate */
40514065
drhd->gfx_dedicated = 1;
4052-
if (!dmar_map_gfx) {
4066+
if (!dmar_map_gfx)
40534067
drhd->ignored = 1;
4054-
for_each_active_dev_scope(drhd->devices,
4055-
drhd->devices_cnt, i, dev)
4056-
dev_iommu_priv_set(dev, DUMMY_DEVICE_DOMAIN_INFO);
4057-
}
40584068
}
40594069
}
40604070

0 commit comments

Comments
 (0)