[+cc Kees] On 4/18/19 12:57 PM, Greg Kroah-Hartman wrote: > [ Upstream commit cffaaf0c816238c45cd2d06913476c83eb50f682 ] > > Commit 57384592c433 ("iommu/vt-d: Store bus information in RMRR PCI > device path") changed the type of the path data, however, the change in > path type was not reflected in size calculations. Update to use the > correct type and prevent a buffer overflow. > > This bug manifests in systems with deep PCI hierarchies, and can lead to > an overflow of the static allocated buffer (dmar_pci_notify_info_buf), > or can lead to overflow of slab-allocated data. > > BUG: KASAN: global-out-of-bounds in dmar_alloc_pci_notify_info+0x1d5/0x2e0 > Write of size 1 at addr ffffffff90445d80 by task swapper/0/1 > CPU: 0 PID: 1 Comm: swapper/0 Tainted: G W 4.14.87-rt49-02406-gd0a0e96 #1 > Call Trace: > ? dump_stack+0x46/0x59 > ? print_address_description+0x1df/0x290 > ? dmar_alloc_pci_notify_info+0x1d5/0x2e0 > ? kasan_report+0x256/0x340 > ? dmar_alloc_pci_notify_info+0x1d5/0x2e0 > ? e820__memblock_setup+0xb0/0xb0 > ? dmar_dev_scope_init+0x424/0x48f > ? __down_write_common+0x1ec/0x230 > ? dmar_dev_scope_init+0x48f/0x48f > ? dmar_free_unused_resources+0x109/0x109 > ? cpumask_next+0x16/0x20 > ? __kmem_cache_create+0x392/0x430 > ? kmem_cache_create+0x135/0x2f0 > ? e820__memblock_setup+0xb0/0xb0 > ? intel_iommu_init+0x170/0x1848 > ? _raw_spin_unlock_irqrestore+0x32/0x60 > ? migrate_enable+0x27a/0x5b0 > ? sched_setattr+0x20/0x20 > ? migrate_disable+0x1fc/0x380 > ? task_rq_lock+0x170/0x170 > ? try_to_run_init_process+0x40/0x40 > ? locks_remove_file+0x85/0x2f0 > ? dev_prepare_static_identity_mapping+0x78/0x78 > ? rt_spin_unlock+0x39/0x50 > ? lockref_put_or_lock+0x2a/0x40 > ? dput+0x128/0x2f0 > ? __rcu_read_unlock+0x66/0x80 > ? __fput+0x250/0x300 > ? __rcu_read_lock+0x1b/0x30 > ? mntput_no_expire+0x38/0x290 > ? e820__memblock_setup+0xb0/0xb0 > ? pci_iommu_init+0x25/0x63 > ? pci_iommu_init+0x25/0x63 > ? do_one_initcall+0x7e/0x1c0 > ? initcall_blacklisted+0x120/0x120 > ? kernel_init_freeable+0x27b/0x307 > ? rest_init+0xd0/0xd0 > ? kernel_init+0xf/0x120 > ? rest_init+0xd0/0xd0 > ? ret_from_fork+0x1f/0x40 > The buggy address belongs to the variable: > dmar_pci_notify_info_buf+0x40/0x60 > > Fixes: 57384592c433 ("iommu/vt-d: Store bus information in RMRR PCI device path") > Signed-off-by: Julia Cartwright <julia@xxxxxx> > Signed-off-by: Joerg Roedel <jroedel@xxxxxxx> > Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx> > --- > drivers/iommu/dmar.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c > index c0d1c4db5794..38d0128b8135 100644 > --- a/drivers/iommu/dmar.c > +++ b/drivers/iommu/dmar.c > @@ -144,7 +144,7 @@ dmar_alloc_pci_notify_info(struct pci_dev *dev, unsigned long event) > for (tmp = dev; tmp; tmp = tmp->bus->self) > level++; > > - size = sizeof(*info) + level * sizeof(struct acpi_dmar_pci_path); > + size = sizeof(*info) + level * sizeof(info->path[0]); > if (size <= sizeof(dmar_pci_notify_info_buf)) { > info = (struct dmar_pci_notify_info *)dmar_pci_notify_info_buf; > } else { > This perfectly illustrates how the use of the new struct_size() helper can prevent these sort of bugs. :) diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 9c49300e9fb7..6d969a172fbb 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -145,7 +145,7 @@ dmar_alloc_pci_notify_info(struct pci_dev *dev, unsigned long event) for (tmp = dev; tmp; tmp = tmp->bus->self) level++; - size = sizeof(*info) + level * sizeof(info->path[0]); + size = struct_size(info, path, level); if (size <= sizeof(dmar_pci_notify_info_buf)) { info = (struct dmar_pci_notify_info *)dmar_pci_notify_info_buf; } else { -- Gustavo