[PATCH 4.17 06/56] ACPI / battery: Safe unregistering of hooks

From: Greg Kroah-Hartman
Date: Tue Jul 10 2018 - 14:36:01 EST


4.17-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jouke Witteveen <j.witteveen@xxxxxxxxx>

commit 673b4271665a12fa839a12abb50e6f6e9953c081 upstream.

A hooking API was implemented for 4.17 in fa93854f7a7ed63d followed
by hooks for Thinkpad laptops in 2801b9683f740012. The Thinkpad
drivers did not support the Thinkpad 13 and the hooking API crashes
on unsupported batteries by altering a list of hooks during unsafe
iteration. Thus, Thinkpad 13 laptops could no longer boot.

Additionally, a lock was kept in place and debugging information was
printed out of order.

Fixes: fa93854f7a7e (battery: Add the battery hooking API)
Cc: 4.17+ <stable@xxxxxxxxxxxxxxx> # 4.17+
Signed-off-by: Jouke Witteveen <j.witteveen@xxxxxxxxx>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>

---
drivers/acpi/battery.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)

--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -709,10 +709,11 @@ void battery_hook_register(struct acpi_b
*/
pr_err("extension failed to load: %s", hook->name);
__battery_hook_unregister(hook, 0);
- return;
+ goto end;
}
}
pr_info("new extension: %s\n", hook->name);
+end:
mutex_unlock(&hook_mutex);
}
EXPORT_SYMBOL_GPL(battery_hook_register);
@@ -724,7 +725,7 @@ EXPORT_SYMBOL_GPL(battery_hook_register)
*/
static void battery_hook_add_battery(struct acpi_battery *battery)
{
- struct acpi_battery_hook *hook_node;
+ struct acpi_battery_hook *hook_node, *tmp;

mutex_lock(&hook_mutex);
INIT_LIST_HEAD(&battery->list);
@@ -736,15 +737,15 @@ static void battery_hook_add_battery(str
* when a battery gets hotplugged or initialized
* during the battery module initialization.
*/
- list_for_each_entry(hook_node, &battery_hook_list, list) {
+ list_for_each_entry_safe(hook_node, tmp, &battery_hook_list, list) {
if (hook_node->add_battery(battery->bat)) {
/*
* The notification of the extensions has failed, to
* prevent further errors we will unload the extension.
*/
- __battery_hook_unregister(hook_node, 0);
pr_err("error in extension, unloading: %s",
hook_node->name);
+ __battery_hook_unregister(hook_node, 0);
}
}
mutex_unlock(&hook_mutex);