diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2019-02-01 14:55:45 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2019-02-01 14:55:45 +0000 |
commit | 5601be3b01d73e21c09331599e2ce62df016ff94 (patch) | |
tree | 7f2d40105790eea7e4bf4132ce10cda5e1400600 | |
parent | 4977986ca38fb1d5357532e1a8032b984047a369 (diff) |
exec.c: Don't reallocate IOMMUNotifiers that are in use
The tcg_register_iommu_notifier() code has a GArray of
TCGIOMMUNotifier structs which it has registered by passing
memory_region_register_iommu_notifier() a pointer to the embedded
IOMMUNotifier field. Unfortunately, if we need to enlarge the
array via g_array_set_size() this can cause a realloc(), which
invalidates the pointer that memory_region_register_iommu_notifier()
put into the MemoryRegion's iommu_notify list. This can result
in segfaults.
Switch the GArray to holding pointers to the TCGIOMMUNotifier
structs, so that we can individually allocate and free them.
Cc: qemu-stable@nongnu.org
Fixes: 1f871c5e6b0f30644a60a ("exec.c: Handle IOMMUs in address_space_translate_for_iotlb()")
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20190128174241.5860-1-peter.maydell@linaro.org
-rw-r--r-- | exec.c | 10 |
1 files changed, 6 insertions, 4 deletions
@@ -665,7 +665,7 @@ static void tcg_register_iommu_notifier(CPUState *cpu, int i; for (i = 0; i < cpu->iommu_notifiers->len; i++) { - notifier = &g_array_index(cpu->iommu_notifiers, TCGIOMMUNotifier, i); + notifier = g_array_index(cpu->iommu_notifiers, TCGIOMMUNotifier *, i); if (notifier->mr == mr && notifier->iommu_idx == iommu_idx) { break; } @@ -673,7 +673,8 @@ static void tcg_register_iommu_notifier(CPUState *cpu, if (i == cpu->iommu_notifiers->len) { /* Not found, add a new entry at the end of the array */ cpu->iommu_notifiers = g_array_set_size(cpu->iommu_notifiers, i + 1); - notifier = &g_array_index(cpu->iommu_notifiers, TCGIOMMUNotifier, i); + notifier = g_new0(TCGIOMMUNotifier, 1); + g_array_index(cpu->iommu_notifiers, TCGIOMMUNotifier *, i) = notifier; notifier->mr = mr; notifier->iommu_idx = iommu_idx; @@ -705,8 +706,9 @@ static void tcg_iommu_free_notifier_list(CPUState *cpu) TCGIOMMUNotifier *notifier; for (i = 0; i < cpu->iommu_notifiers->len; i++) { - notifier = &g_array_index(cpu->iommu_notifiers, TCGIOMMUNotifier, i); + notifier = g_array_index(cpu->iommu_notifiers, TCGIOMMUNotifier *, i); memory_region_unregister_iommu_notifier(notifier->mr, ¬ifier->n); + g_free(notifier); } g_array_free(cpu->iommu_notifiers, true); } @@ -976,7 +978,7 @@ void cpu_exec_realizefn(CPUState *cpu, Error **errp) vmstate_register(NULL, cpu->cpu_index, cc->vmsd, cpu); } - cpu->iommu_notifiers = g_array_new(false, true, sizeof(TCGIOMMUNotifier)); + cpu->iommu_notifiers = g_array_new(false, true, sizeof(TCGIOMMUNotifier *)); #endif } |