]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/libvirt.git/commitdiff
qemu: domain: Prevent overflows in memory alignment code
authorPeter Krempa <pkrempa@redhat.com>
Tue, 1 Dec 2015 13:08:37 +0000 (14:08 +0100)
committerPeter Krempa <pkrempa@redhat.com>
Fri, 4 Dec 2015 14:21:20 +0000 (15:21 +0100)
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.

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1260576

src/qemu/qemu_domain.c
tests/qemuxml2argvdata/qemuxml2argv-memory-align-fail.xml [new file with mode: 0644]
tests/qemuxml2argvtest.c

index ed212456ae107c3d3d6046f91a9f3bba59334f27..a872598965997f7803941b1f3bbff7a22dc175ae 100644 (file)
@@ -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 (file)
index 0000000..bdbdc5b
--- /dev/null
@@ -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>
index 6513651853061c466ad108d32102727246686b34..37f806edd3c0f71dce021fc58af4dbe363f5f667 100644 (file)
@@ -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);