diff mbox series

[RFC,2/4] memory: avoid reenter the device's MMIO handler while processing MMIO

Message ID 20200908164157.47108-3-liq3ea@163.com (mailing list archive)
State New, archived
Headers show
Series Add a 'in_mmio' device flag to avoid the DMA to MMIO | expand

Commit Message

Li Qiang Sept. 8, 2020, 4:41 p.m. UTC
This patch adds a 'in_mmio' flag to 'DeviceState' to indicate that the
device is doing MMIO path. This can avoid the malicious guest do
DMA to MMIO and crash the qemu.

Signed-off-by: Li Qiang <liq3ea@163.com>
---
 include/hw/qdev-core.h |  1 +
 softmmu/memory.c       | 31 ++++++++++++++++++++++++++++---
 2 files changed, 29 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index ea3f73a282..c6f4ebba9e 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -177,6 +177,7 @@  struct DeviceState {
     char *canonical_path;
     bool realized;
     bool pending_deleted_event;
+    bool in_mmio;
     QemuOpts *opts;
     int hotplugged;
     bool allow_unplug_during_migration;
diff --git a/softmmu/memory.c b/softmmu/memory.c
index 2628c9d2d9..7be44f7175 100644
--- a/softmmu/memory.c
+++ b/softmmu/memory.c
@@ -1410,8 +1410,20 @@  MemTxResult memory_region_dispatch_read(MemoryRegion *mr,
         return MEMTX_DECODE_ERROR;
     }
 
+    if (mr->dev) {
+        if (mr->dev->in_mmio) {
+            return MEMTX_ERROR;
+        } else {
+            mr->dev->in_mmio = true;
+        }
+    }
+
     r = memory_region_dispatch_read1(mr, addr, pval, size, attrs);
     adjust_endianness(mr, pval, op);
+
+    if (mr->dev) {
+        mr->dev->in_mmio = false;
+    }
     return r;
 }
 
@@ -1448,6 +1460,7 @@  MemTxResult memory_region_dispatch_write(MemoryRegion *mr,
                                          MemTxAttrs attrs)
 {
     unsigned size = memop_size(op);
+    MemTxResult ret;
 
     if (!memory_region_access_valid(mr, addr, size, true, attrs)) {
         unassigned_mem_write(mr, addr, data, size);
@@ -1461,20 +1474,32 @@  MemTxResult memory_region_dispatch_write(MemoryRegion *mr,
         return MEMTX_OK;
     }
 
+    if (mr->dev) {
+        if (mr->dev->in_mmio) {
+            return MEMTX_ERROR;
+        } else {
+            mr->dev->in_mmio = true;
+        }
+    }
+
     if (mr->ops->write) {
-        return access_with_adjusted_size(addr, &data, size,
+        ret = access_with_adjusted_size(addr, &data, size,
                                          mr->ops->impl.min_access_size,
                                          mr->ops->impl.max_access_size,
                                          memory_region_write_accessor, mr,
                                          attrs);
     } else {
-        return
-            access_with_adjusted_size(addr, &data, size,
+        ret = access_with_adjusted_size(addr, &data, size,
                                       mr->ops->impl.min_access_size,
                                       mr->ops->impl.max_access_size,
                                       memory_region_write_with_attrs_accessor,
                                       mr, attrs);
     }
+    if (mr->dev) {
+        mr->dev->in_mmio = false;
+    }
+
+    return ret;
 }
 
 void memory_region_init_io(MemoryRegion *mr,