Skip to content

Commit 4d87a6e

Browse files
committed
PCI/ASPM: Fix link state exit during switch upstream function removal
JIRA: https://issues.redhat.com/browse/RHEL-102694 commit cbf937d Author: Daniel Stodden <daniel.stodden@gmail.com> Date: Sun, 22 Dec 2024 19:39:08 -0800 Before 456d8aa ("PCI/ASPM: Disable ASPM on MFD function removal to avoid use-after-free"), we would free the ASPM link only after the last function on the bus pertaining to the given link was removed. That was too late. If function 0 is removed before sibling function, link->downstream would point to free'd memory after. After above change, we freed the ASPM parent link state upon any function removal on the bus pertaining to a given link. That is too early. If the link is to a PCIe switch with MFD on the upstream port, then removing functions other than 0 first would free a link which still remains parent_link to the remaining downstream ports. The resulting GPFs are especially frequent during hot-unplug, because pciehp removes devices on the link bus in reverse order. On that switch, function 0 is the virtual P2P bridge to the internal bus. Free exactly when function 0 is removed -- before the parent link is obsolete, but after all subordinate links are gone. Link: https://lore.kernel.org/r/e12898835f25234561c9d7de4435590d957b85d9.1734924854.git.dns@arista.com Fixes: 456d8aa ("PCI/ASPM: Disable ASPM on MFD function removal to avoid use-after-free") Signed-off-by: Daniel Stodden <dns@arista.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> [kwilczynski: commit log] Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org> Signed-off-by: Marcin Juszkiewicz <mjuszkiewicz@redhat.com>
1 parent 025775a commit 4d87a6e

File tree

1 file changed

+9
-8
lines changed

1 file changed

+9
-8
lines changed

drivers/pci/pcie/aspm.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,16 +1270,16 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
12701270
parent_link = link->parent;
12711271

12721272
/*
1273-
* link->downstream is a pointer to the pci_dev of function 0. If
1274-
* we remove that function, the pci_dev is about to be deallocated,
1275-
* so we can't use link->downstream again. Free the link state to
1276-
* avoid this.
1273+
* Free the parent link state, no later than function 0 (i.e.
1274+
* link->downstream) being removed.
12771275
*
1278-
* If we're removing a non-0 function, it's possible we could
1279-
* retain the link state, but PCIe r6.0, sec 7.5.3.7, recommends
1280-
* programming the same ASPM Control value for all functions of
1281-
* multi-function devices, so disable ASPM for all of them.
1276+
* Do not free the link state any earlier. If function 0 is a
1277+
* switch upstream port, this link state is parent_link to all
1278+
* subordinate ones.
12821279
*/
1280+
if (pdev != link->downstream)
1281+
goto out;
1282+
12831283
pcie_config_aspm_link(link, 0);
12841284
list_del(&link->sibling);
12851285
free_link_state(link);
@@ -1290,6 +1290,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
12901290
pcie_config_aspm_path(parent_link);
12911291
}
12921292

1293+
out:
12931294
mutex_unlock(&aspm_lock);
12941295
up_read(&pci_bus_sem);
12951296
}

0 commit comments

Comments
 (0)