]> git.ipfire.org Git - people/arne_f/kernel.git/commitdiff
power: supply: max14656: fix potential use-after-free
authorSven Van Asbroeck <thesven73@gmail.com>
Fri, 15 Feb 2019 21:43:03 +0000 (16:43 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 6 Nov 2019 11:43:00 +0000 (12:43 +0100)
[ Upstream commit 252fbeb86ceffa549af9842cefca2412d53a7653 ]

Explicitly cancel/sync the irq_work delayed work, otherwise
there's a chance that it will run after the device is removed,
which would result in a use-after-free.

Note that cancel/sync should happen:
- after irq's have been disabled, as the isr re-schedules the work
- before the power supply is unregistered, because the work func
    uses the power supply handle.

Cc: Alexander Kurz <akurz@blala.de>
Signed-off-by: Sven Van Asbroeck <TheSven73@gmail.com>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/power/supply/max14656_charger_detector.c

index d19307f791c68957c4f2851462e00ad4017c138d..9e6472834e373010f34b3489895bfb88353b3885 100644 (file)
@@ -240,6 +240,14 @@ static enum power_supply_property max14656_battery_props[] = {
        POWER_SUPPLY_PROP_MANUFACTURER,
 };
 
+static void stop_irq_work(void *data)
+{
+       struct max14656_chip *chip = data;
+
+       cancel_delayed_work_sync(&chip->irq_work);
+}
+
+
 static int max14656_probe(struct i2c_client *client,
                          const struct i2c_device_id *id)
 {
@@ -278,8 +286,6 @@ static int max14656_probe(struct i2c_client *client,
        if (ret)
                return -ENODEV;
 
-       INIT_DELAYED_WORK(&chip->irq_work, max14656_irq_worker);
-
        chip->detect_psy = devm_power_supply_register(dev,
                       &chip->psy_desc, &psy_cfg);
        if (IS_ERR(chip->detect_psy)) {
@@ -287,6 +293,13 @@ static int max14656_probe(struct i2c_client *client,
                return -EINVAL;
        }
 
+       INIT_DELAYED_WORK(&chip->irq_work, max14656_irq_worker);
+       ret = devm_add_action(dev, stop_irq_work, chip);
+       if (ret) {
+               dev_err(dev, "devm_add_action %d failed\n", ret);
+               return ret;
+       }
+
        ret = devm_request_irq(dev, chip->irq, max14656_irq,
                               IRQF_TRIGGER_FALLING,
                               MAX14656_NAME, chip);