diff options
author | Bob Moore <robert.moore@intel.com> | 2014-02-25 21:33:47 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-03-17 20:52:18 -0400 |
commit | f953529f3b659a72c0982c2cf195158db96361f1 (patch) | |
tree | 48eeb4fe487c2c0c82add70e8b71edea9a14f37d /drivers/acpi | |
parent | a487af33a4f0f5ced860ab18c4a740b97b435a3e (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.c | 11 | ||||
-rw-r--r-- | drivers/acpi/acpica/nsobject.c | 10 | ||||
-rw-r--r-- | drivers/acpi/acpica/utdelete.c | 15 |
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 & |