diff options
| author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-08-05 20:26:22 -0400 |
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-08-05 20:26:22 -0400 |
| commit | 623cf33cb055b1e81fa47e4fc16789b2c129e31e (patch) | |
| tree | 7f0f56d1d21be4ce727b3d2433f9379b6a363dc3 /drivers/acpi/proc.c | |
| parent | b3b301c5fed8a0868e56c98b922cb0c881b3857d (diff) | |
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: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Cc: All <stable@vger.kernel.org>
Diffstat (limited to 'drivers/acpi/proc.c')
| -rw-r--r-- | drivers/acpi/proc.c | 8 |
1 files changed, 8 insertions, 0 deletions
diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c index aa1227a7e3f2..04a13784dd20 100644 --- a/drivers/acpi/proc.c +++ b/drivers/acpi/proc.c | |||
| @@ -311,6 +311,8 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset) | |||
| 311 | dev->pnp.bus_id, | 311 | dev->pnp.bus_id, |
| 312 | (u32) dev->wakeup.sleep_state); | 312 | (u32) dev->wakeup.sleep_state); |
| 313 | 313 | ||
| 314 | mutex_lock(&dev->physical_node_lock); | ||
| 315 | |||
| 314 | if (!dev->physical_node_count) { | 316 | if (!dev->physical_node_count) { |
| 315 | seq_printf(seq, "%c%-8s\n", | 317 | seq_printf(seq, "%c%-8s\n", |
| 316 | dev->wakeup.flags.run_wake ? '*' : ' ', | 318 | dev->wakeup.flags.run_wake ? '*' : ' ', |
| @@ -338,6 +340,8 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset) | |||
| 338 | put_device(ldev); | 340 | put_device(ldev); |
| 339 | } | 341 | } |
| 340 | } | 342 | } |
| 343 | |||
| 344 | mutex_unlock(&dev->physical_node_lock); | ||
| 341 | } | 345 | } |
| 342 | mutex_unlock(&acpi_device_lock); | 346 | mutex_unlock(&acpi_device_lock); |
| 343 | return 0; | 347 | return 0; |
| @@ -347,12 +351,16 @@ static void physical_device_enable_wakeup(struct acpi_device *adev) | |||
| 347 | { | 351 | { |
| 348 | struct acpi_device_physical_node *entry; | 352 | struct acpi_device_physical_node *entry; |
| 349 | 353 | ||
| 354 | mutex_lock(&adev->physical_node_lock); | ||
| 355 | |||
| 350 | list_for_each_entry(entry, | 356 | list_for_each_entry(entry, |
| 351 | &adev->physical_node_list, node) | 357 | &adev->physical_node_list, node) |
| 352 | if (entry->dev && device_can_wakeup(entry->dev)) { | 358 | if (entry->dev && device_can_wakeup(entry->dev)) { |
| 353 | bool enable = !device_may_wakeup(entry->dev); | 359 | bool enable = !device_may_wakeup(entry->dev); |
| 354 | device_set_wakeup_enable(entry->dev, enable); | 360 | device_set_wakeup_enable(entry->dev, enable); |
| 355 | } | 361 | } |
| 362 | |||
| 363 | mutex_unlock(&adev->physical_node_lock); | ||
| 356 | } | 364 | } |
| 357 | 365 | ||
| 358 | static ssize_t | 366 | static ssize_t |
