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
This commit is contained in:
Ján Tomko 2015-05-05 17:58:49 +02:00
parent 07df9e1f74
commit 3511c12244
5 changed files with 41 additions and 6 deletions

View File

@ -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);

View File

@ -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);

View File

@ -2334,6 +2334,7 @@ virIsSUID;
virManageVport;
virMemoryLimitIsSet;
virMemoryLimitTruncate;
virMemoryMaxValue;
virParseNumber;
virParseOwnershipIds;
virParseVersionString;

View File

@ -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;
}

View File

@ -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__ */