@samitouri / QOSamiQemu / commits / 42f599172a

hw/misc/edu: restrict dma access to dma buffer

The EDU device doesn't enforce any bound checks on the addresses provided, allowing users of the device to perform arbitrary reads and writes to QEMU's address space. Signed-off-by: Torin Carey <torin@tcarey.uk> Cc: qemu-stable@nongnu.org Fixes: 7b608e5d6c1 ("hw: misc: edu: use qemu_log_mask instead of hw_error") Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3852 Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-ID: <aQtAotYvzFY0Vpft@tcarey.uk> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>

Torin Carey committed Nov 5, 2025 at 12:18 UTC 42f599172ae023924f288e20af0ceed681674747
1 file changed +14 -10
hw/misc/edu.c
+14 -10
@@ -103,7 +103,7 @@ static void edu_lower_irq(EduState *edu, uint32_t val)
103 }
104 }
105
106 -static void edu_check_range(uint64_t xfer_start, uint64_t xfer_size,
106 +static bool edu_check_range(uint64_t xfer_start, uint64_t xfer_size,
107 uint64_t dma_start, uint64_t dma_size)
108 {
109 uint64_t xfer_end = xfer_start + xfer_size;
@@ -115,13 +115,15 @@ static void edu_check_range(uint64_t xfer_start, uint64_t xfer_size,
115 */
116 if (dma_end >= dma_start && xfer_end >= xfer_start &&
117 xfer_start >= dma_start && xfer_end <= dma_end) {
118 - return;
118 + return true;
119 }
120
121 qemu_log_mask(LOG_GUEST_ERROR,
122 "EDU: DMA range 0x%016"PRIx64"-0x%016"PRIx64
123 " out of bounds (0x%016"PRIx64"-0x%016"PRIx64")!",
124 xfer_start, xfer_end - 1, dma_start, dma_end - 1);
125 +
126 + return false;
127 }
128
129 static dma_addr_t edu_clamp_addr(const EduState *edu, dma_addr_t addr)
@@ -148,16 +150,18 @@ static void edu_dma_timer(void *opaque)
150
151 if (EDU_DMA_DIR(edu->dma.cmd) == EDU_DMA_FROM_PCI) {
152 uint64_t dst = edu->dma.dst;
151 - edu_check_range(dst, edu->dma.cnt, DMA_START, DMA_SIZE);
152 - dst -= DMA_START;
153 - pci_dma_read(&edu->pdev, edu_clamp_addr(edu, edu->dma.src),
154 - edu->dma_buf + dst, edu->dma.cnt);
153 + if (edu_check_range(dst, edu->dma.cnt, DMA_START, DMA_SIZE)) {
154 + dst -= DMA_START;
155 + pci_dma_read(&edu->pdev, edu_clamp_addr(edu, edu->dma.src),
156 + edu->dma_buf + dst, edu->dma.cnt);
157 + }
158 } else {
159 uint64_t src = edu->dma.src;
157 - edu_check_range(src, edu->dma.cnt, DMA_START, DMA_SIZE);
158 - src -= DMA_START;
159 - pci_dma_write(&edu->pdev, edu_clamp_addr(edu, edu->dma.dst),
160 - edu->dma_buf + src, edu->dma.cnt);
160 + if (edu_check_range(src, edu->dma.cnt, DMA_START, DMA_SIZE)) {
161 + src -= DMA_START;
162 + pci_dma_write(&edu->pdev, edu_clamp_addr(edu, edu->dma.dst),
163 + edu->dma_buf + src, edu->dma.cnt);
164 + }
165 }
166
167 edu->dma.cmd &= ~EDU_DMA_RUN;