summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBob Moore <robert.moore@intel.com>2014-02-26 10:33:47 +0800
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-03-18 01:52:18 +0100
commitf953529f3b659a72c0982c2cf195158db96361f1 (patch)
tree48eeb4fe487c2c0c82add70e8b71edea9a14f37d
parenta487af33a4f0f5ced860ab18c4a740b97b435a3e (diff)
downloadlinux-f953529f3b659a72c0982c2cf195158db96361f1.tar.bz2
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: Bob Moore <robert.moore@intel.com> Signed-off-by: Lv Zheng <lv.zheng@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/acpi/acpica/evregion.c11
-rw-r--r--drivers/acpi/acpica/nsobject.c10
-rw-r--r--drivers/acpi/acpica/utdelete.c15
3 files changed, 32 insertions, 4 deletions
diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c
index e31049b3e9d4..9957297d1580 100644
--- a/drivers/acpi/acpica/evregion.c
+++ b/drivers/acpi/acpica/evregion.c
@@ -314,6 +314,7 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
{
union acpi_operand_object *handler_obj;
union acpi_operand_object *obj_desc;
+ union acpi_operand_object *start_desc;
union acpi_operand_object **last_obj_ptr;
acpi_adr_space_setup region_setup;
void **region_context;
@@ -341,6 +342,7 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
/* Find this region in the handler's list */
obj_desc = handler_obj->address_space.region_list;
+ start_desc = obj_desc;
last_obj_ptr = &handler_obj->address_space.region_list;
while (obj_desc) {
@@ -438,6 +440,15 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
last_obj_ptr = &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 */
diff --git a/drivers/acpi/acpica/nsobject.c b/drivers/acpi/acpica/nsobject.c
index 32845b105053..fe54a8c73b8c 100644
--- a/drivers/acpi/acpica/nsobject.c
+++ b/drivers/acpi/acpica/nsobject.c
@@ -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;
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;
+
+ /* Handle possible 2-descriptor 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;
}
}
diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c
index ed4cb8683310..a3516de213fa 100644
--- a/drivers/acpi/acpica/utdelete.c
+++ b/drivers/acpi/acpica/utdelete.c
@@ -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 *second_desc;
union acpi_operand_object *next_desc;
+ union acpi_operand_object *start_desc;
union acpi_operand_object **last_obj_ptr;
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)
if (handler_desc) {
next_desc =
handler_desc->address_space.region_list;
+ start_desc = next_desc;
last_obj_ptr =
&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) {
if (next_desc == object) {
@@ -247,10 +249,19 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
break;
}
- /* Walk the linked list of handler */
+ /* Walk the linked list of handlers */
last_obj_ptr = &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 &