]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
power: supply: rt9455: Fix use-after-free in power_supply_changed()
authorWaqar Hameed <waqar.hameed@axis.com>
Sat, 20 Dec 2025 22:36:02 +0000 (23:36 +0100)
committerSebastian Reichel <sebastian.reichel@collabora.com>
Mon, 12 Jan 2026 01:52:31 +0000 (02:52 +0100)
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.

Fixes: e86d69dd786e ("power_supply: Add support for Richtek RT9455 battery charger")
Signed-off-by: Waqar Hameed <waqar.hameed@axis.com>
Link: https://patch.msgid.link/1567d831e04c3e2fcb9e18dd36b7bcba4634581a.1766268280.git.waqar.hameed@axis.com
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
drivers/power/supply/rt9455_charger.c

index 1ffe7f02932f6dbbf10944ba32e6eef0077329b1..5130d2395e88fa2a6bb271349c319d437a21a60e 100644 (file)
@@ -1663,6 +1663,15 @@ static int rt9455_probe(struct i2c_client *client)
        rt9455_charger_config.supplied_to       = rt9455_charger_supplied_to;
        rt9455_charger_config.num_supplicants   =
                                        ARRAY_SIZE(rt9455_charger_supplied_to);
+
+       info->charger = devm_power_supply_register(dev, &rt9455_charger_desc,
+                                                  &rt9455_charger_config);
+       if (IS_ERR(info->charger)) {
+               dev_err(dev, "Failed to register charger\n");
+               ret = PTR_ERR(info->charger);
+               goto put_usb_notifier;
+       }
+
        ret = devm_request_threaded_irq(dev, client->irq, NULL,
                                        rt9455_irq_handler_thread,
                                        IRQF_TRIGGER_LOW | IRQF_ONESHOT,
@@ -1678,14 +1687,6 @@ static int rt9455_probe(struct i2c_client *client)
                goto put_usb_notifier;
        }
 
-       info->charger = devm_power_supply_register(dev, &rt9455_charger_desc,
-                                                  &rt9455_charger_config);
-       if (IS_ERR(info->charger)) {
-               dev_err(dev, "Failed to register charger\n");
-               ret = PTR_ERR(info->charger);
-               goto put_usb_notifier;
-       }
-
        return 0;
 
 put_usb_notifier: