VYPR
Unrated severityNVD Advisory· Published May 27, 2026· Updated May 27, 2026

CVE-2026-45938

CVE-2026-45938

Description

In the Linux kernel, the following vulnerability has been resolved:

power: supply: pm8916_lbc: Fix use-after-free in power_supply_changed()

Using the devm_ variant for requesting IRQ _before_ the devm_ variant for allocating/registering the power_supply handle, means that the power_supply handle will be deallocated/unregistered _before_ the interrupt handler (since devm_ naturally deallocates in reverse allocation order). This means that during removal, there is a race condition where an interrupt can fire just _after_ the power_supply handle has been freed, *but* just _before_ the corresponding unregistration of the IRQ handler has run.

This will lead to the IRQ handler calling power_supply_changed() with a freed power_supply handle. Which usually crashes the system or otherwise silently corrupts the memory...

Note that there is a similar situation which can also happen during probe(); the possibility of an interrupt firing _before_ registering the power_supply handle. This would then lead to the nasty situation of using the power_supply handle *uninitialized* in power_supply_changed().

Fix this racy use-after-free by making sure the IRQ is requested _after_ the registration of the power_supply handle.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Use-after-free in Linux kernel's pm8916 LBC power supply driver due to devm IRQ request before power supply registration, fixed by reordering to register IRQ after power supply.

Vulnerability

The Linux kernel power supply driver pm8916_lbc (Qualcomm PM8916 LBC) contains a use-after-free vulnerability. The driver uses the devm_ resource-managed API variant for requesting the interrupt before allocating and registering the power_supply handle. Because devm_ resources are freed in reverse allocation order, the power_supply handle is deallocated before the interrupt handler is unregistered. This creates a race condition during driver removal, or during probe if an interrupt fires before the power supply is registered. The affected versions are those prior to the commit that fixes the ordering (the stable kernel commit shown in the reference).

Exploitation

An attacker would need local access to trigger the race condition, either by causing the driver to be removed (e.g., via hotplug or module unloading) or by exploiting a timing window during probe. The preconditions include having the ability to trigger an interrupt (e.g., from the hardware) during the vulnerable remove or probe sequence. The exact steps involve invoking a driver removal that frees the power_supply structure while an interrupt is still possible before the IRQ handler is unregistered, causing power_supply_changed() to be called on freed memory.

Impact

Successful exploitation leads to a use-after-free condition. This typically causes a system crash (kernel panic) or, in worst cases, memory corruption that could potentially be leveraged for privilege escalation. The attacker gains no direct control but may cause denial-of-service or undefined behavior.

Mitigation

The fix is included in the Linux kernel stable commit d7d31fc99d24 [1]. Users should update to a kernel version containing this commit. The patch reorders the resource management so that the IRQ is requested _after_ the power_supply handle is registered. No workaround is available besides updating the kernel. There is no indication that this CVE is listed in CISA's Known Exploited Vulnerabilities (KEV) catalog.

[1]: https://git.kernel.org/stable/c/d7d31fc99d248d5f47588f50dce5c7599c991c6a

AI Insight generated on May 27, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

1

Patches

8
b7508129978a

power: supply: pm8916_lbc: Fix use-after-free in power_supply_changed()

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitWaqar HameedDec 20, 2025Fixed in 7.0via kernel-cna
1 file changed · +9 10
  • drivers/power/supply/pm8916_lbc.c+9 10 modified
    diff --git a/drivers/power/supply/pm8916_lbc.c b/drivers/power/supply/pm8916_lbc.c
    index c74b75b1b2676c..3ca717d84aade6 100644
    --- a/drivers/power/supply/pm8916_lbc.c
    +++ b/drivers/power/supply/pm8916_lbc.c
    @@ -274,15 +274,6 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev)
     		return dev_err_probe(dev, -EINVAL,
     				     "Wrong amount of reg values: %d (4 expected)\n", len);
     
    -	irq = platform_get_irq_byname(pdev, "usb_vbus");
    -	if (irq < 0)
    -		return irq;
    -
    -	ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq,
    -					IRQF_ONESHOT, "pm8916_lbc", chg);
    -	if (ret)
    -		return ret;
    -
     	ret = device_property_read_u32_array(dev, "reg", chg->reg, len);
     	if (ret)
     		return ret;
    @@ -332,6 +323,15 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev)
     	if (ret)
     		return dev_err_probe(dev, ret, "Unable to get battery info\n");
     
    +	irq = platform_get_irq_byname(pdev, "usb_vbus");
    +	if (irq < 0)
    +		return irq;
    +
    +	ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq,
    +					IRQF_ONESHOT, "pm8916_lbc", chg);
    +	if (ret)
    +		return ret;
    +
     	chg->edev = devm_extcon_dev_allocate(dev, pm8916_lbc_charger_cable);
     	if (IS_ERR(chg->edev))
     		return PTR_ERR(chg->edev);
    -- 
    cgit 1.3-korg
    
    
    
dbe579e620ef

power: supply: pm8916_lbc: Fix use-after-free in power_supply_changed()

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitWaqar HameedDec 20, 2025Fixed in 6.12.75via kernel-cna
1 file changed · +9 10
  • drivers/power/supply/pm8916_lbc.c+9 10 modified
    diff --git a/drivers/power/supply/pm8916_lbc.c b/drivers/power/supply/pm8916_lbc.c
    index 6d92e98cbecc68..ab324ce3b87219 100644
    --- a/drivers/power/supply/pm8916_lbc.c
    +++ b/drivers/power/supply/pm8916_lbc.c
    @@ -274,15 +274,6 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev)
     		return dev_err_probe(dev, -EINVAL,
     				     "Wrong amount of reg values: %d (4 expected)\n", len);
     
    -	irq = platform_get_irq_byname(pdev, "usb_vbus");
    -	if (irq < 0)
    -		return irq;
    -
    -	ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq,
    -					IRQF_ONESHOT, "pm8916_lbc", chg);
    -	if (ret)
    -		return ret;
    -
     	ret = device_property_read_u32_array(dev, "reg", chg->reg, len);
     	if (ret)
     		return ret;
    @@ -332,6 +323,15 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev)
     	if (ret)
     		return dev_err_probe(dev, ret, "Unable to get battery info\n");
     
    +	irq = platform_get_irq_byname(pdev, "usb_vbus");
    +	if (irq < 0)
    +		return irq;
    +
    +	ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq,
    +					IRQF_ONESHOT, "pm8916_lbc", chg);
    +	if (ret)
    +		return ret;
    +
     	chg->edev = devm_extcon_dev_allocate(dev, pm8916_lbc_charger_cable);
     	if (IS_ERR(chg->edev))
     		return PTR_ERR(chg->edev);
    -- 
    cgit 1.3-korg
    
    
    
08e674e9862a

power: supply: pm8916_lbc: Fix use-after-free in power_supply_changed()

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitWaqar HameedDec 20, 2025Fixed in 6.18.14via kernel-cna
1 file changed · +9 10
  • drivers/power/supply/pm8916_lbc.c+9 10 modified
    diff --git a/drivers/power/supply/pm8916_lbc.c b/drivers/power/supply/pm8916_lbc.c
    index c74b75b1b2676c..3ca717d84aade6 100644
    --- a/drivers/power/supply/pm8916_lbc.c
    +++ b/drivers/power/supply/pm8916_lbc.c
    @@ -274,15 +274,6 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev)
     		return dev_err_probe(dev, -EINVAL,
     				     "Wrong amount of reg values: %d (4 expected)\n", len);
     
    -	irq = platform_get_irq_byname(pdev, "usb_vbus");
    -	if (irq < 0)
    -		return irq;
    -
    -	ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq,
    -					IRQF_ONESHOT, "pm8916_lbc", chg);
    -	if (ret)
    -		return ret;
    -
     	ret = device_property_read_u32_array(dev, "reg", chg->reg, len);
     	if (ret)
     		return ret;
    @@ -332,6 +323,15 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev)
     	if (ret)
     		return dev_err_probe(dev, ret, "Unable to get battery info\n");
     
    +	irq = platform_get_irq_byname(pdev, "usb_vbus");
    +	if (irq < 0)
    +		return irq;
    +
    +	ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq,
    +					IRQF_ONESHOT, "pm8916_lbc", chg);
    +	if (ret)
    +		return ret;
    +
     	chg->edev = devm_extcon_dev_allocate(dev, pm8916_lbc_charger_cable);
     	if (IS_ERR(chg->edev))
     		return PTR_ERR(chg->edev);
    -- 
    cgit 1.3-korg
    
    
    
d7d31fc99d24

power: supply: pm8916_lbc: Fix use-after-free in power_supply_changed()

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitWaqar HameedDec 20, 2025Fixed in 6.19.4via kernel-cna
1 file changed · +9 10
  • drivers/power/supply/pm8916_lbc.c+9 10 modified
    diff --git a/drivers/power/supply/pm8916_lbc.c b/drivers/power/supply/pm8916_lbc.c
    index c74b75b1b2676c..3ca717d84aade6 100644
    --- a/drivers/power/supply/pm8916_lbc.c
    +++ b/drivers/power/supply/pm8916_lbc.c
    @@ -274,15 +274,6 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev)
     		return dev_err_probe(dev, -EINVAL,
     				     "Wrong amount of reg values: %d (4 expected)\n", len);
     
    -	irq = platform_get_irq_byname(pdev, "usb_vbus");
    -	if (irq < 0)
    -		return irq;
    -
    -	ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq,
    -					IRQF_ONESHOT, "pm8916_lbc", chg);
    -	if (ret)
    -		return ret;
    -
     	ret = device_property_read_u32_array(dev, "reg", chg->reg, len);
     	if (ret)
     		return ret;
    @@ -332,6 +323,15 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev)
     	if (ret)
     		return dev_err_probe(dev, ret, "Unable to get battery info\n");
     
    +	irq = platform_get_irq_byname(pdev, "usb_vbus");
    +	if (irq < 0)
    +		return irq;
    +
    +	ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq,
    +					IRQF_ONESHOT, "pm8916_lbc", chg);
    +	if (ret)
    +		return ret;
    +
     	chg->edev = devm_extcon_dev_allocate(dev, pm8916_lbc_charger_cable);
     	if (IS_ERR(chg->edev))
     		return PTR_ERR(chg->edev);
    -- 
    cgit 1.3-korg
    
    
    
d7d31fc99d24

power: supply: pm8916_lbc: Fix use-after-free in power_supply_changed()

1 file changed · +9 10
  • drivers/power/supply/pm8916_lbc.c+9 10 modified
    diff --git a/drivers/power/supply/pm8916_lbc.c b/drivers/power/supply/pm8916_lbc.c
    index c74b75b1b2676c..3ca717d84aade6 100644
    --- a/drivers/power/supply/pm8916_lbc.c
    +++ b/drivers/power/supply/pm8916_lbc.c
    @@ -274,15 +274,6 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev)
     		return dev_err_probe(dev, -EINVAL,
     				     "Wrong amount of reg values: %d (4 expected)\n", len);
     
    -	irq = platform_get_irq_byname(pdev, "usb_vbus");
    -	if (irq < 0)
    -		return irq;
    -
    -	ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq,
    -					IRQF_ONESHOT, "pm8916_lbc", chg);
    -	if (ret)
    -		return ret;
    -
     	ret = device_property_read_u32_array(dev, "reg", chg->reg, len);
     	if (ret)
     		return ret;
    @@ -332,6 +323,15 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev)
     	if (ret)
     		return dev_err_probe(dev, ret, "Unable to get battery info\n");
     
    +	irq = platform_get_irq_byname(pdev, "usb_vbus");
    +	if (irq < 0)
    +		return irq;
    +
    +	ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq,
    +					IRQF_ONESHOT, "pm8916_lbc", chg);
    +	if (ret)
    +		return ret;
    +
     	chg->edev = devm_extcon_dev_allocate(dev, pm8916_lbc_charger_cable);
     	if (IS_ERR(chg->edev))
     		return PTR_ERR(chg->edev);
    -- 
    cgit 1.3-korg
    
    
    
08e674e9862a

power: supply: pm8916_lbc: Fix use-after-free in power_supply_changed()

1 file changed · +9 10
  • drivers/power/supply/pm8916_lbc.c+9 10 modified
    diff --git a/drivers/power/supply/pm8916_lbc.c b/drivers/power/supply/pm8916_lbc.c
    index c74b75b1b2676c..3ca717d84aade6 100644
    --- a/drivers/power/supply/pm8916_lbc.c
    +++ b/drivers/power/supply/pm8916_lbc.c
    @@ -274,15 +274,6 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev)
     		return dev_err_probe(dev, -EINVAL,
     				     "Wrong amount of reg values: %d (4 expected)\n", len);
     
    -	irq = platform_get_irq_byname(pdev, "usb_vbus");
    -	if (irq < 0)
    -		return irq;
    -
    -	ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq,
    -					IRQF_ONESHOT, "pm8916_lbc", chg);
    -	if (ret)
    -		return ret;
    -
     	ret = device_property_read_u32_array(dev, "reg", chg->reg, len);
     	if (ret)
     		return ret;
    @@ -332,6 +323,15 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev)
     	if (ret)
     		return dev_err_probe(dev, ret, "Unable to get battery info\n");
     
    +	irq = platform_get_irq_byname(pdev, "usb_vbus");
    +	if (irq < 0)
    +		return irq;
    +
    +	ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq,
    +					IRQF_ONESHOT, "pm8916_lbc", chg);
    +	if (ret)
    +		return ret;
    +
     	chg->edev = devm_extcon_dev_allocate(dev, pm8916_lbc_charger_cable);
     	if (IS_ERR(chg->edev))
     		return PTR_ERR(chg->edev);
    -- 
    cgit 1.3-korg
    
    
    
b7508129978a

power: supply: pm8916_lbc: Fix use-after-free in power_supply_changed()

1 file changed · +9 10
  • drivers/power/supply/pm8916_lbc.c+9 10 modified
    diff --git a/drivers/power/supply/pm8916_lbc.c b/drivers/power/supply/pm8916_lbc.c
    index c74b75b1b2676c..3ca717d84aade6 100644
    --- a/drivers/power/supply/pm8916_lbc.c
    +++ b/drivers/power/supply/pm8916_lbc.c
    @@ -274,15 +274,6 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev)
     		return dev_err_probe(dev, -EINVAL,
     				     "Wrong amount of reg values: %d (4 expected)\n", len);
     
    -	irq = platform_get_irq_byname(pdev, "usb_vbus");
    -	if (irq < 0)
    -		return irq;
    -
    -	ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq,
    -					IRQF_ONESHOT, "pm8916_lbc", chg);
    -	if (ret)
    -		return ret;
    -
     	ret = device_property_read_u32_array(dev, "reg", chg->reg, len);
     	if (ret)
     		return ret;
    @@ -332,6 +323,15 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev)
     	if (ret)
     		return dev_err_probe(dev, ret, "Unable to get battery info\n");
     
    +	irq = platform_get_irq_byname(pdev, "usb_vbus");
    +	if (irq < 0)
    +		return irq;
    +
    +	ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq,
    +					IRQF_ONESHOT, "pm8916_lbc", chg);
    +	if (ret)
    +		return ret;
    +
     	chg->edev = devm_extcon_dev_allocate(dev, pm8916_lbc_charger_cable);
     	if (IS_ERR(chg->edev))
     		return PTR_ERR(chg->edev);
    -- 
    cgit 1.3-korg
    
    
    
dbe579e620ef

power: supply: pm8916_lbc: Fix use-after-free in power_supply_changed()

1 file changed · +9 10
  • drivers/power/supply/pm8916_lbc.c+9 10 modified
    diff --git a/drivers/power/supply/pm8916_lbc.c b/drivers/power/supply/pm8916_lbc.c
    index 6d92e98cbecc68..ab324ce3b87219 100644
    --- a/drivers/power/supply/pm8916_lbc.c
    +++ b/drivers/power/supply/pm8916_lbc.c
    @@ -274,15 +274,6 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev)
     		return dev_err_probe(dev, -EINVAL,
     				     "Wrong amount of reg values: %d (4 expected)\n", len);
     
    -	irq = platform_get_irq_byname(pdev, "usb_vbus");
    -	if (irq < 0)
    -		return irq;
    -
    -	ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq,
    -					IRQF_ONESHOT, "pm8916_lbc", chg);
    -	if (ret)
    -		return ret;
    -
     	ret = device_property_read_u32_array(dev, "reg", chg->reg, len);
     	if (ret)
     		return ret;
    @@ -332,6 +323,15 @@ static int pm8916_lbc_charger_probe(struct platform_device *pdev)
     	if (ret)
     		return dev_err_probe(dev, ret, "Unable to get battery info\n");
     
    +	irq = platform_get_irq_byname(pdev, "usb_vbus");
    +	if (irq < 0)
    +		return irq;
    +
    +	ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq,
    +					IRQF_ONESHOT, "pm8916_lbc", chg);
    +	if (ret)
    +		return ret;
    +
     	chg->edev = devm_extcon_dev_allocate(dev, pm8916_lbc_charger_cable);
     	if (IS_ERR(chg->edev))
     		return PTR_ERR(chg->edev);
    -- 
    cgit 1.3-korg
    
    
    

Vulnerability mechanics

Root cause

"Incorrect ordering of devm-managed allocations: the IRQ is requested before the power_supply handle is registered, so during removal the power_supply is freed before the IRQ handler is unregistered, creating a use-after-free race in power_supply_changed()."

Attack vector

An attacker with physical access or control over the USB VBUS line can trigger the "usb_vbus" interrupt at the precise moment the pm8916_lbc driver is being removed (unbind/rmmod). Because the devm-managed IRQ was allocated before the devm-managed power_supply registration, the power_supply handle is freed first during reverse-ordered devm cleanup. A racing interrupt that fires after the power_supply is freed but before the IRQ is unregistered causes the handler to call power_supply_changed() on freed memory, leading to a kernel crash or memory corruption [patch_id=2661177]. A similar window exists during probe: an interrupt arriving before power_supply registration would use an uninitialized handle.

Affected code

The vulnerability is in `drivers/power/supply/pm8916_lbc.c` in the `pm8916_lbc_charger_probe()` function. The original code called `devm_request_threaded_irq()` (for the "usb_vbus" IRQ) before the `power_supply` handle was allocated and registered via the devm power supply API. This ordering defect is present in all patched versions [patch_id=2661177].

What the fix does

The patch moves the `platform_get_irq_byname()` and `devm_request_threaded_irq()` calls to after the `power_supply` registration (specifically after the `power_supply_get_battery_info()` call) [patch_id=2661177]. This ensures that during removal, the devm framework unregisters the IRQ handler before freeing the power_supply handle (reverse allocation order), closing both the removal race and the probe-time window where an interrupt could fire against an uninitialized handle.

Preconditions

  • inputThe attacker must be able to trigger the 'usb_vbus' interrupt (e.g., by manipulating USB VBUS) while the pm8916_lbc driver is being removed or probed.
  • configThe system must be running a kernel with the pm8916_lbc driver loaded and the vulnerable ordering of devm allocations.

Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.