Commit 623cf33c authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

ACPI / PM: Walk physical_node_list under physical_node_lock

The list of physical devices corresponding to an ACPI device
object is walked by acpi_system_wakeup_device_seq_show() and
physical_device_enable_wakeup() without taking that object's
physical_node_lock mutex.  Since each of those functions may be
run at any time as a result of a user space action, the lack of
appropriate locking in them may lead to a kernel crash if that
happens during device hot-add or hot-remove involving the device
object in question.

Fix the issue by modifying acpi_system_wakeup_device_seq_show() and
physical_device_enable_wakeup() to use physical_node_lock as
appropriate.
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
Cc: All <stable@vger.kernel.org>
parent b3b301c5
...@@ -311,6 +311,8 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset) ...@@ -311,6 +311,8 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
dev->pnp.bus_id, dev->pnp.bus_id,
(u32) dev->wakeup.sleep_state); (u32) dev->wakeup.sleep_state);
mutex_lock(&dev->physical_node_lock);
if (!dev->physical_node_count) { if (!dev->physical_node_count) {
seq_printf(seq, "%c%-8s\n", seq_printf(seq, "%c%-8s\n",
dev->wakeup.flags.run_wake ? '*' : ' ', dev->wakeup.flags.run_wake ? '*' : ' ',
...@@ -338,6 +340,8 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset) ...@@ -338,6 +340,8 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
put_device(ldev); put_device(ldev);
} }
} }
mutex_unlock(&dev->physical_node_lock);
} }
mutex_unlock(&acpi_device_lock); mutex_unlock(&acpi_device_lock);
return 0; return 0;
...@@ -347,12 +351,16 @@ static void physical_device_enable_wakeup(struct acpi_device *adev) ...@@ -347,12 +351,16 @@ static void physical_device_enable_wakeup(struct acpi_device *adev)
{ {
struct acpi_device_physical_node *entry; struct acpi_device_physical_node *entry;
mutex_lock(&adev->physical_node_lock);
list_for_each_entry(entry, list_for_each_entry(entry,
&adev->physical_node_list, node) &adev->physical_node_list, node)
if (entry->dev && device_can_wakeup(entry->dev)) { if (entry->dev && device_can_wakeup(entry->dev)) {
bool enable = !device_may_wakeup(entry->dev); bool enable = !device_may_wakeup(entry->dev);
device_set_wakeup_enable(entry->dev, enable); device_set_wakeup_enable(entry->dev, enable);
} }
mutex_unlock(&adev->physical_node_lock);
} }
static ssize_t static ssize_t
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment