[libvirt] [PATCH 2/2] qemu: domain: Prevent overflows in memory alignment code
Guido Günther
agx at sigxcpu.org
Sun Jan 3 17:26:56 UTC 2016
Hi,
On Tue, Dec 01, 2015 at 03:11:05PM +0100, Peter Krempa wrote:
> Since libvirt for dubious historical reasons stores memory size as
> kibibytes, it's possible that the alignments done in the qemu code
> overflow the the maximum representable size in bytes. The XML parser
> code handles them in bytes in some stages. Prevent this by doing
> overflow checks when alinging the size and add a test case.
It seems this broke the build on i386:
https://buildd.debian.org/status/fetch.php?pkg=libvirt&arch=i386&ver=1.3.0-1&stamp=1450436203
(search for memory-align-fail)
I did not investigate further yet though.
Cheers,
-- Guido
>
> Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1260576
> ---
> src/qemu/qemu_domain.c | 27 ++++++++++++++++++++
> .../qemuxml2argv-memory-align-fail.xml | 29 ++++++++++++++++++++++
> tests/qemuxml2argvtest.c | 1 +
> 3 files changed, 57 insertions(+)
> create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-memory-align-fail.xml
>
> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
> index ed21245..a872598 100644
> --- a/src/qemu/qemu_domain.c
> +++ b/src/qemu/qemu_domain.c
> @@ -3521,6 +3521,8 @@ qemuDomainGetMemoryModuleSizeAlignment(const virDomainDef *def,
> int
> qemuDomainAlignMemorySizes(virDomainDefPtr def)
> {
> + unsigned long long maxmemkb = virMemoryMaxValue(false) >> 10;
> + unsigned long long maxmemcapped = virMemoryMaxValue(true) >> 10;
> unsigned long long initialmem = 0;
> unsigned long long mem;
> unsigned long long align = qemuDomainGetMemorySizeAlignment(def);
> @@ -3531,6 +3533,13 @@ qemuDomainAlignMemorySizes(virDomainDefPtr def)
> for (i = 0; i < ncells; i++) {
> mem = VIR_ROUND_UP(virDomainNumaGetNodeMemorySize(def->numa, i), align);
> initialmem += mem;
> +
> + if (mem > maxmemkb) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> + _("memory size of NUMA node '%zu' overflowed after "
> + "alignment"), i);
> + return -1;
> + }
> virDomainNumaSetNodeMemorySize(def->numa, i, mem);
> }
>
> @@ -3539,14 +3548,32 @@ qemuDomainAlignMemorySizes(virDomainDefPtr def)
> if (initialmem == 0)
> initialmem = VIR_ROUND_UP(virDomainDefGetMemoryInitial(def), align);
>
> + if (initialmem > maxmemcapped) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> + _("initial memory size overflowed after alignment"));
> + return -1;
> + }
> +
> virDomainDefSetMemoryInitial(def, initialmem);
>
> def->mem.max_memory = VIR_ROUND_UP(def->mem.max_memory, align);
> + if (def->mem.max_memory > maxmemkb) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> + _("maximum memory size overflowed after alignment"));
> + return -1;
> + }
>
> /* Align memory module sizes */
> for (i = 0; i < def->nmems; i++) {
> align = qemuDomainGetMemoryModuleSizeAlignment(def, def->mems[i]);
> def->mems[i]->size = VIR_ROUND_UP(def->mems[i]->size, align);
> +
> + if (def->mems[i]->size > maxmemkb) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> + _("size of memory module '%zu' overflowed after "
> + "alignment"), i);
> + return -1;
> + }
> }
>
> return 0;
> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-memory-align-fail.xml b/tests/qemuxml2argvdata/qemuxml2argv-memory-align-fail.xml
> new file mode 100644
> index 0000000..bdbdc5b
> --- /dev/null
> +++ b/tests/qemuxml2argvdata/qemuxml2argv-memory-align-fail.xml
> @@ -0,0 +1,29 @@
> +<domain type='qemu'>
> + <name>QEMUGuest1</name>
> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
> + <maxMemory slots='16' unit='KiB'>9007199254740991</maxMemory>
> + <memory unit='KiB'>9007199254740991</memory>
> + <currentMemory unit='KiB'>9007199254740991</currentMemory>
> + <vcpu placement='static' cpuset='0-1'>2</vcpu>
> + <os>
> + <type arch='i686' machine='pc'>hvm</type>
> + <boot dev='hd'/>
> + </os>
> + <cpu>
> + <topology sockets='2' cores='1' threads='1'/>
> + <numa>
> + <cell id='0' cpus='0-1' memory='9007199254740991' unit='KiB'/>
> + </numa>
> + </cpu>
> + <clock offset='utc'/>
> + <on_poweroff>destroy</on_poweroff>
> + <on_reboot>restart</on_reboot>
> + <on_crash>destroy</on_crash>
> + <devices>
> + <emulator>/usr/bin/qemu</emulator>
> + <controller type='ide' index='0'/>
> + <controller type='usb' index='0'/>
> + <controller type='pci' index='0' model='pci-root'/>
> + <memballoon model='virtio'/>
> + </devices>
> +</domain>
> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
> index 6513651..37f806e 100644
> --- a/tests/qemuxml2argvtest.c
> +++ b/tests/qemuxml2argvtest.c
> @@ -1660,6 +1660,7 @@ mymain(void)
> DO_TEST_PARSE_ERROR("shmem-msi-only", NONE);
> DO_TEST("cpu-host-passthrough-features", QEMU_CAPS_KVM, QEMU_CAPS_CPU_HOST);
>
> + DO_TEST_FAILURE("memory-align-fail", NONE);
> DO_TEST_FAILURE("memory-hotplug-nonuma", QEMU_CAPS_DEVICE_PC_DIMM);
> DO_TEST_FAILURE("memory-hotplug", NONE);
> DO_TEST("memory-hotplug", QEMU_CAPS_DEVICE_PC_DIMM, QEMU_CAPS_NUMA);
> --
> 2.6.2
>
> --
> libvir-list mailing list
> libvir-list at redhat.com
> https://www.redhat.com/mailman/listinfo/libvir-list
>
More information about the libvir-list
mailing list