| From 78e7b15e17ac175e7eed9e21c6f92d03d3b0a6fa Mon Sep 17 00:00:00 2001 |
| From: Radu Rendec <radu.rendec@gmail.com> |
| Date: Tue, 27 Nov 2018 22:20:48 -0500 |
| Subject: powerpc/msi: Fix NULL pointer access in teardown code |
| |
| From: Radu Rendec <radu.rendec@gmail.com> |
| |
| commit 78e7b15e17ac175e7eed9e21c6f92d03d3b0a6fa upstream. |
| |
| The arch_teardown_msi_irqs() function assumes that controller ops |
| pointers were already checked in arch_setup_msi_irqs(), but this |
| assumption is wrong: arch_teardown_msi_irqs() can be called even when |
| arch_setup_msi_irqs() returns an error (-ENOSYS). |
| |
| This can happen in the following scenario: |
| - msi_capability_init() calls pci_msi_setup_msi_irqs() |
| - pci_msi_setup_msi_irqs() returns -ENOSYS |
| - msi_capability_init() notices the error and calls free_msi_irqs() |
| - free_msi_irqs() calls pci_msi_teardown_msi_irqs() |
| |
| This is easier to see when CONFIG_PCI_MSI_IRQ_DOMAIN is not set and |
| pci_msi_setup_msi_irqs() and pci_msi_teardown_msi_irqs() are just |
| aliases to arch_setup_msi_irqs() and arch_teardown_msi_irqs(). |
| |
| The call to free_msi_irqs() upon pci_msi_setup_msi_irqs() failure |
| seems legit, as it does additional cleanup; e.g. |
| list_del(&entry->list) and kfree(entry) inside free_msi_irqs() do |
| happen (MSI descriptors are allocated before pci_msi_setup_msi_irqs() |
| is called and need to be cleaned up if that fails). |
| |
| Fixes: 6b2fd7efeb88 ("PCI/MSI/PPC: Remove arch_msi_check_device()") |
| Cc: stable@vger.kernel.org # v3.18+ |
| Signed-off-by: Radu Rendec <radu.rendec@gmail.com> |
| Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/powerpc/kernel/msi.c | 7 ++++++- |
| 1 file changed, 6 insertions(+), 1 deletion(-) |
| |
| --- a/arch/powerpc/kernel/msi.c |
| +++ b/arch/powerpc/kernel/msi.c |
| @@ -34,5 +34,10 @@ void arch_teardown_msi_irqs(struct pci_d |
| { |
| struct pci_controller *phb = pci_bus_to_host(dev->bus); |
| |
| - phb->controller_ops.teardown_msi_irqs(dev); |
| + /* |
| + * We can be called even when arch_setup_msi_irqs() returns -ENOSYS, |
| + * so check the pointer again. |
| + */ |
| + if (phb->controller_ops.teardown_msi_irqs) |
| + phb->controller_ops.teardown_msi_irqs(dev); |
| } |