@samitouri / QOSamiQemu / commits / c257745248

hw/audio/intel-hda: restrict all DMA engine paths to memories

CVE-2021-3611 (commit 79fa99831d) restricted the DMA engine to memories by setting attrs.memory=true, but only applied this to intel_hda_response. Three other DMA engine access points still use MEMTXATTRS_UNSPECIFIED, allowing a malicious guest to trigger DMA-to-self-MMIO reentry: - intel_hda_xfer (line 398): called from the audio timer callback (hda_codec_xfer -> bus->xfer), so the MemReentrancyGuard does not fire (engaged_in_io is false outside MMIO dispatch). A guest that points a BDL entry at the HDA controller's own MMIO BAR can write audio samples to device registers, triggering whandler side effects such as starting/stopping streams or injecting codec commands via CORBWP. - intel_hda_parse_bdl (line 478): uses pci_dma_read which hardcodes MEMTXATTRS_UNSPECIFIED. A guest-controlled BDL base address can point at controller MMIO, allowing the DMA engine to read device registers as BDL descriptors. - intel_hda_corb_run (line 333): ldl_le_pci_dma reads the CORB ring with MEMTXATTRS_UNSPECIFIED, allowing the DMA engine to read controller MMIO as CORB entries. Fix all three by passing {.memory = true} explicitly, matching the fix already applied to intel_hda_response. For intel_hda_parse_bdl, replace pci_dma_read with pci_dma_rw to pass the controlled attrs. Fixes: 79fa99831d ("hw/audio/intel-hda: Restrict DMA engine to memories (not MMIO devices)") Reported-by: Haotian Jiang of Tencent Security (Yunding Lab) <jianghaotian.sunday@gmail.com> Signed-off-by: Haotian Jiang <jianghaotian.sunday@gmail.com> Cc: qemu-stable@nongnu.org Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Message-ID: <20260721060941.2989396-1-jianghaotian.sunday@gmail.com> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>

Haotian Jiang committed Jul 21, 2026 at 14:09 UTC c257745248b02fd468619b4b1fdbbade5344191d
1 file changed +6 -3
hw/audio/intel-hda.c
+6 -3
@@ -305,6 +305,7 @@ static int intel_hda_send_command(IntelHDAState *d, uint32_t verb)
305
306 static void intel_hda_corb_run(IntelHDAState *d)
307 {
308 + const MemTxAttrs attrs = { .memory = true };
309 hwaddr addr;
310 uint32_t rp, verb;
311
@@ -330,7 +331,7 @@ static void intel_hda_corb_run(IntelHDAState *d)
331
332 rp = (d->corb_rp + 1) & 0xff;
333 addr = intel_hda_addr(d->corb_lbase, d->corb_ubase);
333 - ldl_le_pci_dma(&d->pci, addr + 4 * rp, &verb, MEMTXATTRS_UNSPECIFIED);
334 + ldl_le_pci_dma(&d->pci, addr + 4 * rp, &verb, attrs);
335 d->corb_rp = rp;
336
337 dprint(d, 2, "%s: [rp 0x%x] verb 0x%08x\n", __func__, rp, verb);
@@ -395,7 +396,7 @@ static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t res
396 static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
397 uint8_t *buf, uint32_t len)
398 {
398 - const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
399 + const MemTxAttrs attrs = { .memory = true };
400 HDACodecBus *bus = HDA_BUS(dev->qdev.parent_bus);
401 IntelHDAState *d = container_of(bus, IntelHDAState, codecs);
402 hwaddr addr;
@@ -466,6 +467,7 @@ static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
467
468 static void intel_hda_parse_bdl(IntelHDAState *d, IntelHDAStream *st)
469 {
470 + const MemTxAttrs attrs = { .memory = true };
471 hwaddr addr;
472 uint8_t buf[16];
473 uint32_t i;
@@ -475,7 +477,8 @@ static void intel_hda_parse_bdl(IntelHDAState *d, IntelHDAStream *st)
477 g_free(st->bpl);
478 st->bpl = g_new(bpl, st->bentries);
479 for (i = 0; i < st->bentries; i++, addr += 16) {
478 - pci_dma_read(&d->pci, addr, buf, 16);
480 + pci_dma_rw(&d->pci, addr, buf, 16,
481 + DMA_DIRECTION_TO_DEVICE, attrs);
482 st->bpl[i].addr = le64_to_cpu(*(uint64_t *)buf);
483 st->bpl[i].len = le32_to_cpu(*(uint32_t *)(buf + 8));
484 st->bpl[i].flags = le32_to_cpu(*(uint32_t *)(buf + 12));