Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 252fbeb8 authored by Sven Van Asbroeck's avatar Sven Van Asbroeck Committed by Sebastian Reichel
Browse files

power: supply: max14656: fix potential use-after-free



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: default avatarSven Van Asbroeck <TheSven73@gmail.com>
Signed-off-by: default avatarSebastian Reichel <sebastian.reichel@collabora.com>
parent 0cd0e497
Loading
Loading
Loading
Loading
+15 −2
Original line number Original line Diff line number Diff line
@@ -240,6 +240,14 @@ static enum power_supply_property max14656_battery_props[] = {
	POWER_SUPPLY_PROP_MANUFACTURER,
	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,
static int max14656_probe(struct i2c_client *client,
			  const struct i2c_device_id *id)
			  const struct i2c_device_id *id)
{
{
@@ -278,8 +286,6 @@ static int max14656_probe(struct i2c_client *client,
	if (ret)
	if (ret)
		return -ENODEV;
		return -ENODEV;


	INIT_DELAYED_WORK(&chip->irq_work, max14656_irq_worker);

	chip->detect_psy = devm_power_supply_register(dev,
	chip->detect_psy = devm_power_supply_register(dev,
		       &chip->psy_desc, &psy_cfg);
		       &chip->psy_desc, &psy_cfg);
	if (IS_ERR(chip->detect_psy)) {
	if (IS_ERR(chip->detect_psy)) {
@@ -287,6 +293,13 @@ static int max14656_probe(struct i2c_client *client,
		return -EINVAL;
		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,
	ret = devm_request_irq(dev, chip->irq, max14656_irq,
			       IRQF_TRIGGER_FALLING,
			       IRQF_TRIGGER_FALLING,
			       MAX14656_NAME, chip);
			       MAX14656_NAME, chip);