Re: [PATCH] usb: hub: fix refcount leak in usb_new_device()

From: Johan Hovold

Date: Fri Jun 12 2026 - 05:10:18 EST


On Thu, Jun 11, 2026 at 09:02:23PM +0800, WenTao Liang wrote:
> If usb_new_device() fails after pm_runtime_get_noresume() has
> been called, it does not release the corresponding reference.
> In the successful path, the reference is properly dropped via
> pm_runtime_put_sync_autosuspend(). However, when an error
> occurs during enumeration (e.g. usb_enumerate_device() failure)
> or device registration (e.g. device_add() failure), the function
> jumps to the "fail" label. That error cleanup path only disables
> runtime PM and marks the device as suspended, never putting the
> usage count back.

> This results in a permanent imbalance of
> power.usage_count, preventing future runtime PM state transitions
> and proper device cleanup.

Not really, as the device is about to be freed. Sure, the runtime pm
usage count is never balanced, but it does not have any practical
implications whatsoever.

> Fix the leak by adding a pm_runtime_put_noidle() call before
> pm_runtime_disable() in the fail error path, which releases the
> reference without queuing any suspend work and appropriately
> matches the pm_runtime_get
>
> Cc: stable@xxxxxxxxxxxxxxx
> Fixes: 9bbdf1e0afe7 ("USB: convert to the runtime PM framework")

So there is no need for either a Fixes or CC-stable tag here.

> Signed-off-by: WenTao Liang <vulab@xxxxxxxxxxx>

How was this "issue" found? Are you using some kind of static checker or
LLM?

> ---
> drivers/usb/core/hub.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
> index 24960ba9caa9..05f1a4267aec 100644
> --- a/drivers/usb/core/hub.c
> +++ b/drivers/usb/core/hub.c
> @@ -2731,6 +2731,7 @@ int usb_new_device(struct usb_device *udev)
> device_del(&udev->dev);
> fail:
> usb_set_device_state(udev, USB_STATE_NOTATTACHED);
> + pm_runtime_put_noidle(&udev->dev);

The reference should be dropped after disabling (so that the device
cannot possibly be suspended here).

> pm_runtime_disable(&udev->dev);
> pm_runtime_set_suspended(&udev->dev);
> return err;

Johan