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 4cd36a1..821a43c 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -7116,12 +7116,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 7dcd40e..d467758 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 c8e6fb4..e77ca81 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2331,6 +2331,7 @@ virIsSUID;
virManageVport;
virMemoryLimitIsSet;
virMemoryLimitTruncate;
+virMemoryMaxValue;
virParseNumber;
virParseOwnershipIds;
virParseVersionString;
diff --git a/src/util/virutil.c b/src/util/virutil.c
index 0426517..e190308 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
+ * (unsigned 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 55a3bd6..c78b357 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__ */
--
2.0.5