From: Rafael J. Wysocki Date: Mon, 29 Aug 2022 15:21:43 +0000 (+0200) Subject: ACPI: PM: Fix NULL argument handling in acpi_device_get/set_power() X-Git-Tag: v6.6.17~6540^2~8^2~7 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d5008ef5b5a21177d3042816542f1afd5ae36152;p=platform%2Fkernel%2Flinux-rpi.git ACPI: PM: Fix NULL argument handling in acpi_device_get/set_power() In principle, it should be valid to pass NULL as the ACPI device pointer to acpi_device_get_power() and acpi_device_set_power() and they both are expected to return -EINVAL in that case, but that has been broken recently by commit 62fcb99bdf10 ("ACPI: Drop parent field from struct acpi_device") which has caused the ACPI device pointer to be dereferenced in these functions before the NULL check. Fix that and while at it make acpi_device_set_power() only use the parent field if the target ACPI device object's ignore_parent flag in not set. Fixes: 62fcb99bdf10 ("ACPI: Drop parent field from struct acpi_device") Reported-by: Dan Carpenter Signed-off-by: Rafael J. Wysocki --- diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 028d8d1..3aca67c 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -74,13 +74,15 @@ static int acpi_dev_pm_explicit_get(struct acpi_device *device, int *state) */ int acpi_device_get_power(struct acpi_device *device, int *state) { - struct acpi_device *parent = acpi_dev_parent(device); int result = ACPI_STATE_UNKNOWN; + struct acpi_device *parent; int error; if (!device || !state) return -EINVAL; + parent = acpi_dev_parent(device); + if (!device->flags.power_manageable) { /* TBD: Non-recursive algorithm for walking up hierarchy. */ *state = parent ? parent->power.state : ACPI_STATE_D0; @@ -159,7 +161,6 @@ static int acpi_dev_pm_explicit_set(struct acpi_device *adev, int state) */ int acpi_device_set_power(struct acpi_device *device, int state) { - struct acpi_device *parent = acpi_dev_parent(device); int target_state = state; int result = 0; @@ -192,13 +193,17 @@ int acpi_device_set_power(struct acpi_device *device, int state) return -ENODEV; } - if (!device->power.flags.ignore_parent && parent && - state < parent->power.state) { - acpi_handle_debug(device->handle, - "Cannot transition to %s for parent in %s\n", - acpi_power_state_string(state), - acpi_power_state_string(parent->power.state)); - return -ENODEV; + if (!device->power.flags.ignore_parent) { + struct acpi_device *parent; + + parent = acpi_dev_parent(device); + if (parent && state < parent->power.state) { + acpi_handle_debug(device->handle, + "Cannot transition to %s for parent in %s\n", + acpi_power_state_string(state), + acpi_power_state_string(parent->power.state)); + return -ENODEV; + } } /*