linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] PCI: avoid NULL deref in alloc_pcie_link_state
@ 2013-06-19 18:56 Radim Krčmář
  2013-06-25  1:38 ` Bjorn Helgaas
  0 siblings, 1 reply; 11+ messages in thread
From: Radim Krčmář @ 2013-06-19 18:56 UTC (permalink / raw)
  To: linux-pci
  Cc: linux-kernel, Myron Stowe, Joe Lawrence, Kenji Kaneshige,
	Bjorn Helgaas, Radim Krčmář

PCIe switch upstream port can be connected directly to the PCIe root bus
in QEMU; ASPM does not expect this topology and dereferences NULL pointer
when initializing.

I have not confirmed this can happen on real hardware, but it is presented
as a feature in QEMU, so there is no reason to panic if we can recover.

The dereference happens with topology defined by
  -M q35 -device x3130-upstream,bus=pcie.0,id=upstream \
  -device xio3130-downstream,bus=upstream,id=downstream,chassis=1
where on line drivers/pci/pcie/aspm.c:530 (alloc_pcie_link_state+13):
  		parent = pdev->bus->parent->self->link_state;
"pdev->bus->parent->self == NULL", because "pdev->bus->parent" has no
"->parent", hence no "->self".

Even though discouraged by QEMU documentation, one can set up even
topology without the upstream port
  -M q35 -device xio3130-downstream,bus=pcie.0,id=downstream,chassis=1
so "pdev->bus->parent == NULL", because "pdev->bus" is the root bus.
The patch checks for this too, because I do not like *NULL.

Right now, PCIe switch has to connect to the root port
  -M q35 -device ioh3420,bus=pcie.0,id=root.0 \
  -device x3130-upstream,bus=root.0,id=upstream \
  -device xio3130-downstream,bus=upstream,id=downstream,chassis=1

Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
---
 drivers/pci/pcie/aspm.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 403a443..1ad1514 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -527,8 +527,8 @@ static struct pcie_link_state *alloc_pcie_link_state(struct pci_dev *pdev)
 	link->pdev = pdev;
 	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM) {
 		struct pcie_link_state *parent;
-		parent = pdev->bus->parent->self->link_state;
-		if (!parent) {
+		if (!pdev->bus->parent || !pdev->bus->parent->self ||
+		    !(parent = pdev->bus->parent->self->link_state)) {
 			kfree(link);
 			return NULL;
 		}
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 11+ messages in thread
* [PATCH] PCI: avoid NULL deref in alloc_pcie_link_state
@ 2013-08-08 13:57 Radim Krčmář
  2013-08-23  0:02 ` Bjorn Helgaas
  0 siblings, 1 reply; 11+ messages in thread
From: Radim Krčmář @ 2013-08-08 13:57 UTC (permalink / raw)
  To: linux-kernel, linux-pci
  Cc: Bjorn Helgaas, Michael S. Tsirkin, Alex Williamson, Myron Stowe,
	Joe Lawrence, Kenji Kaneshige, Isaku Yamahata

PCIe switch can be connected directly to the PCIe root complex in QEMU;
ASPM does not expect this topology and dereferences NULL pointer when
initializing.

Downstream port can be also connected to the root complex without
upstream one, so code checks for both, otherwise they dereference NULL
on line drivers/pci/pcie/aspm.c:530 (alloc_pcie_link_state+13):
  		parent = pdev->bus->parent->self->link_state;
"pdev->bus->parent->self == NULL" if upstream port is connected directly
to the root bus and "pdev->bus->parent == NULL" in the second case.

v1 -> v2: (https://lkml.org/lkml/2013/6/19/753)
 - Initialization is aborted in pcie_aspm_init_link_state, where other
   special cases are being handled
 - pci_is_root_bus is used
 - Warning is printed

Reproducer for "downstream -- root" and "downstream -- upstream -- root"
(used qemu-kvm 1.5, q35 machine type might be missing on older ones)

  for parent in pcie.0 upstream; do
   qemu-kvm -m 128 -M q35 -nographic -no-reboot \
     -device x3130-upstream,bus=pcie.0,id=upstream \
     -device xio3130-downstream,bus=$parent,id=downstream,chassis=1 \
     -device virtio-blk-pci,bus=downstream,id=virtio-zero,drive=zero \
     -drive  file=/dev/zero,id=zero,format=raw \
     -kernel bzImage -append "console=ttyS0 panic=3" # pcie_aspm=off
  done

ASPM in QEMU works if we connect upstream through root port
  -device ioh3420,bus=pcie.0,id=root.0 \
  -device x3130-upstream,bus=root.0,id=upstream

Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
---
 drivers/pci/pcie/aspm.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 403a443..209cd7f 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -570,6 +570,15 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
 	    pdev->bus->self)
 		return;
 
+	/* We require at least two ports between downstream and root bus */
+	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM &&
+	    (pci_is_root_bus(pdev->bus) ||
+	     pci_is_root_bus(pdev->bus->parent))) {
+		dev_warn(&pdev->dev, "ASPM disabled"
+		                     " (connected directly to root bus)\n");
+		return;
+	}
+
 	down_read(&pci_bus_sem);
 	if (list_empty(&pdev->subordinate->devices))
 		goto out;
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2013-08-23 21:46 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-06-19 18:56 [PATCH] PCI: avoid NULL deref in alloc_pcie_link_state Radim Krčmář
2013-06-25  1:38 ` Bjorn Helgaas
2013-06-25  2:58   ` Alex Williamson
2013-06-25  3:35     ` Bjorn Helgaas
2013-06-25  3:57       ` Alex Williamson
2013-06-25 11:23   ` Michael S. Tsirkin
2013-06-25 17:17     ` Bjorn Helgaas
2013-06-25 20:50       ` Radim Krčmář
  -- strict thread matches above, loose matches on Subject: below --
2013-08-08 13:57 Radim Krčmář
2013-08-23  0:02 ` Bjorn Helgaas
2013-08-23 21:46   ` Bjorn Helgaas

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).