aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorBob Moore <robert.moore@intel.com>2014-02-25 21:33:47 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-03-17 20:52:18 -0400
commitf953529f3b659a72c0982c2cf195158db96361f1 (patch)
tree48eeb4fe487c2c0c82add70e8b71edea9a14f37d /drivers/acpi
parenta487af33a4f0f5ced860ab18c4a740b97b435a3e (diff)
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>
Diffstat (limited to 'drivers/acpi')
-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,
314{ 314{
315 union acpi_operand_object *handler_obj; 315 union acpi_operand_object *handler_obj;
316 union acpi_operand_object *obj_desc; 316 union acpi_operand_object *obj_desc;
317 union acpi_operand_object *start_desc;
317 union acpi_operand_object **last_obj_ptr; 318 union acpi_operand_object **last_obj_ptr;
318 acpi_adr_space_setup region_setup; 319 acpi_adr_space_setup region_setup;
319 void **region_context; 320 void **region_context;
@@ -341,6 +342,7 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
341 /* Find this region in the handler's list */ 342 /* Find this region in the handler's list */
342 343
343 obj_desc = handler_obj->address_space.region_list; 344 obj_desc = handler_obj->address_space.region_list;
345 start_desc = obj_desc;
344 last_obj_ptr = &handler_obj->address_space.region_list; 346 last_obj_ptr = &handler_obj->address_space.region_list;
345 347
346 while (obj_desc) { 348 while (obj_desc) {
@@ -438,6 +440,15 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
438 440
439 last_obj_ptr = &obj_desc->region.next; 441 last_obj_ptr = &obj_desc->region.next;
440 obj_desc = obj_desc->region.next; 442 obj_desc = obj_desc->region.next;
443
444 /* Prevent infinite loop if list is corrupted */
445
446 if (obj_desc == start_desc) {
447 ACPI_ERROR((AE_INFO,
448 "Circular handler list in region object %p",
449 region_obj));
450 return_VOID;
451 }
441 } 452 }
442 453
443 /* If we get here, the region was not in the handler's region list */ 454 /* 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)
222 } 222 }
223 } 223 }
224 224
225 /* Clear the entry in all cases */ 225 /* Clear the Node entry in all cases */
226 226
227 node->object = NULL; 227 node->object = NULL;
228 if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) == ACPI_DESC_TYPE_OPERAND) { 228 if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) == ACPI_DESC_TYPE_OPERAND) {
229
230 /* Unlink object from front of possible object list */
231
229 node->object = obj_desc->common.next_object; 232 node->object = obj_desc->common.next_object;
233
234 /* Handle possible 2-descriptor object */
235
230 if (node->object && 236 if (node->object &&
231 ((node->object)->common.type != ACPI_TYPE_LOCAL_DATA)) { 237 (node->object->common.type != ACPI_TYPE_LOCAL_DATA)) {
232 node->object = node->object->common.next_object; 238 node->object = node->object->common.next_object;
233 } 239 }
234 } 240 }
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)
75 union acpi_operand_object *handler_desc; 75 union acpi_operand_object *handler_desc;
76 union acpi_operand_object *second_desc; 76 union acpi_operand_object *second_desc;
77 union acpi_operand_object *next_desc; 77 union acpi_operand_object *next_desc;
78 union acpi_operand_object *start_desc;
78 union acpi_operand_object **last_obj_ptr; 79 union acpi_operand_object **last_obj_ptr;
79 80
80 ACPI_FUNCTION_TRACE_PTR(ut_delete_internal_obj, object); 81 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 if (handler_desc) { 236 if (handler_desc) {
236 next_desc = 237 next_desc =
237 handler_desc->address_space.region_list; 238 handler_desc->address_space.region_list;
239 start_desc = next_desc;
238 last_obj_ptr = 240 last_obj_ptr =
239 &handler_desc->address_space.region_list; 241 &handler_desc->address_space.region_list;
240 242
241 /* Remove the region object from the handler's list */ 243 /* Remove the region object from the handler list */
242 244
243 while (next_desc) { 245 while (next_desc) {
244 if (next_desc == object) { 246 if (next_desc == object) {
@@ -247,10 +249,19 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
247 break; 249 break;
248 } 250 }
249 251
250 /* Walk the linked list of handler */ 252 /* Walk the linked list of handlers */
251 253
252 last_obj_ptr = &next_desc->region.next; 254 last_obj_ptr = &next_desc->region.next;
253 next_desc = next_desc->region.next; 255 next_desc = next_desc->region.next;
256
257 /* Prevent infinite loop if list is corrupted */
258
259 if (next_desc == start_desc) {
260 ACPI_ERROR((AE_INFO,
261 "Circular region list in address handler object %p",
262 handler_desc));
263 return_VOID;
264 }
254 } 265 }
255 266
256 if (handler_desc->address_space.handler_flags & 267 if (handler_desc->address_space.handler_flags &