[PATCH] platform/x86: pmc_atom: Fix PCI device reference leak in pmc_atom_init()

Wentao Liang posted 1 patch 1 week ago
drivers/platform/x86/pmc_atom.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
[PATCH] platform/x86: pmc_atom: Fix PCI device reference leak in pmc_atom_init()
Posted by Wentao Liang 1 week ago
pmc_atom_init() iterates over the PCI devices with for_each_pci_dev()
and returns pmc_setup_dev()'s result directly from inside the loop when
a matching device is found. The reference obtained for the matched
device by pci_get_device() (via for_each_pci_dev()) is never dropped,
leaking a reference to the PCI device on every successful init.

Break out of the loop, drop the reference with pci_dev_put() before
returning, as pci_dev_put() on a NULL pointer is a no-op when no device
was matched.

Fixes: 2b8f8eddaf05 ("x86/platform/intel/pmc_atom: Add Cherrytrail PMC interface")
Cc: stable@vger.kernel.org
Signed-off-by: Wentao Liang <vulab@iscas.ac.cn>
---
 drivers/platform/x86/pmc_atom.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/platform/x86/pmc_atom.c b/drivers/platform/x86/pmc_atom.c
index 48c2a0e59d18..750b72c6c616 100644
--- a/drivers/platform/x86/pmc_atom.c
+++ b/drivers/platform/x86/pmc_atom.c
@@ -579,6 +579,7 @@ static int __init pmc_atom_init(void)
 {
 	struct pci_dev *pdev = NULL;
 	const struct pci_device_id *ent;
+	int ret = -ENODEV;
 
 	/*
 	 * We look for our device - PCU PMC.
@@ -591,11 +592,14 @@ static int __init pmc_atom_init(void)
 	 */
 	for_each_pci_dev(pdev) {
 		ent = pci_match_id(pmc_pci_ids, pdev);
-		if (ent)
-			return pmc_setup_dev(pdev, ent);
+		if (ent) {
+			ret = pmc_setup_dev(pdev, ent);
+			break;
+		}
 	}
-	/* Device not found */
-	return -ENODEV;
+
+	pci_dev_put(pdev);
+	return ret;
 }
 
 device_initcall(pmc_atom_init);
-- 
2.34.1
Re: [PATCH] platform/x86: pmc_atom: Fix PCI device reference leak in pmc_atom_init()
Posted by Andy Shevchenko 1 week ago
On Thu, Sep 17, 2026 at 02:14:14PM +0000, Wentao Liang wrote:
> pmc_atom_init() iterates over the PCI devices with for_each_pci_dev()
> and returns pmc_setup_dev()'s result directly from inside the loop when
> a matching device is found. The reference obtained for the matched
> device by pci_get_device() (via for_each_pci_dev()) is never dropped,
> leaking a reference to the PCI device on every successful init.
> 
> Break out of the loop, drop the reference with pci_dev_put() before
> returning, as pci_dev_put() on a NULL pointer is a no-op when no device
> was matched.

...

>  	/*
>  	 * We look for our device - PCU PMC.

>  	 */

Have you had a chance to read this ^^^ comment in full?

>  	for_each_pci_dev(pdev) {
>  		ent = pci_match_id(pmc_pci_ids, pdev);
> -		if (ent)
> -			return pmc_setup_dev(pdev, ent);
> +		if (ent) {
> +			ret = pmc_setup_dev(pdev, ent);
> +			break;
> +		}
>  	}

...

Have you checked what the below means and why the MODULE_*() are commented out?

>  device_initcall(pmc_atom_init);

-- 
With Best Regards,
Andy Shevchenko