Commit a2fbf1785b for qemu.org
commit a2fbf1785b7a464d61c0f60c4ad0a86d82925e5d
Author: Denis V. Lunev <den@openvz.org>
Date: Mon Aug 17 23:44:59 2026 +0200
hw/ide/ahci: clear cur_cmd when the command list is unmapped
ahci_unmap_clb_address() drops the CLB mapping but leaves cur_cmd
pointing into it. The cancel added by commit d9f78431d8 covers the
buffered reads, and ide_cancel_dma_sync() drains bus->dma->aiocb, but
neither reaches IDEState::pio_aiocb: a PIO write started before the
guest cleared PxCMD.ST completes afterwards and runs its second DRQ
phase against the stale header.
That is harmless while the CLB is direct RAM, because unmapping it
changes nothing. It is a use-after-free once PxCLB points at an MMIO
region, where address_space_map() hands out a bounce buffer that
dma_memory_unmap() then frees.
Clear cur_cmd after the cancel, so nothing reachable from a later
completion still refers to the freed mapping.
Reported-by: Katherine Leaver <katherine.j.leaver@gmail.com>
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3719
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/4043
Cc: John Snow <jsnow@redhat.com>
Cc: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Signed-off-by: Denis V. Lunev <den@openvz.org>
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 995b40efd5..4c138b0c51 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -743,6 +743,12 @@ static void ahci_unmap_clb_address(AHCIDevice *ad)
/* Cancel in-flight reads that would complete against a cleared cur_cmd. */
ide_cancel_dma_sync(ide_bus_active_if(&ad->port));
+ /*
+ * Whatever survives the cancel must not be left pointing into the
+ * mapping this function is about to drop.
+ */
+ ad->cur_cmd = NULL;
+
if (ad->lst == NULL) {
trace_ahci_unmap_clb_address_null(ad->hba, ad->port_no);
return;