]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
taskset: fix cpuset list parser
authorKarel Zak <kzak@redhat.com>
Wed, 20 Mar 2019 12:12:25 +0000 (13:12 +0100)
committerKarel Zak <kzak@redhat.com>
Wed, 20 Mar 2019 12:12:25 +0000 (13:12 +0100)
taskset hangs when executed with badly formatted cpuset list, for
example:

 $ taskset -c 0--1 true

The current cpuset list parser is pretty weak as based on scanf()
without strings verification ("-1" as input for "%u" returns
unexpected number). It seems faster and better to use strtoul() and
isdigit().

Addresses: https://github.com/karelzak/util-linux/issues/77
Signed-off-by: Karel Zak <kzak@redhat.com>
lib/cpuset.c

index 011b6882b82b785a8382ed2146d2cc8a5559b465..2847db8530324925972ba96a4bf3eb049ed6c443 100644 (file)
@@ -260,6 +260,19 @@ int cpumask_parse(const char *str, cpu_set_t *set, size_t setsize)
        return 0;
 }
 
+static int nextnumber(const char *str, char **end, unsigned int *result)
+{
+       errno = 0;
+       if (str == NULL || *str == '\0' || !isdigit(*str))
+               return -EINVAL;
+       *result = (unsigned int) strtoul(str, end, 10);
+       if (errno)
+               return -errno;
+       if (str == *end)
+               return -EINVAL;
+       return 0;
+}
+
 /*
  * Parses string with list of CPU ranges.
  * Returns 0 on success.
@@ -272,7 +285,7 @@ int cpulist_parse(const char *str, cpu_set_t *set, size_t setsize, int fail)
 {
        size_t max = cpuset_nbits(setsize);
        const char *p, *q;
-       int r = 0;
+       char *end = NULL;
 
        q = str;
        CPU_ZERO_S(setsize, set);
@@ -282,21 +295,24 @@ int cpulist_parse(const char *str, cpu_set_t *set, size_t setsize, int fail)
                unsigned int b; /* end of range */
                unsigned int s; /* stride */
                const char *c1, *c2;
-               char c;
 
-               if ((r = sscanf(p, "%u%c", &a, &c)) < 1)
+               if (nextnumber(p, &end, &a) != 0)
                        return 1;
                b = a;
                s = 1;
+               p = end;
 
                c1 = nexttoken(p, '-');
                c2 = nexttoken(p, ',');
+
                if (c1 != NULL && (c2 == NULL || c1 < c2)) {
-                       if ((r = sscanf(c1, "%u%c", &b, &c)) < 1)
+                       if (nextnumber(c1, &end, &b) != 0)
                                return 1;
-                       c1 = nexttoken(c1, ':');
+
+                       c1 = end && *end ? nexttoken(end, ':') : NULL;
+
                        if (c1 != NULL && (c2 == NULL || c1 < c2)) {
-                               if ((r = sscanf(c1, "%u%c", &s, &c)) < 1)
+                               if (nextnumber(c1, &end, &s) != 0)
                                        return 1;
                                if (s == 0)
                                        return 1;
@@ -313,7 +329,7 @@ int cpulist_parse(const char *str, cpu_set_t *set, size_t setsize, int fail)
                }
        }
 
-       if (r == 2)
+       if (end && *end)
                return 1;
        return 0;
 }
@@ -390,7 +406,7 @@ int main(int argc, char *argv[])
 
 usage_err:
        fprintf(stderr,
-               "usage: %s [--ncpus <num>] --mask <mask> | --range <list>",
+               "usage: %s [--ncpus <num>] --mask <mask> | --range <list>\n",
                program_invocation_short_name);
        exit(EXIT_FAILURE);
 }