power: supply: core: fix use after free in uevent
authorSebastian Reichel <sebastian.reichel@collabora.com>
Tue, 19 Sep 2023 12:08:29 +0000 (14:08 +0200)
committerSebastian Reichel <sebastian.reichel@collabora.com>
Tue, 19 Sep 2023 12:08:34 +0000 (14:08 +0200)
power_supply_uevent() which is called to emit a udev event on device
deletion attempts to use the power_supply_battery_info structure,
which is device-managed and has been freed before this point.

Fix this by not generating all battery/charger properties when the
device is about to be removed. This also avoids generating errors
when trying to access the hardware in hot-unplug scenarios.

==================================================================
 BUG: KASAN: slab-use-after-free in power_supply_battery_info_has_prop (power_supply_core.c:872)
 Read of size 4 at addr 0000000062e59028 by task python3/27

 Call Trace:
  power_supply_battery_info_has_prop (power_supply_core.c:872)
  power_supply_uevent (power_supply_sysfs.c:504)
  dev_uevent (drivers/base/core.c:2590)
  kobject_uevent_env (lib/kobject_uevent.c:558)
  kobject_uevent (lib/kobject_uevent.c:643)
  device_del (drivers/base/core.c:3266 drivers/base/core.c:3831)
  device_unregister (drivers/base/core.c:3730 drivers/base/core.c:3854)
  power_supply_unregister (power_supply_core.c:1608)
  devm_power_supply_release (power_supply_core.c:1515)
  release_nodes (drivers/base/devres.c:506)
  devres_release_group (drivers/base/devres.c:669)
  i2c_device_remove (drivers/i2c/i2c-core-base.c:629)
  device_remove (drivers/base/dd.c:570)
  device_release_driver_internal (drivers/base/dd.c:1274 drivers/base/dd.c:1295)
  device_driver_detach (drivers/base/dd.c:1332)
  unbind_store (drivers/base/bus.c:247)
  ...

 Allocated by task 27:
  devm_kmalloc (drivers/base/devres.c:119 drivers/base/devres.c:829)
  power_supply_get_battery_info (include/linux/device.h:316 power_supply_core.c:626)
  __power_supply_register (power_supply_core.c:1408)
  devm_power_supply_register (power_supply_core.c:1544)
  bq256xx_probe (bq256xx_charger.c:1539 bq256xx_charger.c:1727) bq256xx_charger
  i2c_device_probe (drivers/i2c/i2c-core-base.c:584)
  really_probe (drivers/base/dd.c:579 drivers/base/dd.c:658)
  __driver_probe_device (drivers/base/dd.c:800)
  device_driver_attach (drivers/base/dd.c:1128)
  bind_store (drivers/base/bus.c:273)
  ...

 Freed by task 27:
  kfree (mm/slab_common.c:1073)
  release_nodes (drivers/base/devres.c:503)
  devres_release_all (drivers/base/devres.c:536)
  device_del (drivers/base/core.c:3829)
  device_unregister (drivers/base/core.c:3730 drivers/base/core.c:3854)
  power_supply_unregister (power_supply_core.c:1608)
  devm_power_supply_release (power_supply_core.c:1515)
  release_nodes (drivers/base/devres.c:506)
  devres_release_group (drivers/base/devres.c:669)
  i2c_device_remove (drivers/i2c/i2c-core-base.c:629)
  device_remove (drivers/base/dd.c:570)
  device_release_driver_internal (drivers/base/dd.c:1274 drivers/base/dd.c:1295)
  device_driver_detach (drivers/base/dd.c:1332)
  unbind_store (drivers/base/bus.c:247)
  ...
 ==================================================================

Reported-by: Vincent Whitchurch <vincent.whitchurch@axis.com>
Fixes: 27a2195efa8d ("power: supply: core: auto-exposure of simple-battery data")
Tested-by: Vincent Whitchurch <vincent.whitchurch@axis.com>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
drivers/power/supply/power_supply_sysfs.c

index 06e5b6b..d483a81 100644 (file)
@@ -482,6 +482,13 @@ int power_supply_uevent(const struct device *dev, struct kobj_uevent_env *env)
        if (ret)
                return ret;
 
+       /*
+        * Kernel generates KOBJ_REMOVE uevent in device removal path, after
+        * resources have been freed. Exit early to avoid use-after-free.
+        */
+       if (psy->removing)
+               return 0;
+
        prop_buf = (char *)get_zeroed_page(GFP_KERNEL);
        if (!prop_buf)
                return -ENOMEM;