From: ikaros Date: Wed, 27 May 2026 17:59:12 +0000 (+0200) Subject: ACPICA: Fix use-after-free in acpi_ds_terminate_control_method() X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=945e87267cfd90937b3c637f87324cbb56998b72;p=thirdparty%2Fkernel%2Flinux.git ACPICA: Fix use-after-free in acpi_ds_terminate_control_method() Fix use-after-free issue in acpi_ds_terminate_control_method() by clearing references to method locals and arguments. Link: https://github.com/acpica/acpica/commit/36f22a94cb1b Signed-off-by: ikaros Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/8730924.NyiUUSuA9g@rafael.j.wysocki --- diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 45ec32e81903a..08bfe83030838 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -705,6 +705,8 @@ void acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, struct acpi_walk_state *walk_state) { + u32 i; + struct acpi_namespace_node *ref_node; ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state); @@ -715,6 +717,47 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, } if (walk_state) { + /* + * Check if the return value is a ref_of reference to a method local + * or argument. If so, clear the reference to avoid use-after-free + * when the walk state is deleted. + */ + if (walk_state->return_desc && + (walk_state->return_desc->common.type == + ACPI_TYPE_LOCAL_REFERENCE) + && (walk_state->return_desc->reference.class == + ACPI_REFCLASS_REFOF)) { + ref_node = walk_state->return_desc->reference.object; + if (ref_node) { + + /* Check against method locals */ + for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) { + if (ref_node == + &walk_state->local_variables[i]) { + acpi_ut_remove_reference + (walk_state->return_desc); + walk_state->return_desc = NULL; + break; + } + } + + /* Check against method arguments if not already cleared */ + if (walk_state->return_desc) { + for (i = 0; i < ACPI_METHOD_NUM_ARGS; + i++) { + if (ref_node == + &walk_state->arguments[i]) { + acpi_ut_remove_reference + (walk_state-> + return_desc); + walk_state-> + return_desc = NULL; + break; + } + } + } + } + } /* Delete all arguments and locals */