hwrng: amd - Fix PCI device refcount leak
authorXiongfeng Wang <wangxiongfeng2@huawei.com>
Fri, 2 Dec 2022 13:22:33 +0000 (21:22 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 31 Dec 2022 12:32:37 +0000 (13:32 +0100)
[ Upstream commit ecadb5b0111ea19fc7c240bb25d424a94471eb7d ]

for_each_pci_dev() is implemented by pci_get_device(). The comment of
pci_get_device() says that it will increase the reference count for the
returned pci_dev and also decrease the reference count for the input
pci_dev @from if it is not NULL.

If we break for_each_pci_dev() loop with pdev not NULL, we need to call
pci_dev_put() to decrease the reference count. Add the missing
pci_dev_put() for the normal and error path.

Fixes: 96d63c0297cc ("[PATCH] Add AMD HW RNG driver")
Signed-off-by: Xiongfeng Wang <wangxiongfeng2@huawei.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/char/hw_random/amd-rng.c

index c22d418..0555e38 100644 (file)
@@ -143,15 +143,19 @@ static int __init amd_rng_mod_init(void)
 found:
        err = pci_read_config_dword(pdev, 0x58, &pmbase);
        if (err)
-               return err;
+               goto put_dev;
 
        pmbase &= 0x0000FF00;
-       if (pmbase == 0)
-               return -EIO;
+       if (pmbase == 0) {
+               err = -EIO;
+               goto put_dev;
+       }
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
+       if (!priv) {
+               err = -ENOMEM;
+               goto put_dev;
+       }
 
        if (!request_region(pmbase + PMBASE_OFFSET, PMBASE_SIZE, DRV_NAME)) {
                dev_err(&pdev->dev, DRV_NAME " region 0x%x already in use!\n",
@@ -185,6 +189,8 @@ err_iomap:
        release_region(pmbase + PMBASE_OFFSET, PMBASE_SIZE);
 out:
        kfree(priv);
+put_dev:
+       pci_dev_put(pdev);
        return err;
 }
 
@@ -200,6 +206,8 @@ static void __exit amd_rng_mod_exit(void)
 
        release_region(priv->pmbase + PMBASE_OFFSET, PMBASE_SIZE);
 
+       pci_dev_put(priv->pcidev);
+
        kfree(priv);
 }