| Message ID | 20260317172732.58053-1-adiyenga@cisco.com |
|---|---|
| State | New |
| Headers | show |
| Series | PCI/AER: Fix device reference leak in aer_inject() | expand |
On Tue, Mar 17, 2026 at 10:57:32PM +0530, Aadityarangan Shridhar Iyengar wrote: > In aer_inject(), pcie_port_find_device() returns a device with an > incremented reference count. The function returns this device but never > calls put_device() to release the reference, resulting in a reference leak. From AI (https://sashiko.dev/#/patchset/20260317172732.58053-1-adiyenga%40cisco.com): Is this description accurate? Looking at pcie_port_find_device(), it uses device_for_each_child() with the find_service_iter() callback. Unlike device_find_child(), neither of these functions calls get_device() on the matched child device to increment its reference count. > Fix this by calling put_device() after using the device in both the success > and error paths. > > Fixes: 0e98db259fd8 ("PCI/AER: Reuse existing pcie_port_find_device() interface") > Signed-off-by: Aadityarangan Shridhar Iyengar <adiyenga@cisco.com> > --- > drivers/pci/pcie/aer_inject.c | 2 ++ > 1 file changed, 2 insertions(+) > > diff --git a/drivers/pci/pcie/aer_inject.c b/drivers/pci/pcie/aer_inject.c > index 09bfc7194ef3..5025843157b1 100644 > --- a/drivers/pci/pcie/aer_inject.c > +++ b/drivers/pci/pcie/aer_inject.c > @@ -467,11 +467,13 @@ static int aer_inject(struct aer_error_inj *einj) > if (!get_service_data(edev)) { > pci_warn(edev->port, "AER service is not initialized\n"); > ret = -EPROTONOSUPPORT; > + put_device(device); > goto out_put; > } > pci_info(edev->port, "Injecting errors %08x/%08x into device %s\n", > einj->cor_status, einj->uncor_status, pci_name(dev)); > ret = irq_inject_interrupt(edev->irq); > + put_device(device); > } else { > pci_err(rpdev, "AER device not found\n"); > ret = -ENODEV; > -- > 2.35.6 >
On Mon, Mar 17, 2026 at 09:17:00PM +0000, Bjorn Helgaas wrote: > From AI > (https://sashiko.dev/#/patchset/20260317172732.58053-1-adiyenga%40cisco.com): > > Is this description accurate? Looking at pcie_port_find_device(), it > uses device_for_each_child() with the find_service_iter() callback. > Unlike device_find_child(), neither of these functions calls > get_device() on the matched child device to increment its reference > count. You're right, the description is inaccurate. I confused device_for_each_child() with device_find_child(). The latter explicitly calls get_device() on the matched child and documents that the caller must call put_device(), but device_for_each_child() does not — the iterator ref is dropped by klist_iter_exit() and no caller-owned reference is returned. Adding put_device() here would underflow the refcount, which is worse than the original code. Please drop this patch. Sorry for the noise. Aditya
diff --git a/drivers/pci/pcie/aer_inject.c b/drivers/pci/pcie/aer_inject.c index 09bfc7194ef3..5025843157b1 100644 --- a/drivers/pci/pcie/aer_inject.c +++ b/drivers/pci/pcie/aer_inject.c @@ -467,11 +467,13 @@ static int aer_inject(struct aer_error_inj *einj) if (!get_service_data(edev)) { pci_warn(edev->port, "AER service is not initialized\n"); ret = -EPROTONOSUPPORT; + put_device(device); goto out_put; } pci_info(edev->port, "Injecting errors %08x/%08x into device %s\n", einj->cor_status, einj->uncor_status, pci_name(dev)); ret = irq_inject_interrupt(edev->irq); + put_device(device); } else { pci_err(rpdev, "AER device not found\n"); ret = -ENODEV;
In aer_inject(), pcie_port_find_device() returns a device with an incremented reference count. The function returns this device but never calls put_device() to release the reference, resulting in a reference leak. Fix this by calling put_device() after using the device in both the success and error paths. Fixes: 0e98db259fd8 ("PCI/AER: Reuse existing pcie_port_find_device() interface") Signed-off-by: Aadityarangan Shridhar Iyengar <adiyenga@cisco.com> --- drivers/pci/pcie/aer_inject.c | 2 ++ 1 file changed, 2 insertions(+)