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);
}
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 */