power: supply: max14656: fix potential use-before-alloc
PATCH 1/2 power: supply: max14656: fix potential use-before-alloc
Call order on probe():
- max14656_hw_init() enables interrupts on the chip
- devm_request_irq() starts processing interrupts, isr could be called immediately
- isr: schedules delayed work (irq_work)
- irq_work: calls power_supply_changed()
- devm_power_supply_register() registers the power supply
Depending on timing, it's possible that power_supply_changed() is called on an unregistered power supply structure.
Fix by registering the power supply before requesting the irq.
--- drivers/power/supply/max14656_charger_detector.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
drivers/power/supply/max14656_charger_detector.c +7 -7
@@ -280,6 +280,13 @@ static int max14656_probe(struct i2c_client *client,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)) { +dev_err (dev,"power_supply_register failed\n" ); +return -EINVAL ; + } + ret =devm_request_irq (dev, chip->irq, max14656_irq,IRQF_TRIGGER_FALLING ,MAX14656_NAME , chip);
@@ -289,13 +296,6 @@ static int max14656_probe(struct i2c_client *client, }enable_irq_wake (chip->irq); - chip->detect_psy =devm_power_supply_register (dev, - &chip->psy_desc, &psy_cfg); -if (IS_ERR (chip->detect_psy)) { -dev_err (dev,"power_supply_register failed\n" ); -return -EINVAL ; - } -schedule_delayed_work (&chip->irq_work,msecs_to_jiffies (2000 ));return 0 ;
Signature · 1 line
2.17.1
PATCH 2/2 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.
--- .../power/supply/max14656_charger_detector.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
drivers/power/supply/max14656_charger_detector.c +15 -2
@@ -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);
Signature · 1 line
2.17.1