From 83848fbe7e6af978c080a88c130a67178b1ac0e4 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 7 Jun 2017 12:54:58 +0800 Subject: ACPICA: Tables: Mechanism to handle late stage acpi_get_table() imbalance Considering this case: 1. A program opens a sysfs table file 65535 times, it can increase validation_count and first increment cause the table to be mapped: validation_count = 65535 2. AML execution causes "Load" to be executed on the same table, this time it cannot increase validation_count, so validation_count remains: validation_count = 65535 3. The program closes sysfs table file 65535 times, it can decrease validation_count and the last decrement cause the table to be unmapped: validation_count = 0 4. AML code still accessing the loaded table, kernel crash can be observed. To prevent that from happening, add a validation_count threashold. When it is reached, the validation_count can no longer be incremented/decremented to invalidate the table descriptor (means preventing table unmappings) Note that code added in acpi_tb_put_table() is actually a no-op but changes the warning message into a "warn once" one. Lv Zheng. Signed-off-by: Lv Zheng [ rjw: Changelog, comments ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/tbutils.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 7abe66505739..0d2e98920069 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -416,9 +416,18 @@ acpi_tb_get_table(struct acpi_table_desc *table_desc, } } - table_desc->validation_count++; - if (table_desc->validation_count == 0) { - table_desc->validation_count--; + if (table_desc->validation_count < ACPI_MAX_TABLE_VALIDATIONS) { + table_desc->validation_count++; + + /* + * Detect validation_count overflows to ensure that the warning + * message will only be printed once. + */ + if (table_desc->validation_count >= ACPI_MAX_TABLE_VALIDATIONS) { + ACPI_WARNING((AE_INFO, + "Table %p, Validation count overflows\n", + table_desc)); + } } *out_table = table_desc->pointer; @@ -445,13 +454,20 @@ void acpi_tb_put_table(struct acpi_table_desc *table_desc) ACPI_FUNCTION_TRACE(acpi_tb_put_table); - if (table_desc->validation_count == 0) { - ACPI_WARNING((AE_INFO, - "Table %p, Validation count is zero before decrement\n", - table_desc)); - return_VOID; + if (table_desc->validation_count < ACPI_MAX_TABLE_VALIDATIONS) { + table_desc->validation_count--; + + /* + * Detect validation_count underflows to ensure that the warning + * message will only be printed once. + */ + if (table_desc->validation_count >= ACPI_MAX_TABLE_VALIDATIONS) { + ACPI_WARNING((AE_INFO, + "Table %p, Validation count underflows\n", + table_desc)); + return_VOID; + } } - table_desc->validation_count--; if (table_desc->validation_count == 0) { -- cgit v1.2.3