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;