]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
irqdomain/treewide: Keep firmware node unconditionally allocated
authorThomas Gleixner <tglx@linutronix.de>
Thu, 9 Jul 2020 09:53:06 +0000 (11:53 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 29 Jul 2020 05:42:52 +0000 (07:42 +0200)
[ Upstream commit e3beca48a45b5e0e6e6a4e0124276b8248dcc9bb ]

Quite some non OF/ACPI users of irqdomains allocate firmware nodes of type
IRQCHIP_FWNODE_NAMED or IRQCHIP_FWNODE_NAMED_ID and free them right after
creating the irqdomain. The only purpose of these FW nodes is to convey
name information. When this was introduced the core code did not store the
pointer to the node in the irqdomain. A recent change stored the firmware
node pointer in irqdomain for other reasons and missed to notice that the
usage sites which do the alloc_fwnode/create_domain/free_fwnode sequence
are broken by this. Storing a dangling pointer is dangerous itself, but in
case that the domain is destroyed later on this leads to a double free.

Remove the freeing of the firmware node after creating the irqdomain from
all affected call sites to cure this.

Fixes: 711419e504eb ("irqdomain: Add the missing assignment of domain->fwnode for named fwnode")
Reported-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: Marc Zyngier <maz@kernel.org>
Cc: stable@vger.kernel.org
Link: https://lkml.kernel.org/r/873661qakd.fsf@nanos.tec.linutronix.de
Signed-off-by: Sasha Levin <sashal@kernel.org>
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/apic/msi.c
arch/x86/kernel/apic/vector.c
arch/x86/platform/uv/uv_irq.c
drivers/iommu/amd_iommu.c
drivers/iommu/intel_irq_remapping.c
drivers/pci/host/vmd.c

index 2271adbc3c42a86bb80632d877b78d7346d3d39a..b5652233e674590b565f8d18bcee7438b4c654d4 100644 (file)
@@ -2233,12 +2233,12 @@ static int mp_irqdomain_create(int ioapic)
        ip->irqdomain = irq_domain_create_linear(fn, hwirqs, cfg->ops,
                                                 (void *)(long)ioapic);
 
-       /* Release fw handle if it was allocated above */
-       if (!cfg->dev)
-               irq_domain_free_fwnode(fn);
-
-       if (!ip->irqdomain)
+       if (!ip->irqdomain) {
+               /* Release fw handle if it was allocated above */
+               if (!cfg->dev)
+                       irq_domain_free_fwnode(fn);
                return -ENOMEM;
+       }
 
        ip->irqdomain->parent = parent;
 
index f10e7f93b0e2c04e7b5f22adbc7ebb574f710281..8c102d62b8596bd05e3e61f2683e1359ed5e7b88 100644 (file)
@@ -149,10 +149,11 @@ void __init arch_init_msi_domain(struct irq_domain *parent)
                msi_default_domain =
                        pci_msi_create_irq_domain(fn, &pci_msi_domain_info,
                                                  parent);
-               irq_domain_free_fwnode(fn);
        }
-       if (!msi_default_domain)
+       if (!msi_default_domain) {
+               irq_domain_free_fwnode(fn);
                pr_warn("failed to initialize irqdomain for MSI/MSI-x.\n");
+       }
 }
 
 #ifdef CONFIG_IRQ_REMAP
@@ -185,7 +186,8 @@ struct irq_domain *arch_create_remap_msi_irq_domain(struct irq_domain *parent,
        if (!fn)
                return NULL;
        d = pci_msi_create_irq_domain(fn, &pci_msi_ir_domain_info, parent);
-       irq_domain_free_fwnode(fn);
+       if (!d)
+               irq_domain_free_fwnode(fn);
        return d;
 }
 #endif
@@ -248,7 +250,8 @@ static struct irq_domain *dmar_get_irq_domain(void)
        if (fn) {
                dmar_domain = msi_create_irq_domain(fn, &dmar_msi_domain_info,
                                                    x86_vector_domain);
-               irq_domain_free_fwnode(fn);
+               if (!dmar_domain)
+                       irq_domain_free_fwnode(fn);
        }
 out:
        mutex_unlock(&dmar_lock);
@@ -373,7 +376,10 @@ struct irq_domain *hpet_create_irq_domain(int hpet_id)
        }
 
        d = msi_create_irq_domain(fn, domain_info, parent);
-       irq_domain_free_fwnode(fn);
+       if (!d) {
+               irq_domain_free_fwnode(fn);
+               kfree(domain_info);
+       }
        return d;
 }
 
index b958082c74a77f0903c830949f6b3aae667adea9..36cd34524ac197116dd412b0881d8c26016684e7 100644 (file)
@@ -457,7 +457,6 @@ int __init arch_early_irq_init(void)
        x86_vector_domain = irq_domain_create_tree(fn, &x86_vector_domain_ops,
                                                   NULL);
        BUG_ON(x86_vector_domain == NULL);
-       irq_domain_free_fwnode(fn);
        irq_set_default_host(x86_vector_domain);
 
        arch_init_msi_domain(x86_vector_domain);
index 03fc397335b7482e9302f7d7f6b85d9c0f553df5..c9fc725a1dcf4a43f2fb55c3a733b623f9794654 100644 (file)
@@ -171,9 +171,10 @@ static struct irq_domain *uv_get_irq_domain(void)
                goto out;
 
        uv_domain = irq_domain_create_tree(fn, &uv_domain_ops, NULL);
-       irq_domain_free_fwnode(fn);
        if (uv_domain)
                uv_domain->parent = x86_vector_domain;
+       else
+               irq_domain_free_fwnode(fn);
 out:
        mutex_unlock(&uv_lock);
 
index 778f167be2d3517656799bd609f84d53765457a3..494caaa265af0b5dd6624ffa916f97db733239c7 100644 (file)
@@ -4394,9 +4394,10 @@ int amd_iommu_create_irq_domain(struct amd_iommu *iommu)
        if (!fn)
                return -ENOMEM;
        iommu->ir_domain = irq_domain_create_tree(fn, &amd_ir_domain_ops, iommu);
-       irq_domain_free_fwnode(fn);
-       if (!iommu->ir_domain)
+       if (!iommu->ir_domain) {
+               irq_domain_free_fwnode(fn);
                return -ENOMEM;
+       }
 
        iommu->ir_domain->parent = arch_get_ir_parent_domain();
        iommu->msi_domain = arch_create_remap_msi_irq_domain(iommu->ir_domain,
index 25842b566c39c1497d1cecd91b6af8a079492185..154949a499c2177a1c7debea8fca711a126f692a 100644 (file)
@@ -536,8 +536,8 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu)
                                            0, INTR_REMAP_TABLE_ENTRIES,
                                            fn, &intel_ir_domain_ops,
                                            iommu);
-       irq_domain_free_fwnode(fn);
        if (!iommu->ir_domain) {
+               irq_domain_free_fwnode(fn);
                pr_err("IR%d: failed to allocate irqdomain\n", iommu->seq_id);
                goto out_free_bitmap;
        }
index af6d5da10ea5f89bdc47d5ddb463201569f75783..05f191ae0ff1b09c8b0f2c39e4e8dd5d86b1f637 100644 (file)
@@ -638,9 +638,10 @@ static int vmd_enable_domain(struct vmd_dev *vmd)
 
        vmd->irq_domain = pci_msi_create_irq_domain(fn, &vmd_msi_domain_info,
                                                    x86_vector_domain);
-       irq_domain_free_fwnode(fn);
-       if (!vmd->irq_domain)
+       if (!vmd->irq_domain) {
+               irq_domain_free_fwnode(fn);
                return -ENODEV;
+       }
 
        pci_add_resource(&resources, &vmd->resources[0]);
        pci_add_resource(&resources, &vmd->resources[1]);