mirror of https://gitee.com/openkylin/libvirt.git
qemu: domain: Prevent overflows in memory alignment code
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
This commit is contained in:
parent
e5fac00946
commit
645881139b
|
@ -3521,6 +3521,8 @@ qemuDomainGetMemoryModuleSizeAlignment(const virDomainDef *def,
|
||||||
int
|
int
|
||||||
qemuDomainAlignMemorySizes(virDomainDefPtr def)
|
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 initialmem = 0;
|
||||||
unsigned long long mem;
|
unsigned long long mem;
|
||||||
unsigned long long align = qemuDomainGetMemorySizeAlignment(def);
|
unsigned long long align = qemuDomainGetMemorySizeAlignment(def);
|
||||||
|
@ -3531,6 +3533,13 @@ qemuDomainAlignMemorySizes(virDomainDefPtr def)
|
||||||
for (i = 0; i < ncells; i++) {
|
for (i = 0; i < ncells; i++) {
|
||||||
mem = VIR_ROUND_UP(virDomainNumaGetNodeMemorySize(def->numa, i), align);
|
mem = VIR_ROUND_UP(virDomainNumaGetNodeMemorySize(def->numa, i), align);
|
||||||
initialmem += mem;
|
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);
|
virDomainNumaSetNodeMemorySize(def->numa, i, mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3539,14 +3548,32 @@ qemuDomainAlignMemorySizes(virDomainDefPtr def)
|
||||||
if (initialmem == 0)
|
if (initialmem == 0)
|
||||||
initialmem = VIR_ROUND_UP(virDomainDefGetMemoryInitial(def), align);
|
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);
|
virDomainDefSetMemoryInitial(def, initialmem);
|
||||||
|
|
||||||
def->mem.max_memory = VIR_ROUND_UP(def->mem.max_memory, align);
|
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 */
|
/* Align memory module sizes */
|
||||||
for (i = 0; i < def->nmems; i++) {
|
for (i = 0; i < def->nmems; i++) {
|
||||||
align = qemuDomainGetMemoryModuleSizeAlignment(def, def->mems[i]);
|
align = qemuDomainGetMemoryModuleSizeAlignment(def, def->mems[i]);
|
||||||
def->mems[i]->size = VIR_ROUND_UP(def->mems[i]->size, align);
|
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;
|
return 0;
|
||||||
|
|
|
@ -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>
|
|
@ -1660,6 +1660,7 @@ mymain(void)
|
||||||
DO_TEST_PARSE_ERROR("shmem-msi-only", NONE);
|
DO_TEST_PARSE_ERROR("shmem-msi-only", NONE);
|
||||||
DO_TEST("cpu-host-passthrough-features", QEMU_CAPS_KVM, QEMU_CAPS_CPU_HOST);
|
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-nonuma", QEMU_CAPS_DEVICE_PC_DIMM);
|
||||||
DO_TEST_FAILURE("memory-hotplug", NONE);
|
DO_TEST_FAILURE("memory-hotplug", NONE);
|
||||||
DO_TEST("memory-hotplug", QEMU_CAPS_DEVICE_PC_DIMM, QEMU_CAPS_NUMA);
|
DO_TEST("memory-hotplug", QEMU_CAPS_DEVICE_PC_DIMM, QEMU_CAPS_NUMA);
|
||||||
|
|
Loading…
Reference in New Issue