diff --git a/src/Makefile.am b/src/Makefile.am index e2d6164..ae0b0a8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -67,7 +67,7 @@ libvirt_la_SOURCES = $(CLIENT_SOURCES) $(SERVER_SOURCES) bin_PROGRAMS = virsh -virsh_SOURCES = virsh.c console.c console.h +virsh_SOURCES = virsh.c console.c console.h xstrtol.c xstrtol.h virsh_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDFLAGS) virsh_DEPENDENCIES = $(DEPS) virsh_LDADD = $(LDADDS) $(VIRSH_LIBS) diff --git a/src/virsh.c b/src/virsh.c index 5327a28..1f15ee4 100644 --- a/src/virsh.c +++ b/src/virsh.c @@ -44,6 +44,7 @@ #include "config.h" #include "internal.h" #include "console.h" +#include "xstrtol.h" static char *progname; @@ -2961,10 +2962,8 @@ cmdVNCDisplay(vshControl * ctl, vshCmd * cmd) (obj->stringval == NULL) || (obj->stringval[0] == 0)) { goto cleanup; } - port = strtol((const char *)obj->stringval, NULL, 10); - if (port == -1) { + if (xstrtol_i((const char *)obj->stringval, NULL, 10, &port) || port < 0) goto cleanup; - } xmlXPathFreeObject(obj); obj = xmlXPathEval(BAD_CAST "string(/domain/devices/graphics[@type='vnc']/@listen)", ctxt); @@ -3997,7 +3996,7 @@ vshCommandOptDomainBy(vshControl * ctl, vshCmd * cmd, const char *optname, char **name, int flag) { virDomainPtr dom = NULL; - char *n, *end = NULL; + char *n; int id; if (!(n = vshCommandOptString(cmd, optname, NULL))) { @@ -4013,8 +4012,7 @@ vshCommandOptDomainBy(vshControl * ctl, vshCmd * cmd, const char *optname, /* try it by ID */ if (flag & VSH_BYID) { - id = (int) strtol(n, &end, 10); - if (id >= 0 && end && *end == '\0') { + if (xstrtol_i(n, NULL, 10, &id) == 0 && id >= 0) { vshDebug(ctl, 5, "%s: <%s> seems like domain ID\n", cmd->def->name, optname); dom = virDomainLookupByID(ctl->conn, id); diff --git a/src/xstrtol.c b/src/xstrtol.c new file mode 100644 index 0000000..1f0a8ec --- /dev/null +++ b/src/xstrtol.c @@ -0,0 +1,33 @@ +/* + * xstrtol.c: strtol wrappers + * + * Copyright (C) 2007 Red Hat, Inc. + */ +#include +#include +#include + +#include "xstrtol.h" + +/* Like strtol, but produce an "int" result, and check more carefully. + Return 0 upon success; return -1 to indicate failure. + When END_PTR is NULL, the byte after the final valid digit must be NUL. + Otherwise, it's like strtol and lets the caller check any suffix for + validity. This function is careful to return -1 when the string S + represents a number that is not representable as an "int". */ +int xstrtol_i(char const *s, char **end_ptr, int base, int *result) +{ + long int val; + char *p; + int err; + + errno = 0; + val = strtol(s, &p, base); + err = (errno || (!end_ptr && *p) || p == s || (int) val != val); + if (end_ptr) + *end_ptr = p; + if (err) + return -1; + *result = val; + return 0; +} diff --git a/src/xstrtol.h b/src/xstrtol.h new file mode 100644 index 0000000..2bfb812 --- /dev/null +++ b/src/xstrtol.h @@ -0,0 +1,7 @@ +/* + * xstrtol.h: strtol wrappers + * + * Copyright (C) 2007 Red Hat, Inc. + */ + +int xstrtol_i(char const *s, char **end_ptr, int base, int *result); diff --git a/tests/Makefile.am b/tests/Makefile.am index 80692e0..8a472f8 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -38,13 +38,19 @@ noinst_PROGRAMS = xmlrpctest xml2sexprtest sexpr2xmltest virshtest conftest \ nodeinfotest TESTS = xml2sexprtest sexpr2xmltest virshtest test_conf.sh xmconfigtest \ - xencapstest qemuxml2argvtest qemuxml2xmltest nodeinfotest + xencapstest qemuxml2argvtest qemuxml2xmltest nodeinfotest \ + int-overflow if ENABLE_XEN_TESTS TESTS += reconnect endif +TESTS_ENVIRONMENT = \ + abs_top_builddir='$(abs_top_builddir)' \ + abs_top_srcdir='$(abs_top_srcdir)' \ + $(VG) + valgrind: - $(MAKE) check TESTS_ENVIRONMENT="valgrind --quiet --leak-check=full" + $(MAKE) check VG="valgrind --quiet --leak-check=full" # Note: xmlrpc.[c|h] is not in libvirt yet xmlrpctest_SOURCES = \ diff --git a/tests/int-overflow b/tests/int-overflow new file mode 100755 index 0000000..97a1ab2 --- /dev/null +++ b/tests/int-overflow @@ -0,0 +1,22 @@ +#!/bin/bash +# Ensure that an invalid domain ID isn't interpreted as a valid one. +# Before, an ID of 2^32+2 would be treated just like an ID of 2. + +# Boilerplate code to set up a test directory, cd into it, +# and to ensure we remove it upon completion. +this_test_() { echo "./$0" | sed 's,.*/,,'; } +t_=$(this_test_)-$$ +init_cwd_=$(pwd) +trap 'st=$?; d='"$t_"'; + cd '"$init_cwd_"' && chmod -R u+rwx "$d" && rm -rf "$d" && exit $st' 0 +trap '(exit $?); exit $?' 1 2 13 15 +mkdir "$t_" || fail=1 +cd "$t_" || fail=1 + +echo "error: failed to get domain '4294967298'" > exp || fail=1 +echo domname 4294967298 | $abs_top_builddir/src/virsh --quiet \ + --connect test://$abs_top_srcdir/docs/testnode.xml \ + > /dev/null 2> err || fail=1 +diff -u err exp || fail=1 + +exit $fail -- 1.5.3.5.602.g53d1