From 4ad136961a7089f357fcfd22e67414fae7823ae4 Mon Sep 17 00:00:00 2001 From: Sriharsha Allenki Date: Mon, 26 Jul 2021 11:33:43 +0530 Subject: [PATCH] pci: pci-msm: Prevent double free of default state In the case of a linkdown during pm_suspend, the pci_saved_state during enumeration(default_state) is used to restore config space. But this state is freed up during pm_resume as part of pm_load_and_free_saved_state. And if this state (default_state) is used again in case of another linkdown, this leads to use after free. Fix this by using a copy of the default_state instead of the original copy for restoring config space incase of a linkdown. Change-Id: I6ac763ed88341c739f0b26992d1e31bf2513fdab Signed-off-by: Sriharsha Allenki --- drivers/pci/controller/pci-msm.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/pci/controller/pci-msm.c b/drivers/pci/controller/pci-msm.c index 35461811c178..ee1ad2de6bda 100644 --- a/drivers/pci/controller/pci-msm.c +++ b/drivers/pci/controller/pci-msm.c @@ -7275,24 +7275,37 @@ static int msm_pcie_pm_suspend(struct pci_dev *dev, if (dev) { if (msm_pcie_confirm_linkup(pcie_dev, true, true, dev)) { + PCIE_DBG(pcie_dev, "PCIe: RC%d: save config space\n", + pcie_dev->rc_idx); ret = pci_save_state(dev); if (ret) { PCIE_ERR(pcie_dev, - "PCIe: RC%d: fail to save state of RC%d:%d.\n", + "PCIe: RC%d: fail to save state:%d.\n", pcie_dev->rc_idx, ret); pcie_dev->suspending = false; return ret; } - pcie_dev->saved_state = pci_store_saved_state(dev); } else { - pci_load_and_free_saved_state(dev, - &pcie_dev->saved_state); - pcie_dev->saved_state = pcie_dev->default_state; + kfree(pcie_dev->saved_state); + pcie_dev->saved_state = NULL; + PCIE_DBG(pcie_dev, - "PCIe: RC%d: saved default config space\n", + "PCIe: RC%d: load default config space\n", pcie_dev->rc_idx); + ret = pci_load_saved_state(dev, pcie_dev->default_state); + if (ret) { + PCIE_ERR(pcie_dev, + "PCIe: RC%d: fail to load default state:%d.\n", + pcie_dev->rc_idx, ret); + pcie_dev->suspending = false; + return ret; + } } + + PCIE_DBG(pcie_dev, "PCIe: RC%d: store saved state\n", + pcie_dev->rc_idx); + pcie_dev->saved_state = pci_store_saved_state(dev); } spin_lock_irqsave(&pcie_dev->cfg_lock,