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 <lv.zheng@intel.com> [ rjw: Changelog, comments ] Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
parent
186f0a0d8e
commit
83848fbe7e
|
@ -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) {
|
||||
|
||||
|
|
|
@ -374,6 +374,20 @@ struct acpi_table_desc {
|
|||
u16 validation_count;
|
||||
};
|
||||
|
||||
/*
|
||||
* Maximum value of the validation_count field in struct acpi_table_desc.
|
||||
* When reached, validation_count cannot be changed any more and the table will
|
||||
* be permanently regarded as validated.
|
||||
*
|
||||
* This is to prevent situations in which unbalanced table get/put operations
|
||||
* may cause premature table unmapping in the OS to happen.
|
||||
*
|
||||
* The maximum validation count can be defined to any value, but should be
|
||||
* greater than the maximum number of OS early stage mapping slots to avoid
|
||||
* leaking early stage table mappings to the late stage.
|
||||
*/
|
||||
#define ACPI_MAX_TABLE_VALIDATIONS ACPI_UINT16_MAX
|
||||
|
||||
/* Masks for Flags field above */
|
||||
|
||||
#define ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL (0) /* Virtual address, external maintained */
|
||||
|
|
Loading…
Reference in New Issue