@samitouri / QOSamiQemu / commits / d7f16bad8f

hw/ide/ahci: refuse a PIO transfer with no command header

ahci_map_clb_address() already clears cur_cmd, so every consumer of it has to cope with there being no current command. ahci_pio_transfer(), ahci_commit_buf() and ahci_populate_sglist() all dereference it unconditionally instead. Give the three of them a NULL check. Declaring the data transferred anyway is not enough: ide_transfer_start() goes on to call the end transfer function, and for a multi-sector write that is ide_sector_write(), which commits an io_buffer the guest never refilled. Clearing PxCMD.ST during a WRITE SECTOR(S) of two sectors therefore writes the first sector's contents over the second, at a sector the guest chose. Let pio_transfer report that nothing was transferred and halt there, so no callback acts on a buffer that was never filled. Only the AHCI HBA implements the callback, so the signature change is local to it. Cc: John Snow <jsnow@redhat.com> Cc: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Signed-off-by: Denis V. Lunev <den@openvz.org>

Denis V. Lunev committed Aug 17, 2026 at 23:44 UTC d7f16bad8f0263ca01c1da61d5d69ee79fca837f
4 files changed +51 -12
hw/ide/ahci.c
+37 -10
@@ -906,12 +906,12 @@ static int prdt_tbl_entry_size(const AHCI_SG *tbl)
906 static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist,
907 AHCICmdHdr *cmd, int64_t limit, uint64_t offset)
908 {
909 - uint16_t opts = le16_to_cpu(cmd->opts);
910 - uint16_t prdtl = le16_to_cpu(cmd->prdtl);
911 - uint64_t cfis_addr = le64_to_cpu(cmd->tbl_addr);
912 - uint64_t prdt_addr = cfis_addr + 0x80;
913 - dma_addr_t prdt_len = (prdtl * sizeof(AHCI_SG));
914 - dma_addr_t real_prdt_len = prdt_len;
909 + uint16_t opts;
910 + uint16_t prdtl;
911 + uint64_t cfis_addr;
912 + uint64_t prdt_addr;
913 + dma_addr_t prdt_len;
914 + dma_addr_t real_prdt_len;
915 uint8_t *prdt;
916 int i;
917 int r = 0;
@@ -923,6 +923,18 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist,
923
924 trace_ahci_populate_sglist(ad->hba, ad->port_no);
925
926 + if (!cmd) {
927 + trace_ahci_populate_sglist_no_cmd(ad->hba, ad->port_no);
928 + return -1;
929 + }
930 +
931 + opts = le16_to_cpu(cmd->opts);
932 + prdtl = le16_to_cpu(cmd->prdtl);
933 + cfis_addr = le64_to_cpu(cmd->tbl_addr);
934 + prdt_addr = cfis_addr + 0x80;
935 + prdt_len = (prdtl * sizeof(AHCI_SG));
936 + real_prdt_len = prdt_len;
937 +
938 if (!prdtl) {
939 trace_ahci_populate_sglist_no_prdtl(ad->hba, ad->port_no, opts);
940 return -1;
@@ -1371,18 +1383,27 @@ out:
1383 }
1384
1385 /* Transfer PIO data between RAM and device */
1374 -static void ahci_pio_transfer(const IDEDMA *dma)
1386 +static bool ahci_pio_transfer(const IDEDMA *dma)
1387 {
1388 AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
1389 IDEState *s = &ad->port.ifs[0];
1390 uint32_t size = (uint32_t)(s->data_end - s->data_ptr);
1391 /* write == ram -> device */
1380 - uint16_t opts = le16_to_cpu(ad->cur_cmd->opts);
1381 - int is_write = opts & AHCI_CMD_WRITE;
1382 - int is_atapi = opts & AHCI_CMD_ATAPI;
1392 + uint16_t opts;
1393 + int is_write;
1394 + int is_atapi;
1395 int has_sglist = 0;
1396 bool pio_fis_i;
1397
1398 + if (ad->cur_cmd == NULL) {
1399 + trace_ahci_pio_transfer_no_cmd(ad->hba, ad->port_no);
1400 + return false;
1401 + }
1402 +
1403 + opts = le16_to_cpu(ad->cur_cmd->opts);
1404 + is_write = opts & AHCI_CMD_WRITE;
1405 + is_atapi = opts & AHCI_CMD_ATAPI;
1406 +
1407 /* The PIO Setup FIS is received prior to transfer, but the interrupt
1408 * is only triggered after data is received.
1409 *
@@ -1430,6 +1451,8 @@ out:
1451 if (pio_fis_i) {
1452 ahci_trigger_irq(ad->hba, ad, AHCI_PORT_IRQ_BIT_PSS);
1453 }
1454 +
1455 + return true;
1456 }
1457
1458 static void ahci_start_dma(const IDEDMA *dma, IDEState *s,
@@ -1492,6 +1515,10 @@ static void ahci_commit_buf(const IDEDMA *dma, uint32_t tx_bytes)
1515 {
1516 AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
1517
1518 + if (ad->cur_cmd == NULL) {
1519 + return;
1520 + }
1521 +
1522 tx_bytes += le32_to_cpu(ad->cur_cmd->status);
1523 ad->cur_cmd->status = cpu_to_le32(tx_bytes);
1524 }
hw/ide/core.c
+10 -1
@@ -80,6 +80,7 @@ static const char *IDE_DMA_CMD_str(enum ide_dma_cmd enval)
80 }
81
82 static void ide_dummy_transfer_stop(IDEState *s);
83 +static void ide_transfer_halt(IDEState *s);
84
85 const MemoryRegionPortio ide_portio_list[] = {
86 { 0, 8, 1, .read = ide_ioport_read, .write = ide_ioport_write },
@@ -568,7 +569,15 @@ bool ide_transfer_start_norecurse(IDEState *s, uint8_t *buf, int size,
569 s->end_transfer_func = end_transfer_func;
570 return false;
571 }
571 - s->bus->dma->ops->pio_transfer(s->bus->dma);
572 + if (!s->bus->dma->ops->pio_transfer(s->bus->dma)) {
573 + /*
574 + * No data reached the buffer, so the caller must not act on it. A
575 + * write would otherwise commit whatever the previous phase left
576 + * there to the next sector.
577 + */
578 + ide_transfer_halt(s);
579 + return false;
580 + }
581 return true;
582 }
583
hw/ide/trace-events
+2
@@ -85,6 +85,7 @@ ahci_reset_port(void *s, int port) "ahci(%p)[%d]: reset port"
85 ahci_unmap_fis_address_null(void *s, int port) "ahci(%p)[%d]: Attempt to unmap NULL FIS address"
86 ahci_unmap_clb_address_null(void *s, int port) "ahci(%p)[%d]: Attempt to unmap NULL CLB address"
87 ahci_populate_sglist(void *s, int port) "ahci(%p)[%d]"
88 +ahci_populate_sglist_no_cmd(void *s, int port) "ahci(%p)[%d]: no command header"
89 ahci_populate_sglist_no_prdtl(void *s, int port, uint16_t opts) "ahci(%p)[%d]: no sg list given by guest: 0x%04x"
90 ahci_populate_sglist_no_map(void *s, int port) "ahci(%p)[%d]: DMA mapping failed"
91 ahci_populate_sglist_short_map(void *s, int port) "ahci(%p)[%d]: mapped less than expected"
@@ -109,6 +110,7 @@ handle_cmd_badfis(void *s, int port) "ahci(%p)[%d]: guest provided an invalid cm
110 handle_cmd_badmap(void *s, int port, uint64_t len) "ahci(%p)[%d]: dma_memory_map failed, 0x%02"PRIx64" != 0x80"
111 handle_cmd_unhandled_fis(void *s, int port, uint8_t b0, uint8_t b1, uint8_t b2) "ahci(%p)[%d]: unhandled FIS type. cmd_fis: 0x%02x-%02x-%02x"
112 ahci_pio_transfer(void *s, int port, const char *rw, uint32_t size, const char *tgt, const char *sgl) "ahci(%p)[%d]: %sing %d bytes on %s w/%s sglist"
113 +ahci_pio_transfer_no_cmd(void *s, int port) "ahci(%p)[%d]: PIO transfer without a command header"
114 ahci_start_dma(void *s, int port) "ahci(%p)[%d]: start dma"
115 ahci_dma_prepare_buf(void *s, int port, int32_t io_buffer_size, int32_t limit) "ahci(%p)[%d]: prepare buf limit=%"PRId32" prepared=%"PRId32
116 ahci_dma_prepare_buf_fail(void *s, int port) "ahci(%p)[%d]: sglist population failed"
include/hw/ide/ide-dma.h
+2 -1
@@ -10,6 +10,7 @@ typedef struct IDEDMA IDEDMA;
10
11 typedef void DMAStartFunc(const IDEDMA *, IDEState *, BlockCompletionFunc *);
12 typedef void DMAVoidFunc(const IDEDMA *);
13 +typedef bool DMABoolFunc(const IDEDMA *);
14 typedef int DMAIntFunc(const IDEDMA *, bool);
15 typedef int32_t DMAInt32Func(const IDEDMA *, int32_t len);
16 typedef void DMAu32Func(const IDEDMA *, uint32_t);
@@ -17,7 +18,7 @@ typedef void DMAStopFunc(const IDEDMA *, bool);
18
19 struct IDEDMAOps {
20 DMAStartFunc *start_dma;
20 - DMAVoidFunc *pio_transfer;
21 + DMABoolFunc *pio_transfer;
22 DMAInt32Func *prepare_buf;
23 DMAu32Func *commit_buf;
24 DMAIntFunc *rw_buf;