perf/dwc_pcie: fix duplicate pci_dev devices
authorYunhui Cui <cuiyunhui@bytedance.com>
Thu, 20 Feb 2025 12:17:16 +0000 (20:17 +0800)
committerWill Deacon <will@kernel.org>
Sat, 1 Mar 2025 06:12:37 +0000 (06:12 +0000)
During platform_device_register, wrongly using struct device
pci_dev as platform_data caused a kmemdup copy of pci_dev. Worse
still, accessing the duplicated device leads to list corruption as its
mutex content (e.g., list, magic) remains the same as the original.

Signed-off-by: Yunhui Cui <cuiyunhui@bytedance.com>
Reviewed-by: Shuai Xue <xueshuai@linux.alibaba.com>
Link: https://lore.kernel.org/r/20250220121716.50324-3-cuiyunhui@bytedance.com
Signed-off-by: Will Deacon <will@kernel.org>
drivers/perf/dwc_pcie_pmu.c

index 19fa2ba8dd6704ec12e57644c96f909b606c8601..f851e070760c5628f3c200d2c213af157c9113b8 100644 (file)
@@ -565,9 +565,7 @@ static int dwc_pcie_register_dev(struct pci_dev *pdev)
        u32 sbdf;
 
        sbdf = (pci_domain_nr(pdev->bus) << 16) | PCI_DEVID(pdev->bus->number, pdev->devfn);
-       plat_dev = platform_device_register_data(NULL, "dwc_pcie_pmu", sbdf,
-                                                pdev, sizeof(*pdev));
-
+       plat_dev = platform_device_register_simple("dwc_pcie_pmu", sbdf, NULL, 0);
        if (IS_ERR(plat_dev))
                return PTR_ERR(plat_dev);
 
@@ -616,18 +614,26 @@ static struct notifier_block dwc_pcie_pmu_nb = {
 
 static int dwc_pcie_pmu_probe(struct platform_device *plat_dev)
 {
-       struct pci_dev *pdev = plat_dev->dev.platform_data;
+       struct pci_dev *pdev;
        struct dwc_pcie_pmu *pcie_pmu;
        char *name;
        u32 sbdf;
        u16 vsec;
        int ret;
 
+       sbdf = plat_dev->id;
+       pdev = pci_get_domain_bus_and_slot(sbdf >> 16, PCI_BUS_NUM(sbdf & 0xffff),
+                                          sbdf & 0xff);
+       if (!pdev) {
+               pr_err("No pdev found for the sbdf 0x%x\n", sbdf);
+               return -ENODEV;
+       }
+
        vsec = dwc_pcie_des_cap(pdev);
        if (!vsec)
                return -ENODEV;
 
-       sbdf = plat_dev->id;
+       pci_dev_put(pdev);
        name = devm_kasprintf(&plat_dev->dev, GFP_KERNEL, "dwc_rootport_%x", sbdf);
        if (!name)
                return -ENOMEM;
@@ -642,7 +648,7 @@ static int dwc_pcie_pmu_probe(struct platform_device *plat_dev)
        pcie_pmu->on_cpu = -1;
        pcie_pmu->pmu = (struct pmu){
                .name           = name,
-               .parent         = &pdev->dev,
+               .parent         = &plat_dev->dev,
                .module         = THIS_MODULE,
                .attr_groups    = dwc_pcie_attr_groups,
                .capabilities   = PERF_PMU_CAP_NO_EXCLUDE,