Commit 2d559513 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

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 bba63a29
(ACPICA: Implicit notify support) that added the wake_device argument
to acpi_setup_gpe_for_wake().

Signed-off-by: default avatarRafael J. Wysocki <rjw@sisk.pl>
parent 100b33c8
Loading
Loading
Loading
Loading
+26 −23
Original line number Original line Diff line number Diff line
@@ -212,37 +212,40 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device,
		return_ACPI_STATUS(AE_BAD_PARAMETER);
		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);
	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);


	/* Ensure that we have a valid GPE number */
	/* Ensure that we have a valid GPE number */


	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
	if (gpe_event_info) {
	if (!gpe_event_info) {
		goto unlock_and_exit;
	}

	/*
	/*
	 * If there is no method or handler for this GPE, then the
	 * If there is no method or handler for this GPE, then the
	 * wake_device will be notified whenever this GPE fires (aka
	 * wake_device will be notified whenever this GPE fires (aka
	 * "implicit notify") Note: The GPE is assumed to be
	 * "implicit notify") Note: The GPE is assumed to be
	 * level-triggered (for windows compatibility).
	 * level-triggered (for windows compatibility).
	 */
	 */
		if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
	if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
		    ACPI_GPE_DISPATCH_NONE) {
	      ACPI_GPE_DISPATCH_NONE) && (wake_device != ACPI_ROOT_OBJECT)) {
			gpe_event_info->flags =

			    (ACPI_GPE_DISPATCH_NOTIFY |
		/* 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);
					 ACPI_GPE_LEVEL_TRIGGERED);
		gpe_event_info->dispatch.device_node = device_node;
		gpe_event_info->dispatch.device_node = device_node;
	}
	}


	gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
	gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
	status = AE_OK;
	status = AE_OK;
	}


 unlock_and_exit:
	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
	return_ACPI_STATUS(status);
	return_ACPI_STATUS(status);
}
}