Commit f953529f authored by Bob Moore's avatar Bob Moore Committed by Rafael J. Wysocki

ACPICA: Prevent infinite loops when traversing corrupted lists.

This change hardens the ACPICA code to detect circular linked object
lists and prevent an infinite loop if such corruption exists.
Signed-off-by: default avatarBob Moore <robert.moore@intel.com>
Signed-off-by: default avatarLv Zheng <lv.zheng@intel.com>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent a487af33
...@@ -314,6 +314,7 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj, ...@@ -314,6 +314,7 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
{ {
union acpi_operand_object *handler_obj; union acpi_operand_object *handler_obj;
union acpi_operand_object *obj_desc; union acpi_operand_object *obj_desc;
union acpi_operand_object *start_desc;
union acpi_operand_object **last_obj_ptr; union acpi_operand_object **last_obj_ptr;
acpi_adr_space_setup region_setup; acpi_adr_space_setup region_setup;
void **region_context; void **region_context;
...@@ -341,6 +342,7 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj, ...@@ -341,6 +342,7 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
/* Find this region in the handler's list */ /* Find this region in the handler's list */
obj_desc = handler_obj->address_space.region_list; obj_desc = handler_obj->address_space.region_list;
start_desc = obj_desc;
last_obj_ptr = &handler_obj->address_space.region_list; last_obj_ptr = &handler_obj->address_space.region_list;
while (obj_desc) { while (obj_desc) {
...@@ -438,6 +440,15 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj, ...@@ -438,6 +440,15 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
last_obj_ptr = &obj_desc->region.next; last_obj_ptr = &obj_desc->region.next;
obj_desc = obj_desc->region.next; obj_desc = obj_desc->region.next;
/* Prevent infinite loop if list is corrupted */
if (obj_desc == start_desc) {
ACPI_ERROR((AE_INFO,
"Circular handler list in region object %p",
region_obj));
return_VOID;
}
} }
/* If we get here, the region was not in the handler's region list */ /* If we get here, the region was not in the handler's region list */
......
...@@ -222,13 +222,19 @@ void acpi_ns_detach_object(struct acpi_namespace_node *node) ...@@ -222,13 +222,19 @@ void acpi_ns_detach_object(struct acpi_namespace_node *node)
} }
} }
/* Clear the entry in all cases */ /* Clear the Node entry in all cases */
node->object = NULL; node->object = NULL;
if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) == ACPI_DESC_TYPE_OPERAND) { if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) == ACPI_DESC_TYPE_OPERAND) {
/* Unlink object from front of possible object list */
node->object = obj_desc->common.next_object; node->object = obj_desc->common.next_object;
/* Handle possible 2-descriptor object */
if (node->object && if (node->object &&
((node->object)->common.type != ACPI_TYPE_LOCAL_DATA)) { (node->object->common.type != ACPI_TYPE_LOCAL_DATA)) {
node->object = node->object->common.next_object; node->object = node->object->common.next_object;
} }
} }
......
...@@ -75,6 +75,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) ...@@ -75,6 +75,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
union acpi_operand_object *handler_desc; union acpi_operand_object *handler_desc;
union acpi_operand_object *second_desc; union acpi_operand_object *second_desc;
union acpi_operand_object *next_desc; union acpi_operand_object *next_desc;
union acpi_operand_object *start_desc;
union acpi_operand_object **last_obj_ptr; union acpi_operand_object **last_obj_ptr;
ACPI_FUNCTION_TRACE_PTR(ut_delete_internal_obj, object); ACPI_FUNCTION_TRACE_PTR(ut_delete_internal_obj, object);
...@@ -235,10 +236,11 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) ...@@ -235,10 +236,11 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
if (handler_desc) { if (handler_desc) {
next_desc = next_desc =
handler_desc->address_space.region_list; handler_desc->address_space.region_list;
start_desc = next_desc;
last_obj_ptr = last_obj_ptr =
&handler_desc->address_space.region_list; &handler_desc->address_space.region_list;
/* Remove the region object from the handler's list */ /* Remove the region object from the handler list */
while (next_desc) { while (next_desc) {
if (next_desc == object) { if (next_desc == object) {
...@@ -247,10 +249,19 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) ...@@ -247,10 +249,19 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
break; break;
} }
/* Walk the linked list of handler */ /* Walk the linked list of handlers */
last_obj_ptr = &next_desc->region.next; last_obj_ptr = &next_desc->region.next;
next_desc = next_desc->region.next; next_desc = next_desc->region.next;
/* Prevent infinite loop if list is corrupted */
if (next_desc == start_desc) {
ACPI_ERROR((AE_INFO,
"Circular region list in address handler object %p",
handler_desc));
return_VOID;
}
} }
if (handler_desc->address_space.handler_flags & if (handler_desc->address_space.handler_flags &
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment