libvirt/tools/virsh-completer-host.c
Michal Privoznik d5f81479a6 virsh: Fix integer overflow in allocpages
I've came across an aarch64 system which supports hugepages up to
16GiB of size. However, I was unable to allocate them using
virsh allocpages. This is because cmdAllocpages() uses
vshCommandOptScaledInt(), which scales passed value into bytes,
but since the virNodeAllocPages() expects size in KiB the
variable holding bytes is then divided by 1024. However, the
limit for the biggest value passed to vshCommandOptScaledInt() is
UINT_MAX which is now obviously wrong, as it needs to be UINT_MAX
* 1024.

The same bug is in completer. But here, let's use ULLONG_MAX so
that we don't have to care about it anymore.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2022-03-31 14:33:40 +02:00

183 lines
5.0 KiB
C

/*
* virsh-completer-host.c: virsh completer callbacks related to host
*
* Copyright (C) 2019 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "virsh-completer-host.h"
#include "viralloc.h"
#include "virsh.h"
#include "virstring.h"
#include "virxml.h"
#include "virutil.h"
#include "virsh-host.h"
static char *
virshPagesizeNodeToString(xmlNodePtr node)
{
g_autofree char *pagesize = NULL;
g_autofree char *unit = NULL;
unsigned long long byteval = 0;
const char *suffix = NULL;
double size = 0;
char *ret;
pagesize = virXMLPropString(node, "size");
unit = virXMLPropString(node, "unit");
if (virStrToLong_ull(pagesize, NULL, 10, &byteval) < 0)
return NULL;
if (virScaleInteger(&byteval, unit, 1024, ULLONG_MAX) < 0)
return NULL;
size = vshPrettyCapacity(byteval, &suffix);
ret = g_strdup_printf("%.0f%s", size, suffix);
return ret;
}
char **
virshAllocpagesPagesizeCompleter(vshControl *ctl,
const vshCmd *cmd G_GNUC_UNUSED,
unsigned int flags)
{
g_autoptr(xmlXPathContext) ctxt = NULL;
virshControl *priv = ctl->privData;
int npages = 0;
g_autofree xmlNodePtr *pages = NULL;
g_autoptr(xmlDoc) doc = NULL;
size_t i = 0;
const char *cellnum = NULL;
bool cellno = vshCommandOptBool(cmd, "cellno");
g_autofree char *path = NULL;
g_autofree char *cap_xml = NULL;
g_auto(GStrv) tmp = NULL;
virCheckFlags(0, NULL);
if (!priv->conn || virConnectIsAlive(priv->conn) <= 0)
return NULL;
if (!(cap_xml = virConnectGetCapabilities(priv->conn)))
return NULL;
if (!(doc = virXMLParseStringCtxt(cap_xml, _("capabilities"), &ctxt)))
return NULL;
if (cellno && vshCommandOptStringQuiet(ctl, cmd, "cellno", &cellnum) > 0) {
path = g_strdup_printf("/capabilities/host/topology/cells/cell[@id=\"%s\"]/pages",
cellnum);
} else {
path = g_strdup("/capabilities/host/cpu/pages");
}
npages = virXPathNodeSet(path, ctxt, &pages);
if (npages <= 0)
return NULL;
tmp = g_new0(char *, npages + 1);
for (i = 0; i < npages; i++) {
if (!(tmp[i] = virshPagesizeNodeToString(pages[i])))
return NULL;
}
return g_steal_pointer(&tmp);
}
char **
virshCellnoCompleter(vshControl *ctl,
const vshCmd *cmd G_GNUC_UNUSED,
unsigned int flags)
{
g_autoptr(xmlXPathContext) ctxt = NULL;
virshControl *priv = ctl->privData;
int ncells = 0;
g_autofree xmlNodePtr *cells = NULL;
g_autoptr(xmlDoc) doc = NULL;
size_t i = 0;
g_autofree char *cap_xml = NULL;
g_auto(GStrv) tmp = NULL;
virCheckFlags(0, NULL);
if (!priv->conn || virConnectIsAlive(priv->conn) <= 0)
return NULL;
if (!(cap_xml = virConnectGetCapabilities(priv->conn)))
return NULL;
if (!(doc = virXMLParseStringCtxt(cap_xml, _("capabilities"), &ctxt)))
return NULL;
ncells = virXPathNodeSet("/capabilities/host/topology/cells/cell", ctxt, &cells);
if (ncells <= 0)
return NULL;
tmp = g_new0(char *, ncells + 1);
for (i = 0; i < ncells; i++) {
if (!(tmp[i] = virXMLPropString(cells[i], "id")))
return NULL;
}
return g_steal_pointer(&tmp);
}
char **
virshNodeCpuCompleter(vshControl *ctl,
const vshCmd *cmd G_GNUC_UNUSED,
unsigned int flags)
{
virshControl *priv = ctl->privData;
g_auto(GStrv) tmp = NULL;
size_t i;
int cpunum;
size_t offset = 0;
unsigned int online;
g_autofree unsigned char *cpumap = NULL;
virCheckFlags(0, NULL);
if ((cpunum = virNodeGetCPUMap(priv->conn, &cpumap, &online, 0)) < 0)
return NULL;
tmp = g_new0(char *, online + 1);
for (i = 0; i < cpunum; i++) {
if (VIR_CPU_USED(cpumap, i) == 0)
continue;
tmp[offset++] = g_strdup_printf("%zu", i);
}
return g_steal_pointer(&tmp);
}
char **
virshNodeSuspendTargetCompleter(vshControl *ctl G_GNUC_UNUSED,
const vshCmd *cmd G_GNUC_UNUSED,
unsigned int flags)
{
virCheckFlags(0, NULL);
return virshEnumComplete(VIR_NODE_SUSPEND_TARGET_LAST,
virshNodeSuspendTargetTypeToString);
}