diff mbox

[1/3] acpica: add some extra run time verification to FACP (FADT)

Message ID 20170324161015.8664-2-colin.king@canonical.com
State Accepted
Headers show

Commit Message

Colin Ian King March 24, 2017, 4:10 p.m. UTC
From: Colin Ian King <colin.king@canonical.com>

While running fwts through some regression tests from random broken
ACPI data dumps I found that some files have an FACP (FADT) that
point to the FACS or DSDT which actually don't exist in the data
dump. This causes ACPICA to segfault because we have pointers to
non-existent tables. Add a level of verification on these tables
to ensure we are not passing garbage to the ACPICA execution engine.

Signed-off-by: Colin Ian King <colin.king@canonical.com>
---
 src/acpica/fwts_acpica.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)

Comments

Alex Hung March 25, 2017, 2:46 a.m. UTC | #1
On 2017-03-25 12:10 AM, Colin King wrote:
> From: Colin Ian King <colin.king@canonical.com>
>
> While running fwts through some regression tests from random broken
> ACPI data dumps I found that some files have an FACP (FADT) that
> point to the FACS or DSDT which actually don't exist in the data
> dump. This causes ACPICA to segfault because we have pointers to
> non-existent tables. Add a level of verification on these tables
> to ensure we are not passing garbage to the ACPICA execution engine.
>
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
> ---
>  src/acpica/fwts_acpica.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 70 insertions(+)
>
> diff --git a/src/acpica/fwts_acpica.c b/src/acpica/fwts_acpica.c
> index 726623cc..c26e3e4d 100644
> --- a/src/acpica/fwts_acpica.c
> +++ b/src/acpica/fwts_acpica.c
> @@ -957,6 +957,73 @@ static int fwtsInstallLateHandlers(fwts_framework *fw)
>  }
>
>  /*
> + *  fwts_acpica_verify_table_get()
> + *	fetch a named table with some sanity checks, helper
> + *	function for fwts_acpica_verify_facp_table_pointers().
> + *	Note: table is never NULL
> + */
> +static int fwts_acpica_verify_table_get(
> +	fwts_framework *fw,
> +	const char *name,
> +	fwts_acpi_table_info **table)
> +{
> +	if (fwts_acpi_find_table(fw, name, 0, table) != FWTS_OK) {
> +		fwts_log_error(fw, "Failed to find ACPI table '%s'.", name);
> +		return FWTS_ERROR;
> +	}
> +	if (!(*table)) {
> +		/* The load may have failed to find this table */
> +		fwts_log_error(fw, "Missing ACPI table '%s' and  "
> +			"the FACP points to it.", name);
> +		return FWTS_ERROR;
> +	}
> +	if ((*table)->data == NULL) {
> +		/* This really should not happen */
> +		fwts_log_error(fw, "ACPI table %s had a NULL address "
> +			"which is unexpected.", name);
> +		return FWTS_ERROR;
> +	}
> +	return FWTS_OK;
> +}
> +
> +/*
> + *  fwts_acpica_verify_facp_table_pointers()
> + *	verify facp points to tables that actually exist
> + *	Note: if they don't exist then ACPICA segfaults
> + */
> +static int fwts_acpica_verify_facp_table_pointers(fwts_framework *fw)
> +{
> +	fwts_acpi_table_info *table;
> +	fwts_acpi_table_fadt *fadt;
> +
> +	if (fwts_acpica_verify_table_get(fw, "FACP", &table) != FWTS_OK)
> +		return FWTS_ERROR;
> +	fadt = (fwts_acpi_table_fadt *)table->data;
> +
> +	if (fadt->dsdt || fadt->x_dsdt) {
> +		if (fwts_acpica_verify_table_get(fw, "DSDT", &table) != FWTS_OK)
> +			return FWTS_ERROR;
> +	printf("FADT DSDT -> %" PRIx32 " %" PRIx64 " %" PRIx64 "\n",
> +		fadt->dsdt, fadt->x_dsdt,  table->addr);
> +		if (((uint64_t)fadt->dsdt != table->addr) &&
> +		    (fadt->x_dsdt != table->addr)) {
> +			fwts_log_error(fw, "FACP points to non-existent DSDT.");
> +			return FWTS_ERROR;
> +		}
> +	}
> +	if (fadt->firmware_control || fadt->x_firmware_ctrl) {
> +		if (fwts_acpica_verify_table_get(fw, "FACS", &table) != FWTS_OK)
> +			return FWTS_ERROR;
> +		if (((uint64_t)fadt->firmware_control != table->addr) &&
> +		    (fadt->x_firmware_ctrl != table->addr)) {
> +			fwts_log_error(fw, "FACP points to non-existent FACS.");
> +			return FWTS_ERROR;
> +		}
> +	}
> +	return FWTS_OK;
> +}
> +
> +/*
>   *  fwts_acpcia_set_fwts_framework()
>   *	set fwts_acpica_fw ptr
>   */
> @@ -1048,6 +1115,9 @@ int fwts_acpica_init(fwts_framework *fw)
>  		fwts_acpica_FADT = NULL;
>  	}
>
> +	if (fwts_acpica_verify_facp_table_pointers(fw) != FWTS_OK)
> +		return FWTS_ERROR;
> +
>  	/* Clone XSDT, make it point to tables in user address space */
>  	if (fwts_acpi_find_table(fw, "XSDT", 0, &table) != FWTS_OK)
>  		return FWTS_ERROR;
>

Acked-by: Alex Hung <alex.hung@canonical.com>
Ivan Hu April 3, 2017, 9:56 a.m. UTC | #2
On 03/25/2017 12:10 AM, Colin King wrote:
> From: Colin Ian King <colin.king@canonical.com>
>
> While running fwts through some regression tests from random broken
> ACPI data dumps I found that some files have an FACP (FADT) that
> point to the FACS or DSDT which actually don't exist in the data
> dump. This causes ACPICA to segfault because we have pointers to
> non-existent tables. Add a level of verification on these tables
> to ensure we are not passing garbage to the ACPICA execution engine.
>
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
> ---
>   src/acpica/fwts_acpica.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 70 insertions(+)
>
> diff --git a/src/acpica/fwts_acpica.c b/src/acpica/fwts_acpica.c
> index 726623cc..c26e3e4d 100644
> --- a/src/acpica/fwts_acpica.c
> +++ b/src/acpica/fwts_acpica.c
> @@ -957,6 +957,73 @@ static int fwtsInstallLateHandlers(fwts_framework *fw)
>   }
>   
>   /*
> + *  fwts_acpica_verify_table_get()
> + *	fetch a named table with some sanity checks, helper
> + *	function for fwts_acpica_verify_facp_table_pointers().
> + *	Note: table is never NULL
> + */
> +static int fwts_acpica_verify_table_get(
> +	fwts_framework *fw,
> +	const char *name,
> +	fwts_acpi_table_info **table)
> +{
> +	if (fwts_acpi_find_table(fw, name, 0, table) != FWTS_OK) {
> +		fwts_log_error(fw, "Failed to find ACPI table '%s'.", name);
> +		return FWTS_ERROR;
> +	}
> +	if (!(*table)) {
> +		/* The load may have failed to find this table */
> +		fwts_log_error(fw, "Missing ACPI table '%s' and  "
> +			"the FACP points to it.", name);
> +		return FWTS_ERROR;
> +	}
> +	if ((*table)->data == NULL) {
> +		/* This really should not happen */
> +		fwts_log_error(fw, "ACPI table %s had a NULL address "
> +			"which is unexpected.", name);
> +		return FWTS_ERROR;
> +	}
> +	return FWTS_OK;
> +}
> +
> +/*
> + *  fwts_acpica_verify_facp_table_pointers()
> + *	verify facp points to tables that actually exist
> + *	Note: if they don't exist then ACPICA segfaults
> + */
> +static int fwts_acpica_verify_facp_table_pointers(fwts_framework *fw)
> +{
> +	fwts_acpi_table_info *table;
> +	fwts_acpi_table_fadt *fadt;
> +
> +	if (fwts_acpica_verify_table_get(fw, "FACP", &table) != FWTS_OK)
> +		return FWTS_ERROR;
> +	fadt = (fwts_acpi_table_fadt *)table->data;
> +
> +	if (fadt->dsdt || fadt->x_dsdt) {
> +		if (fwts_acpica_verify_table_get(fw, "DSDT", &table) != FWTS_OK)
> +			return FWTS_ERROR;
> +	printf("FADT DSDT -> %" PRIx32 " %" PRIx64 " %" PRIx64 "\n",
> +		fadt->dsdt, fadt->x_dsdt,  table->addr);
> +		if (((uint64_t)fadt->dsdt != table->addr) &&
> +		    (fadt->x_dsdt != table->addr)) {
> +			fwts_log_error(fw, "FACP points to non-existent DSDT.");
> +			return FWTS_ERROR;
> +		}
> +	}
> +	if (fadt->firmware_control || fadt->x_firmware_ctrl) {
> +		if (fwts_acpica_verify_table_get(fw, "FACS", &table) != FWTS_OK)
> +			return FWTS_ERROR;
> +		if (((uint64_t)fadt->firmware_control != table->addr) &&
> +		    (fadt->x_firmware_ctrl != table->addr)) {
> +			fwts_log_error(fw, "FACP points to non-existent FACS.");
> +			return FWTS_ERROR;
> +		}
> +	}
> +	return FWTS_OK;
> +}
> +
> +/*
>    *  fwts_acpcia_set_fwts_framework()
>    *	set fwts_acpica_fw ptr
>    */
> @@ -1048,6 +1115,9 @@ int fwts_acpica_init(fwts_framework *fw)
>   		fwts_acpica_FADT = NULL;
>   	}
>   
> +	if (fwts_acpica_verify_facp_table_pointers(fw) != FWTS_OK)
> +		return FWTS_ERROR;
> +
>   	/* Clone XSDT, make it point to tables in user address space */
>   	if (fwts_acpi_find_table(fw, "XSDT", 0, &table) != FWTS_OK)
>   		return FWTS_ERROR;


Acked-by: Ivan Hu <ivan.hu@canonical.com>
diff mbox

Patch

diff --git a/src/acpica/fwts_acpica.c b/src/acpica/fwts_acpica.c
index 726623cc..c26e3e4d 100644
--- a/src/acpica/fwts_acpica.c
+++ b/src/acpica/fwts_acpica.c
@@ -957,6 +957,73 @@  static int fwtsInstallLateHandlers(fwts_framework *fw)
 }
 
 /*
+ *  fwts_acpica_verify_table_get()
+ *	fetch a named table with some sanity checks, helper
+ *	function for fwts_acpica_verify_facp_table_pointers().
+ *	Note: table is never NULL
+ */
+static int fwts_acpica_verify_table_get(
+	fwts_framework *fw,
+	const char *name,
+	fwts_acpi_table_info **table)
+{
+	if (fwts_acpi_find_table(fw, name, 0, table) != FWTS_OK) {
+		fwts_log_error(fw, "Failed to find ACPI table '%s'.", name);
+		return FWTS_ERROR;
+	}
+	if (!(*table)) {
+		/* The load may have failed to find this table */
+		fwts_log_error(fw, "Missing ACPI table '%s' and  "
+			"the FACP points to it.", name);
+		return FWTS_ERROR;
+	}
+	if ((*table)->data == NULL) {
+		/* This really should not happen */
+		fwts_log_error(fw, "ACPI table %s had a NULL address "
+			"which is unexpected.", name);
+		return FWTS_ERROR;
+	}
+	return FWTS_OK;
+}
+
+/*
+ *  fwts_acpica_verify_facp_table_pointers()
+ *	verify facp points to tables that actually exist
+ *	Note: if they don't exist then ACPICA segfaults
+ */
+static int fwts_acpica_verify_facp_table_pointers(fwts_framework *fw)
+{
+	fwts_acpi_table_info *table;
+	fwts_acpi_table_fadt *fadt;
+
+	if (fwts_acpica_verify_table_get(fw, "FACP", &table) != FWTS_OK)
+		return FWTS_ERROR;
+	fadt = (fwts_acpi_table_fadt *)table->data;
+
+	if (fadt->dsdt || fadt->x_dsdt) {
+		if (fwts_acpica_verify_table_get(fw, "DSDT", &table) != FWTS_OK)
+			return FWTS_ERROR;
+	printf("FADT DSDT -> %" PRIx32 " %" PRIx64 " %" PRIx64 "\n",
+		fadt->dsdt, fadt->x_dsdt,  table->addr);
+		if (((uint64_t)fadt->dsdt != table->addr) &&
+		    (fadt->x_dsdt != table->addr)) {
+			fwts_log_error(fw, "FACP points to non-existent DSDT.");
+			return FWTS_ERROR;
+		}
+	}
+	if (fadt->firmware_control || fadt->x_firmware_ctrl) {
+		if (fwts_acpica_verify_table_get(fw, "FACS", &table) != FWTS_OK)
+			return FWTS_ERROR;
+		if (((uint64_t)fadt->firmware_control != table->addr) &&
+		    (fadt->x_firmware_ctrl != table->addr)) {
+			fwts_log_error(fw, "FACP points to non-existent FACS.");
+			return FWTS_ERROR;
+		}
+	}
+	return FWTS_OK;
+}
+
+/*
  *  fwts_acpcia_set_fwts_framework()
  *	set fwts_acpica_fw ptr
  */
@@ -1048,6 +1115,9 @@  int fwts_acpica_init(fwts_framework *fw)
 		fwts_acpica_FADT = NULL;
 	}
 
+	if (fwts_acpica_verify_facp_table_pointers(fw) != FWTS_OK)
+		return FWTS_ERROR;
+
 	/* Clone XSDT, make it point to tables in user address space */
 	if (fwts_acpi_find_table(fw, "XSDT", 0, &table) != FWTS_OK)
 		return FWTS_ERROR;