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 <liq...@163.com> --- include/hw/qdev-core.h | 1 + softmmu/memory.c | 31 ++++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) 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, -- 2.17.1