aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShannon Zhao <zhaoshenglong@huawei.com>2018-05-31 14:50:53 +0100
committerPeter Maydell <peter.maydell@linaro.org>2018-05-31 16:32:35 +0100
commit6e3e723966197463117642d8a5fd7b4f6446e510 (patch)
tree3fbefd8ee42e9271f2c2e0ccc1b3183c7bb5e5d1
parente0a37e266084fb26951465e08515af46807c312c (diff)
ARM: ACPI: Fix use-after-free due to memory realloc
acpi_data_push uses g_array_set_size to resize the memory size. If there is no enough contiguous memory, the address will be changed. So previous pointer could not be used any more. It must update the pointer and use the new one. Also, previous codes wrongly use le32 conversion of iort->node_offset for subsequent computations that will result incorrect value if host is not litlle endian. So use the non-converted one instead. Signed-off-by: Shannon Zhao <zhaoshenglong@huawei.com> Reviewed-by: Eric Auger <eric.auger@redhat.com> Message-id: 1527663951-14552-1-git-send-email-zhaoshenglong@huawei.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--hw/arm/virt-acpi-build.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 92ceee9c0f..74f5744e87 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -400,7 +400,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
AcpiIortItsGroup *its;
AcpiIortTable *iort;
AcpiIortSmmu3 *smmu;
- size_t node_size, iort_length, smmu_offset = 0;
+ size_t node_size, iort_node_offset, iort_length, smmu_offset = 0;
AcpiIortRC *rc;
iort = acpi_data_push(table_data, sizeof(*iort));
@@ -413,7 +413,12 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
iort_length = sizeof(*iort);
iort->node_count = cpu_to_le32(nb_nodes);
- iort->node_offset = cpu_to_le32(sizeof(*iort));
+ /*
+ * Use a copy in case table_data->data moves during acpi_data_push
+ * operations.
+ */
+ iort_node_offset = sizeof(*iort);
+ iort->node_offset = cpu_to_le32(iort_node_offset);
/* ITS group node */
node_size = sizeof(*its) + sizeof(uint32_t);
@@ -429,7 +434,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
int irq = vms->irqmap[VIRT_SMMU];
/* SMMUv3 node */
- smmu_offset = iort->node_offset + node_size;
+ smmu_offset = iort_node_offset + node_size;
node_size = sizeof(*smmu) + sizeof(*idmap);
iort_length += node_size;
smmu = acpi_data_push(table_data, node_size);
@@ -450,7 +455,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
idmap->id_count = cpu_to_le32(0xFFFF);
idmap->output_base = 0;
/* output IORT node is the ITS group node (the first node) */
- idmap->output_reference = cpu_to_le32(iort->node_offset);
+ idmap->output_reference = cpu_to_le32(iort_node_offset);
}
/* Root Complex Node */
@@ -479,9 +484,14 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
idmap->output_reference = cpu_to_le32(smmu_offset);
} else {
/* output IORT node is the ITS group node (the first node) */
- idmap->output_reference = cpu_to_le32(iort->node_offset);
+ idmap->output_reference = cpu_to_le32(iort_node_offset);
}
+ /*
+ * Update the pointer address in case table_data->data moves during above
+ * acpi_data_push operations.
+ */
+ iort = (AcpiIortTable *)(table_data->data + iort_start);
iort->length = cpu_to_le32(iort_length);
build_header(linker, table_data, (void *)(table_data->data + iort_start),