From 3fd64fb0e236fc80ffa2cc977c0d471f11fc39bf Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Fri, 22 Sep 2023 11:01:40 +0200 Subject: [PATCH] virDomainMemoryDefValidate: Check for overlapping memory devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As of v9.4.0-rc2~5 it is possible to specify guest address where a virtio-mem/virtio-pmem memory device is mapped to. What that commit forgot to introduce was a check for overlaps. And yes, this is technically an O(n^2) algorithm, as virDomainMemoryDefValidate() is called over each memory device and after this, virDomainMemoryDefValidate() also iterates over each memory device. But given there's usually only a handful of such devices, and this runs only when parsing domain XML I guess code readability wins over some less obvious solution. Resolves: https://issues.redhat.com/browse/RHEL-4452 Signed-off-by: Michal Privoznik Reviewed-by: Ján Tomko --- src/conf/domain_validate.c | 47 +++++++++++++++++ ...rtio-mem-overlap-address.x86_64-latest.err | 1 + ...ory-hotplug-virtio-mem-overlap-address.xml | 50 +++++++++++++++++++ tests/qemuxml2argvtest.c | 1 + 4 files changed, 99 insertions(+) create mode 100644 tests/qemuxml2argvdata/memory-hotplug-virtio-mem-overlap-address.x86_64-latest.err create mode 100644 tests/qemuxml2argvdata/memory-hotplug-virtio-mem-overlap-address.xml diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c index d14559cd73..6962fe76bf 100644 --- a/src/conf/domain_validate.c +++ b/src/conf/domain_validate.c @@ -2223,6 +2223,9 @@ virDomainMemoryDefValidate(const virDomainMemoryDef *mem, { const long pagesize = virGetSystemPageSize(); unsigned long long thpSize; + unsigned long long thisStart = 0; + unsigned long long thisEnd = 0; + size_t i; /* Guest NUMA nodes are continuous and indexed from zero. */ if (mem->targetNode != -1) { @@ -2304,6 +2307,7 @@ virDomainMemoryDefValidate(const virDomainMemoryDef *mem, pagesize); return -1; } + thisStart = mem->target.virtio_pmem.address; break; case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: @@ -2347,6 +2351,7 @@ virDomainMemoryDefValidate(const virDomainMemoryDef *mem, _("memory device address must be aligned to blocksize")); return -1; } + thisStart = mem->target.virtio_mem.address; break; case VIR_DOMAIN_MEMORY_MODEL_DIMM: @@ -2368,6 +2373,48 @@ virDomainMemoryDefValidate(const virDomainMemoryDef *mem, return -1; } + if (thisStart == 0) { + return 0; + } + + /* thisStart and thisEnd are in bytes, mem->size in kibibytes */ + thisEnd = thisStart + mem->size * 1024; + + for (i = 0; i < def->nmems; i++) { + const virDomainMemoryDef *other = def->mems[i]; + unsigned long long otherStart = 0; + + if (other == mem) + continue; + + switch (other->model) { + case VIR_DOMAIN_MEMORY_MODEL_NONE: + case VIR_DOMAIN_MEMORY_MODEL_DIMM: + case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_LAST: + continue; + break; + + case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: + otherStart = other->target.virtio_pmem.address; + break; + case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: + otherStart = other->target.virtio_mem.address; + break; + } + + if (otherStart == 0) + continue; + + if (thisStart <= otherStart && thisEnd > otherStart) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("memory device address [0x%1$llx:0x%2$llx] overlaps with other memory device (0x%3$llx)"), + thisStart, thisEnd, otherStart); + return -1; + } + } + return 0; } diff --git a/tests/qemuxml2argvdata/memory-hotplug-virtio-mem-overlap-address.x86_64-latest.err b/tests/qemuxml2argvdata/memory-hotplug-virtio-mem-overlap-address.x86_64-latest.err new file mode 100644 index 0000000000..36d5b8a6e6 --- /dev/null +++ b/tests/qemuxml2argvdata/memory-hotplug-virtio-mem-overlap-address.x86_64-latest.err @@ -0,0 +1 @@ +unsupported configuration: memory device address [0x140000000:0x180000000] overlaps with other memory device (0x170000000) diff --git a/tests/qemuxml2argvdata/memory-hotplug-virtio-mem-overlap-address.xml b/tests/qemuxml2argvdata/memory-hotplug-virtio-mem-overlap-address.xml new file mode 100644 index 0000000000..65999ccd99 --- /dev/null +++ b/tests/qemuxml2argvdata/memory-hotplug-virtio-mem-overlap-address.xml @@ -0,0 +1,50 @@ + + QEMUGuest1 + c7a5fdbd-edaf-9455-926a-d65c16db1809 + 1099511627776 + 8388608 + 8388608 + 2 + + hvm + + + + qemu64 + + + + + + + destroy + restart + destroy + + /usr/bin/qemu-system-x86_64 + + + 1048576 + 0 + 2048 + 524288 +
+ +
+ + + + 1-3 + 2048 + + + 2097152 + 0 + 2048 + 1048576 +
+ +
+ + + diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 2195d8efa3..a454dcb205 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -2114,6 +2114,7 @@ mymain(void) DO_TEST_CAPS_LATEST("memory-hotplug-virtio-pmem"); DO_TEST_CAPS_LATEST("memory-hotplug-virtio-mem"); DO_TEST_CAPS_LATEST("memory-hotplug-multiple"); + DO_TEST_CAPS_LATEST_PARSE_ERROR("memory-hotplug-virtio-mem-overlap-address"); DO_TEST_CAPS_ARCH_LATEST("machine-aeskeywrap-on-caps", "s390x"); DO_TEST_CAPS_ARCH_LATEST("machine-aeskeywrap-on-cap", "s390x");