ACPICA: Update parameter validation for data_table_region and load_table
authorBob Moore <robert.moore@intel.com>
Tue, 25 Aug 2015 02:28:39 +0000 (10:28 +0800)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tue, 25 Aug 2015 21:11:31 +0000 (23:11 +0200)
ACPICA commit 51ab555e60b4a3de3cc4a846e86d0de255be441a

Add additional validation for the table signature and
the OEM strings. Eliminates buffer read overrun in data_table_region.
ACPICA BZ 1184.

Link: https://bugs.acpica.org/show_bug.cgi?id=1184
Link: https://github.com/acpica/acpica/commit/51ab555e
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>
drivers/acpi/acpica/actables.h
drivers/acpi/acpica/dsopcode.c
drivers/acpi/acpica/exconfig.c
drivers/acpi/acpica/tbfind.c
drivers/acpi/acpica/tbutils.c

index 7e0b6f1bec9c98fde5ca20b9ea379bc2e6c49a88..58497b7e33472c72e31c7fe7fa525df3aa377354 100644 (file)
@@ -164,4 +164,6 @@ acpi_tb_install_fixed_table(acpi_physical_address address,
 
 acpi_status acpi_tb_parse_root_table(acpi_physical_address rsdp_address);
 
+u8 acpi_is_valid_signature(char *signature);
+
 #endif                         /* __ACTABLES_H__ */
index ea0cc4e08f8033c8acc230657d6d425a2a801510..81d7b9863e3213855790536b41b550a48e727375 100644 (file)
@@ -480,8 +480,8 @@ acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state,
        union acpi_operand_object **operand;
        struct acpi_namespace_node *node;
        union acpi_parse_object *next_op;
-       u32 table_index;
        struct acpi_table_header *table;
+       u32 table_index;
 
        ACPI_FUNCTION_TRACE_PTR(ds_eval_table_region_operands, op);
 
@@ -504,6 +504,8 @@ acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state,
                return_ACPI_STATUS(status);
        }
 
+       operand = &walk_state->operands[0];
+
        /*
         * Resolve the Signature string, oem_id string,
         * and oem_table_id string operands
@@ -511,32 +513,34 @@ acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state,
        status = acpi_ex_resolve_operands(op->common.aml_opcode,
                                          ACPI_WALK_OPERANDS, walk_state);
        if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
+               goto cleanup;
        }
 
-       operand = &walk_state->operands[0];
-
        /* Find the ACPI table */
 
        status = acpi_tb_find_table(operand[0]->string.pointer,
                                    operand[1]->string.pointer,
                                    operand[2]->string.pointer, &table_index);
        if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
+               if (status == AE_NOT_FOUND) {
+                       ACPI_ERROR((AE_INFO,
+                                   "ACPI Table [%4.4s] OEM:(%s, %s) not found in RSDT/XSDT",
+                                   operand[0]->string.pointer,
+                                   operand[1]->string.pointer,
+                                   operand[2]->string.pointer));
+               }
+               goto cleanup;
        }
 
-       acpi_ut_remove_reference(operand[0]);
-       acpi_ut_remove_reference(operand[1]);
-       acpi_ut_remove_reference(operand[2]);
-
        status = acpi_get_table_by_index(table_index, &table);
        if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
+               goto cleanup;
        }
 
        obj_desc = acpi_ns_get_attached_object(node);
        if (!obj_desc) {
-               return_ACPI_STATUS(AE_NOT_EXIST);
+               status = AE_NOT_EXIST;
+               goto cleanup;
        }
 
        obj_desc->region.address = ACPI_PTR_TO_PHYSADDR(table);
@@ -551,6 +555,11 @@ acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state,
 
        obj_desc->region.flags |= AOPOBJ_DATA_VALID;
 
+cleanup:
+       acpi_ut_remove_reference(operand[0]);
+       acpi_ut_remove_reference(operand[1]);
+       acpi_ut_remove_reference(operand[2]);
+
        return_ACPI_STATUS(status);
 }
 
index 24a4c5c2b124825b5616371882ffa0f9666cdc85..b540913c11acebdb2bb9ee16e9915445a58dd40f 100644 (file)
@@ -162,14 +162,6 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
 
        ACPI_FUNCTION_TRACE(ex_load_table_op);
 
-       /* Validate lengths for the Signature, oem_id, and oem_table_id strings */
-
-       if ((operand[0]->string.length > ACPI_NAME_SIZE) ||
-           (operand[1]->string.length > ACPI_OEM_ID_SIZE) ||
-           (operand[2]->string.length > ACPI_OEM_TABLE_ID_SIZE)) {
-               return_ACPI_STATUS(AE_AML_STRING_LIMIT);
-       }
-
        /* Find the ACPI table in the RSDT/XSDT */
 
        status = acpi_tb_find_table(operand[0]->string.pointer,
index 119c84ad98334e2404fb72e585c4ec30ee49c684..405529d49a1ab83d20387900682c3a983d7c7a67 100644 (file)
@@ -68,12 +68,25 @@ acpi_status
 acpi_tb_find_table(char *signature,
                   char *oem_id, char *oem_table_id, u32 *table_index)
 {
-       u32 i;
        acpi_status status;
        struct acpi_table_header header;
+       u32 i;
 
        ACPI_FUNCTION_TRACE(tb_find_table);
 
+       /* Validate the input table signature */
+
+       if (!acpi_is_valid_signature(signature)) {
+               return_ACPI_STATUS(AE_BAD_SIGNATURE);
+       }
+
+       /* Don't allow the OEM strings to be too long */
+
+       if ((strlen(oem_id) > ACPI_OEM_ID_SIZE) ||
+           (strlen(oem_table_id) > ACPI_OEM_TABLE_ID_SIZE)) {
+               return_ACPI_STATUS(AE_AML_STRING_LIMIT);
+       }
+
        /* Normalize the input strings */
 
        memset(&header, 0, sizeof(struct acpi_table_header));
index 568ac0e4a3c6a784efe38349213c26146888f6d5..db7f2aa9a457d7e63aded8bf014dbcb07896ba62 100644 (file)
@@ -412,3 +412,36 @@ next_table:
 
        return_ACPI_STATUS(AE_OK);
 }
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_is_valid_signature
+ *
+ * PARAMETERS:  signature           - Sig string to be validated
+ *
+ * RETURN:      TRUE if signature is correct length and has valid characters
+ *
+ * DESCRIPTION: Validate an ACPI table signature.
+ *
+ ******************************************************************************/
+
+u8 acpi_is_valid_signature(char *signature)
+{
+       u32 i;
+
+       /* Validate the signature length */
+
+       if (strlen(signature) != ACPI_NAME_SIZE) {
+               return (FALSE);
+       }
+
+       /* Validate each character in the signature */
+
+       for (i = 0; i < ACPI_NAME_SIZE; i++) {
+               if (!acpi_ut_valid_acpi_char(signature[i], i)) {
+                       return (FALSE);
+               }
+       }
+
+       return (TRUE);
+}