diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2011-02-12 03:39:15 +0300 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2011-02-12 03:39:15 +0300 |
commit | 2d55951368faa32ff098398c56780ebb6405a3d9 (patch) | |
tree | 0e6290e8fa625c8c028ca06edb629549e6379240 /drivers/acpi | |
parent | 100b33c8bd8a3235fd0b7948338d6cbb3db3c63d (diff) | |
download | linux-2d55951368faa32ff098398c56780ebb6405a3d9.tar.xz |
ACPI / ACPICA: Avoid crashing if _PRW is defined for the root object
Some ACPI BIOSes define _PRW for the root object which causes
acpi_setup_gpe_for_wake() to crash when trying to dereference the
bogus device_node pointer. Avoid the crash by checking if
wake_device is not the root object before attempting to set up the
"implicit notify" mechanism for it.
The problem was introduced by commit bba63a296ffab20e08d9e8252d2f0d99
(ACPICA: Implicit notify support) that added the wake_device argument
to acpi_setup_gpe_for_wake().
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/acpica/evxfgpe.c | 49 |
1 files changed, 26 insertions, 23 deletions
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index e9562a7cb2f9..3b20a3401b64 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -212,37 +212,40 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device, return_ACPI_STATUS(AE_BAD_PARAMETER); } - /* Validate wake_device is of type Device */ - - device_node = ACPI_CAST_PTR(struct acpi_namespace_node, wake_device); - if (device_node->type != ACPI_TYPE_DEVICE) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); /* Ensure that we have a valid GPE number */ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); - if (gpe_event_info) { - /* - * If there is no method or handler for this GPE, then the - * wake_device will be notified whenever this GPE fires (aka - * "implicit notify") Note: The GPE is assumed to be - * level-triggered (for windows compatibility). - */ - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == - ACPI_GPE_DISPATCH_NONE) { - gpe_event_info->flags = - (ACPI_GPE_DISPATCH_NOTIFY | - ACPI_GPE_LEVEL_TRIGGERED); - gpe_event_info->dispatch.device_node = device_node; - } + if (!gpe_event_info) { + goto unlock_and_exit; + } + + /* + * If there is no method or handler for this GPE, then the + * wake_device will be notified whenever this GPE fires (aka + * "implicit notify") Note: The GPE is assumed to be + * level-triggered (for windows compatibility). + */ + if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == + ACPI_GPE_DISPATCH_NONE) && (wake_device != ACPI_ROOT_OBJECT)) { - gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; - status = AE_OK; + /* Validate wake_device is of type Device */ + + device_node = ACPI_CAST_PTR(struct acpi_namespace_node, + wake_device); + if (device_node->type != ACPI_TYPE_DEVICE) { + goto unlock_and_exit; + } + gpe_event_info->flags = (ACPI_GPE_DISPATCH_NOTIFY | + ACPI_GPE_LEVEL_TRIGGERED); + gpe_event_info->dispatch.device_node = device_node; } + gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; + status = AE_OK; + + unlock_and_exit: acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return_ACPI_STATUS(status); } |