From 3511c12244beb289dd44503739d65b0e823685cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1n=20Tomko?= Date: Tue, 5 May 2015 17:58:49 +0200 Subject: [PATCH] reject out of range memory in SetMemory APIs The APIs take the memory value in KiB and we store it in KiB internally, but we cannot parse the whole ULONG_MAX range on 64-bit systems, because virDomainParseScaledValue needs to fit the value in bytes in an unsigned long long. https://bugzilla.redhat.com/show_bug.cgi?id=1176739 --- src/conf/domain_conf.c | 7 +------ src/libvirt-domain.c | 18 ++++++++++++++++++ src/libvirt_private.syms | 1 + src/util/virutil.c | 20 ++++++++++++++++++++ src/util/virutil.h | 1 + 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 68cac1de01..d150582897 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -7098,12 +7098,7 @@ virDomainParseMemory(const char *xpath, int ret = -1; unsigned long long bytes, max; - /* On 32-bit machines, our bound is 0xffffffff * KiB. On 64-bit - * machines, our bound is off_t (2^63). */ - if (capped && sizeof(unsigned long) < sizeof(long long)) - max = 1024ull * ULONG_MAX; - else - max = LLONG_MAX; + max = virMemoryMaxValue(capped); ret = virDomainParseScaledValue(xpath, units_xpath, ctxt, &bytes, 1024, max, required); diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index 7dcd40e420..d4677581b4 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -1850,6 +1850,12 @@ virDomainSetMaxMemory(virDomainPtr domain, unsigned long memory) virCheckReadOnlyGoto(conn->flags, error); virCheckNonZeroArgGoto(memory, error); + if (virMemoryMaxValue(true) / 1024 <= memory) { + virReportError(VIR_ERR_OVERFLOW, _("input too large: %lu"), + memory); + goto error; + } + if (conn->driver->domainSetMaxMemory) { int ret; ret = conn->driver->domainSetMaxMemory(domain, memory); @@ -1896,6 +1902,12 @@ virDomainSetMemory(virDomainPtr domain, unsigned long memory) virCheckReadOnlyGoto(conn->flags, error); virCheckNonZeroArgGoto(memory, error); + if (virMemoryMaxValue(true) / 1024 <= memory) { + virReportError(VIR_ERR_OVERFLOW, _("input too large: %lu"), + memory); + goto error; + } + if (conn->driver->domainSetMemory) { int ret; ret = conn->driver->domainSetMemory(domain, memory); @@ -1953,6 +1965,12 @@ virDomainSetMemoryFlags(virDomainPtr domain, unsigned long memory, virCheckReadOnlyGoto(conn->flags, error); virCheckNonZeroArgGoto(memory, error); + if (virMemoryMaxValue(true) / 1024 <= memory) { + virReportError(VIR_ERR_OVERFLOW, _("input too large: %lu"), + memory); + goto error; + } + if (conn->driver->domainSetMemoryFlags) { int ret; ret = conn->driver->domainSetMemoryFlags(domain, memory, flags); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 67a7e21a20..6e33f84e49 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2334,6 +2334,7 @@ virIsSUID; virManageVport; virMemoryLimitIsSet; virMemoryLimitTruncate; +virMemoryMaxValue; virParseNumber; virParseOwnershipIds; virParseVersionString; diff --git a/src/util/virutil.c b/src/util/virutil.c index 042651703f..638d6e2166 100644 --- a/src/util/virutil.c +++ b/src/util/virutil.c @@ -2598,3 +2598,23 @@ virMemoryLimitIsSet(unsigned long long value) { return value < VIR_DOMAIN_MEMORY_PARAM_UNLIMITED; } + + +/** + * virMemoryMaxValue + * + * @ulong: whether the value must fit into unsigned long + * (long long is assumed otherwise) + * + * Returns the maximum possible memory value in bytes. + */ +unsigned long long +virMemoryMaxValue(bool ulong) +{ + /* On 32-bit machines, our bound is 0xffffffff * KiB. On 64-bit + * machines, our bound is off_t (2^63). */ + if (ulong && sizeof(unsigned long) < sizeof(long long)) + return 1024ull * ULONG_MAX; + else + return LLONG_MAX; +} diff --git a/src/util/virutil.h b/src/util/virutil.h index 55a3bd6221..c78b357b43 100644 --- a/src/util/virutil.h +++ b/src/util/virutil.h @@ -245,5 +245,6 @@ long virGetSystemPageSizeKB(void); unsigned long long virMemoryLimitTruncate(unsigned long long value); bool virMemoryLimitIsSet(unsigned long long value); +unsigned long long virMemoryMaxValue(bool ulong); #endif /* __VIR_UTIL_H__ */