CVE-2026-45867
Description
In the Linux kernel, the following vulnerability has been resolved:
power: supply: act8945a: 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.
A use-after-free in the Linux kernel's act8945a charger driver occurs due to devm IRQ request before power supply registration, potentially leading to system crash or memory corruption.
Vulnerability
A use-after-free vulnerability exists in the Linux kernel's act8945a power supply charger driver. The driver requests the interrupt handler using the devm_ (managed) API *before* allocating and registering the power_supply device. During device removal, devm_ releases resources in reverse order, so the power_supply handle is freed before the IRQ handler is unregistered. A race window allows an interrupt to fire after the power_supply handle has been freed but before the IRQ handler is removed, causing the handler to call power_supply_changed() with a freed pointer. The same ordering flaw also causes a potential use of an uninitialized handle if an interrupt fires during probe, before registration. Affected versions include all Linux kernel trees before the commit f27eb76def5c07e4d7cc468b40741f19dafc83ce was applied [1].
Exploitation
An attacker does not need special privileges. The vulnerability is triggered during normal device removal (unbind or module unload) or during probe if an interrupt arrives before the power_supply is registered. The attacker must have the ability to cause the driver to remove (e.g., via hot-unplug of the hardware) and to generate a racing interrupt, which may happen naturally depending on hardware behavior. No authentication is required; the race is purely a timing issue at the kernel driver level.
Impact
Successful exploitation leads to a use-after-free condition in the interrupt handler, which calls power_supply_changed() on a freed or uninitialized power_supply structure. This can crash the system (kernel panic) or silently corrupt memory, potentially leading to privilege escalation or information disclosure depending on system state. The vulnerability is rated with a high severity due to the likelihood of a crash and the possibility of memory corruption.
Mitigation
The fix is to ensure the IRQ is requested *after* the power_supply handle is registered. The commit f27eb76def5c07e4d7cc468b40741f19dafc83ce resolves the issue by reordering the initialization in the driver. Users should apply the corresponding kernel update from their Linux distribution. No workaround is available if the patch is not applied, as the issue is inherent in the driver's lifecycle management. The vulnerability is not known to be listed in CISA's Known Exploited Vulnerabilities (KEV) catalog.
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
1Patches
1683c1bd466c51power: supply: act8945a: Fix use-after-free in power_supply_changed()
1 file changed · +8 −9
drivers/power/supply/act8945a_charger.c+8 −9 modifieddiff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c index 3901a02f326a55..9dec4486b1439a 100644 --- a/drivers/power/supply/act8945a_charger.c +++ b/drivers/power/supply/act8945a_charger.c @@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev) return irq ?: -ENXIO; } - ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, - IRQF_TRIGGER_FALLING, "act8945a_interrupt", - charger); - if (ret) { - dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); - return ret; - } - charger->desc.name = "act8945a-charger"; charger->desc.get_property = act8945a_charger_get_property; charger->desc.properties = act8945a_charger_props; @@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev) return PTR_ERR(charger->psy); } + ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, + IRQF_TRIGGER_FALLING, "act8945a_interrupt", + charger); + if (ret) { + dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); + return ret; + } + platform_set_drvdata(pdev, charger); INIT_WORK(&charger->work, act8945a_work); -- cgit 1.3-korg
f2a0777b1e5apower: supply: act8945a: Fix use-after-free in power_supply_changed()
1 file changed · +8 −9
drivers/power/supply/act8945a_charger.c+8 −9 modifieddiff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c index 5f3eb6941d0586..a12cbfeca11238 100644 --- a/drivers/power/supply/act8945a_charger.c +++ b/drivers/power/supply/act8945a_charger.c @@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev) return irq ?: -ENXIO; } - ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, - IRQF_TRIGGER_FALLING, "act8945a_interrupt", - charger); - if (ret) { - dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); - return ret; - } - charger->desc.name = "act8945a-charger"; charger->desc.get_property = act8945a_charger_get_property; charger->desc.properties = act8945a_charger_props; @@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev) return PTR_ERR(charger->psy); } + ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, + IRQF_TRIGGER_FALLING, "act8945a_interrupt", + charger); + if (ret) { + dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); + return ret; + } + platform_set_drvdata(pdev, charger); INIT_WORK(&charger->work, act8945a_work); -- cgit 1.3-korg
0768e8525a46power: supply: act8945a: Fix use-after-free in power_supply_changed()
1 file changed · +8 −9
drivers/power/supply/act8945a_charger.c+8 −9 modifieddiff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c index e9b5f42837729f..e9cb06daecea90 100644 --- a/drivers/power/supply/act8945a_charger.c +++ b/drivers/power/supply/act8945a_charger.c @@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev) return irq ?: -ENXIO; } - ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, - IRQF_TRIGGER_FALLING, "act8945a_interrupt", - charger); - if (ret) { - dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); - return ret; - } - charger->desc.name = "act8945a-charger"; charger->desc.get_property = act8945a_charger_get_property; charger->desc.properties = act8945a_charger_props; @@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev) return PTR_ERR(charger->psy); } + ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, + IRQF_TRIGGER_FALLING, "act8945a_interrupt", + charger); + if (ret) { + dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); + return ret; + } + platform_set_drvdata(pdev, charger); INIT_WORK(&charger->work, act8945a_work); -- cgit 1.3-korg
697bb5dc0cb4power: supply: act8945a: Fix use-after-free in power_supply_changed()
1 file changed · +8 −9
drivers/power/supply/act8945a_charger.c+8 −9 modifieddiff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c index e9b5f42837729f..e9cb06daecea90 100644 --- a/drivers/power/supply/act8945a_charger.c +++ b/drivers/power/supply/act8945a_charger.c @@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev) return irq ?: -ENXIO; } - ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, - IRQF_TRIGGER_FALLING, "act8945a_interrupt", - charger); - if (ret) { - dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); - return ret; - } - charger->desc.name = "act8945a-charger"; charger->desc.get_property = act8945a_charger_get_property; charger->desc.properties = act8945a_charger_props; @@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev) return PTR_ERR(charger->psy); } + ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, + IRQF_TRIGGER_FALLING, "act8945a_interrupt", + charger); + if (ret) { + dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); + return ret; + } + platform_set_drvdata(pdev, charger); INIT_WORK(&charger->work, act8945a_work); -- cgit 1.3-korg
f27eb76def5cpower: supply: act8945a: Fix use-after-free in power_supply_changed()
1 file changed · +8 −9
drivers/power/supply/act8945a_charger.c+8 −9 modifieddiff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c index 3901a02f326a55..9dec4486b1439a 100644 --- a/drivers/power/supply/act8945a_charger.c +++ b/drivers/power/supply/act8945a_charger.c @@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev) return irq ?: -ENXIO; } - ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, - IRQF_TRIGGER_FALLING, "act8945a_interrupt", - charger); - if (ret) { - dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); - return ret; - } - charger->desc.name = "act8945a-charger"; charger->desc.get_property = act8945a_charger_get_property; charger->desc.properties = act8945a_charger_props; @@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev) return PTR_ERR(charger->psy); } + ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, + IRQF_TRIGGER_FALLING, "act8945a_interrupt", + charger); + if (ret) { + dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); + return ret; + } + platform_set_drvdata(pdev, charger); INIT_WORK(&charger->work, act8945a_work); -- cgit 1.3-korg
3291c51d4684power: supply: act8945a: Fix use-after-free in power_supply_changed()
1 file changed · +8 −9
drivers/power/supply/act8945a_charger.c+8 −9 modifieddiff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c index 3901a02f326a55..9dec4486b1439a 100644 --- a/drivers/power/supply/act8945a_charger.c +++ b/drivers/power/supply/act8945a_charger.c @@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev) return irq ?: -ENXIO; } - ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, - IRQF_TRIGGER_FALLING, "act8945a_interrupt", - charger); - if (ret) { - dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); - return ret; - } - charger->desc.name = "act8945a-charger"; charger->desc.get_property = act8945a_charger_get_property; charger->desc.properties = act8945a_charger_props; @@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev) return PTR_ERR(charger->psy); } + ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, + IRQF_TRIGGER_FALLING, "act8945a_interrupt", + charger); + if (ret) { + dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); + return ret; + } + platform_set_drvdata(pdev, charger); INIT_WORK(&charger->work, act8945a_work); -- cgit 1.3-korg
76a42ba547a9power: supply: act8945a: Fix use-after-free in power_supply_changed()
1 file changed · +8 −9
drivers/power/supply/act8945a_charger.c+8 −9 modifieddiff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c index 51122bfbf196c9..699030bfa296ac 100644 --- a/drivers/power/supply/act8945a_charger.c +++ b/drivers/power/supply/act8945a_charger.c @@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev) return irq ?: -ENXIO; } - ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, - IRQF_TRIGGER_FALLING, "act8945a_interrupt", - charger); - if (ret) { - dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); - return ret; - } - charger->desc.name = "act8945a-charger"; charger->desc.get_property = act8945a_charger_get_property; charger->desc.properties = act8945a_charger_props; @@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev) return PTR_ERR(charger->psy); } + ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, + IRQF_TRIGGER_FALLING, "act8945a_interrupt", + charger); + if (ret) { + dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); + return ret; + } + platform_set_drvdata(pdev, charger); INIT_WORK(&charger->work, act8945a_work); -- cgit 1.3-korg
d023ef9f748bpower: supply: act8945a: Fix use-after-free in power_supply_changed()
1 file changed · +8 −9
drivers/power/supply/act8945a_charger.c+8 −9 modifieddiff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c index e9b5f42837729f..e9cb06daecea90 100644 --- a/drivers/power/supply/act8945a_charger.c +++ b/drivers/power/supply/act8945a_charger.c @@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev) return irq ?: -ENXIO; } - ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, - IRQF_TRIGGER_FALLING, "act8945a_interrupt", - charger); - if (ret) { - dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); - return ret; - } - charger->desc.name = "act8945a-charger"; charger->desc.get_property = act8945a_charger_get_property; charger->desc.properties = act8945a_charger_props; @@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev) return PTR_ERR(charger->psy); } + ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, + IRQF_TRIGGER_FALLING, "act8945a_interrupt", + charger); + if (ret) { + dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); + return ret; + } + platform_set_drvdata(pdev, charger); INIT_WORK(&charger->work, act8945a_work); -- cgit 1.3-korg
0768e8525a46power: supply: act8945a: Fix use-after-free in power_supply_changed()
1 file changed · +8 −9
drivers/power/supply/act8945a_charger.c+8 −9 modifieddiff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c index e9b5f42837729f..e9cb06daecea90 100644 --- a/drivers/power/supply/act8945a_charger.c +++ b/drivers/power/supply/act8945a_charger.c @@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev) return irq ?: -ENXIO; } - ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, - IRQF_TRIGGER_FALLING, "act8945a_interrupt", - charger); - if (ret) { - dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); - return ret; - } - charger->desc.name = "act8945a-charger"; charger->desc.get_property = act8945a_charger_get_property; charger->desc.properties = act8945a_charger_props; @@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev) return PTR_ERR(charger->psy); } + ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, + IRQF_TRIGGER_FALLING, "act8945a_interrupt", + charger); + if (ret) { + dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); + return ret; + } + platform_set_drvdata(pdev, charger); INIT_WORK(&charger->work, act8945a_work); -- cgit 1.3-korg
76a42ba547a9power: supply: act8945a: Fix use-after-free in power_supply_changed()
1 file changed · +8 −9
drivers/power/supply/act8945a_charger.c+8 −9 modifieddiff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c index 51122bfbf196c9..699030bfa296ac 100644 --- a/drivers/power/supply/act8945a_charger.c +++ b/drivers/power/supply/act8945a_charger.c @@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev) return irq ?: -ENXIO; } - ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, - IRQF_TRIGGER_FALLING, "act8945a_interrupt", - charger); - if (ret) { - dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); - return ret; - } - charger->desc.name = "act8945a-charger"; charger->desc.get_property = act8945a_charger_get_property; charger->desc.properties = act8945a_charger_props; @@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev) return PTR_ERR(charger->psy); } + ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, + IRQF_TRIGGER_FALLING, "act8945a_interrupt", + charger); + if (ret) { + dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); + return ret; + } + platform_set_drvdata(pdev, charger); INIT_WORK(&charger->work, act8945a_work); -- cgit 1.3-korg
83c1bd466c51power: supply: act8945a: Fix use-after-free in power_supply_changed()
1 file changed · +8 −9
drivers/power/supply/act8945a_charger.c+8 −9 modifieddiff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c index 3901a02f326a55..9dec4486b1439a 100644 --- a/drivers/power/supply/act8945a_charger.c +++ b/drivers/power/supply/act8945a_charger.c @@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev) return irq ?: -ENXIO; } - ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, - IRQF_TRIGGER_FALLING, "act8945a_interrupt", - charger); - if (ret) { - dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); - return ret; - } - charger->desc.name = "act8945a-charger"; charger->desc.get_property = act8945a_charger_get_property; charger->desc.properties = act8945a_charger_props; @@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev) return PTR_ERR(charger->psy); } + ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, + IRQF_TRIGGER_FALLING, "act8945a_interrupt", + charger); + if (ret) { + dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); + return ret; + } + platform_set_drvdata(pdev, charger); INIT_WORK(&charger->work, act8945a_work); -- cgit 1.3-korg
d023ef9f748bpower: supply: act8945a: Fix use-after-free in power_supply_changed()
1 file changed · +8 −9
drivers/power/supply/act8945a_charger.c+8 −9 modifieddiff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c index e9b5f42837729f..e9cb06daecea90 100644 --- a/drivers/power/supply/act8945a_charger.c +++ b/drivers/power/supply/act8945a_charger.c @@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev) return irq ?: -ENXIO; } - ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, - IRQF_TRIGGER_FALLING, "act8945a_interrupt", - charger); - if (ret) { - dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); - return ret; - } - charger->desc.name = "act8945a-charger"; charger->desc.get_property = act8945a_charger_get_property; charger->desc.properties = act8945a_charger_props; @@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev) return PTR_ERR(charger->psy); } + ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, + IRQF_TRIGGER_FALLING, "act8945a_interrupt", + charger); + if (ret) { + dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); + return ret; + } + platform_set_drvdata(pdev, charger); INIT_WORK(&charger->work, act8945a_work); -- cgit 1.3-korg
f2a0777b1e5apower: supply: act8945a: Fix use-after-free in power_supply_changed()
1 file changed · +8 −9
drivers/power/supply/act8945a_charger.c+8 −9 modifieddiff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c index 5f3eb6941d0586..a12cbfeca11238 100644 --- a/drivers/power/supply/act8945a_charger.c +++ b/drivers/power/supply/act8945a_charger.c @@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev) return irq ?: -ENXIO; } - ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, - IRQF_TRIGGER_FALLING, "act8945a_interrupt", - charger); - if (ret) { - dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); - return ret; - } - charger->desc.name = "act8945a-charger"; charger->desc.get_property = act8945a_charger_get_property; charger->desc.properties = act8945a_charger_props; @@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev) return PTR_ERR(charger->psy); } + ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, + IRQF_TRIGGER_FALLING, "act8945a_interrupt", + charger); + if (ret) { + dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); + return ret; + } + platform_set_drvdata(pdev, charger); INIT_WORK(&charger->work, act8945a_work); -- cgit 1.3-korg
f27eb76def5cpower: supply: act8945a: Fix use-after-free in power_supply_changed()
1 file changed · +8 −9
drivers/power/supply/act8945a_charger.c+8 −9 modifieddiff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c index 3901a02f326a55..9dec4486b1439a 100644 --- a/drivers/power/supply/act8945a_charger.c +++ b/drivers/power/supply/act8945a_charger.c @@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev) return irq ?: -ENXIO; } - ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, - IRQF_TRIGGER_FALLING, "act8945a_interrupt", - charger); - if (ret) { - dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); - return ret; - } - charger->desc.name = "act8945a-charger"; charger->desc.get_property = act8945a_charger_get_property; charger->desc.properties = act8945a_charger_props; @@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev) return PTR_ERR(charger->psy); } + ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, + IRQF_TRIGGER_FALLING, "act8945a_interrupt", + charger); + if (ret) { + dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); + return ret; + } + platform_set_drvdata(pdev, charger); INIT_WORK(&charger->work, act8945a_work); -- cgit 1.3-korg
3291c51d4684power: supply: act8945a: Fix use-after-free in power_supply_changed()
1 file changed · +8 −9
drivers/power/supply/act8945a_charger.c+8 −9 modifieddiff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c index 3901a02f326a55..9dec4486b1439a 100644 --- a/drivers/power/supply/act8945a_charger.c +++ b/drivers/power/supply/act8945a_charger.c @@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev) return irq ?: -ENXIO; } - ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, - IRQF_TRIGGER_FALLING, "act8945a_interrupt", - charger); - if (ret) { - dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); - return ret; - } - charger->desc.name = "act8945a-charger"; charger->desc.get_property = act8945a_charger_get_property; charger->desc.properties = act8945a_charger_props; @@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev) return PTR_ERR(charger->psy); } + ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, + IRQF_TRIGGER_FALLING, "act8945a_interrupt", + charger); + if (ret) { + dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); + return ret; + } + platform_set_drvdata(pdev, charger); INIT_WORK(&charger->work, act8945a_work); -- cgit 1.3-korg
697bb5dc0cb4power: supply: act8945a: Fix use-after-free in power_supply_changed()
1 file changed · +8 −9
drivers/power/supply/act8945a_charger.c+8 −9 modifieddiff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c index e9b5f42837729f..e9cb06daecea90 100644 --- a/drivers/power/supply/act8945a_charger.c +++ b/drivers/power/supply/act8945a_charger.c @@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev) return irq ?: -ENXIO; } - ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, - IRQF_TRIGGER_FALLING, "act8945a_interrupt", - charger); - if (ret) { - dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); - return ret; - } - charger->desc.name = "act8945a-charger"; charger->desc.get_property = act8945a_charger_get_property; charger->desc.properties = act8945a_charger_props; @@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev) return PTR_ERR(charger->psy); } + ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, + IRQF_TRIGGER_FALLING, "act8945a_interrupt", + charger); + if (ret) { + dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); + return ret; + } + platform_set_drvdata(pdev, charger); INIT_WORK(&charger->work, act8945a_work); -- cgit 1.3-korg
Vulnerability mechanics
Root cause
"Incorrect ordering of devm-managed resource allocation: IRQ requested before power_supply registration, causing use-after-free during teardown due to reverse deallocation order."
Attack vector
An attacker who can trigger a hardware interrupt on the ACT8945A charger's nIRQ pin during driver removal can cause a use-after-free. Because `devm_request_irq()` was called before `devm_power_supply_register()`, the `power_supply` handle is freed first during teardown (reverse allocation order), but the IRQ handler is unregistered afterward. A race window exists where an interrupt fires after the `power_supply` handle is freed but before the IRQ is unregistered, causing `act8945a_status_changed` to call `power_supply_changed()` on freed memory [patch_id=2661917]. A similar race exists during probe: an interrupt arriving before `power_supply_register()` would cause `power_supply_changed()` to use an uninitialized handle [patch_id=2661917].
Affected code
The bug is in `drivers/power/supply/act8945a_charger.c` in the `act8945a_charger_probe()` function [patch_id=2661917]. The original code called `devm_request_irq()` (lines ~597-603) before `devm_power_supply_register()` (line ~625), creating a reverse-teardown ordering problem.
What the fix does
The patch moves the `devm_request_irq()` call to after `devm_power_supply_register()` in `act8945a_charger_probe()` [patch_id=2661917]. This ensures the IRQ is registered last, so during teardown the IRQ handler is unregistered first (reverse order), preventing any interrupt from firing after the `power_supply` handle is freed. It also prevents interrupts during probe from reaching an unregistered `power_supply` handle.
Preconditions
- configThe ACT8945A charger driver must be loaded and the hardware must be capable of generating interrupts on the nIRQ pin.
- inputThe attacker must be able to trigger a hardware interrupt (e.g., by manipulating charger state) during the driver removal race window.
Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
8- git.kernel.org/stable/c/0768e8525a46df103647ca5059b32320d7fd17e4nvd
- git.kernel.org/stable/c/3291c51d4684d048dd2eb91b5b65fcfdaf72141fnvd
- git.kernel.org/stable/c/697bb5dc0cb4791e244f3970b067bc1ef33be9d9nvd
- git.kernel.org/stable/c/76a42ba547a9b2e2337894f67a4d9247445007d5nvd
- git.kernel.org/stable/c/83c1bd466c514cb24ca6ef347c5aac76a13c4e1envd
- git.kernel.org/stable/c/d023ef9f748b2090f7a9dbdd5c622b6ad99088eanvd
- git.kernel.org/stable/c/f27eb76def5c07e4d7cc468b40741f19dafc83cenvd
- git.kernel.org/stable/c/f2a0777b1e5a3cee1712c4d3e9095c0df8fc8cb3nvd
News mentions
0No linked articles in our index yet.