]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
parse-util: really refuse parsing negative values as positive ones, even on x86-32
authorLennart Poettering <lennart@poettering.net>
Tue, 10 Nov 2015 16:27:16 +0000 (17:27 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 10 Nov 2015 16:36:52 +0000 (17:36 +0100)
strtoull() doesn't make it particularly easy to detect passed-in
negative numbers, as it silently converts them to positive ones without
generating any error. Since we are not interested in negative values we
should hence explicitly filter them out by looking at the string
directly and returning ERANGE if we see a leading "-".

Fixes: #1829
src/basic/parse-util.c

index b6358c459a1c2668ec50792b343f948446b5787d..151067e91604d3a15d22184850213363af7a157f 100644 (file)
@@ -67,11 +67,14 @@ int parse_mode(const char *s, mode_t *ret) {
         assert(s);
         assert(ret);
 
+        s += strspn(s, WHITESPACE);
+        if (s[0] == '-')
+                return -ERANGE;
+
         errno = 0;
         l = strtol(s, &x, 8);
         if (errno != 0)
                 return -errno;
-
         if (!x || x == s || *x)
                 return -EINVAL;
         if (l < 0 || l  > 07777)
@@ -162,15 +165,15 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) {
                 unsigned i;
 
                 p += strspn(p, WHITESPACE);
-                if (*p == '-')
-                        return -ERANGE;
 
                 errno = 0;
                 l = strtoull(p, &e, 10);
-                if (errno > 0)
+                if (errno != 0)
                         return -errno;
                 if (e == p)
                         return -EINVAL;
+                if (*p == '-')
+                        return -ERANGE;
 
                 if (*e == '.') {
                         e++;
@@ -181,7 +184,7 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) {
                                 char *e2;
 
                                 l2 = strtoull(e, &e2, 10);
-                                if (errno > 0)
+                                if (errno != 0)
                                         return -errno;
 
                                 /* Ignore failure. E.g. 10.M is valid */
@@ -307,12 +310,24 @@ int safe_atou(const char *s, unsigned *ret_u) {
         assert(s);
         assert(ret_u);
 
-        errno = 0;
-        l = strtoul(s, &x, 0);
+        /* strtoul() is happy to parse negative values, and silently
+         * converts them to unsigned values without generating an
+         * error. We want a clean error, hence let's look for the "-"
+         * prefix on our own, and generate an error. But let's do so
+         * only after strtoul() validated that the string is clean
+         * otherwise, so that we return EINVAL preferably over
+         * ERANGE. */
 
-        if (!x || x == s || *x || errno)
-                return errno > 0 ? -errno : -EINVAL;
+        s += strspn(s, WHITESPACE);
 
+        errno = 0;
+        l = strtoul(s, &x, 0);
+        if (errno != 0)
+                return -errno;
+        if (!x || x == s || *x)
+                return -EINVAL;
+        if (s[0] == '-')
+                return -ERANGE;
         if ((unsigned long) (unsigned) l != l)
                 return -ERANGE;
 
@@ -329,10 +344,10 @@ int safe_atoi(const char *s, int *ret_i) {
 
         errno = 0;
         l = strtol(s, &x, 0);
-
-        if (!x || x == s || *x || errno)
-                return errno > 0 ? -errno : -EINVAL;
-
+        if (errno != 0)
+                return -errno;
+        if (!x || x == s || *x)
+                return -EINVAL;
         if ((long) (int) l != l)
                 return -ERANGE;
 
@@ -347,11 +362,16 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) {
         assert(s);
         assert(ret_llu);
 
+        s += strspn(s, WHITESPACE);
+
         errno = 0;
         l = strtoull(s, &x, 0);
-
-        if (!x || x == s || *x || errno)
-                return errno ? -errno : -EINVAL;
+        if (errno != 0)
+                return -errno;
+        if (!x || x == s || *x)
+                return -EINVAL;
+        if (*s == '-')
+                return -ERANGE;
 
         *ret_llu = l;
         return 0;
@@ -366,9 +386,10 @@ int safe_atolli(const char *s, long long int *ret_lli) {
 
         errno = 0;
         l = strtoll(s, &x, 0);
-
-        if (!x || x == s || *x || errno)
-                return errno ? -errno : -EINVAL;
+        if (errno != 0)
+                return -errno;
+        if (!x || x == s || *x)
+                return -EINVAL;
 
         *ret_lli = l;
         return 0;
@@ -381,12 +402,16 @@ int safe_atou8(const char *s, uint8_t *ret) {
         assert(s);
         assert(ret);
 
+        s += strspn(s, WHITESPACE);
+
         errno = 0;
         l = strtoul(s, &x, 0);
-
-        if (!x || x == s || *x || errno)
-                return errno > 0 ? -errno : -EINVAL;
-
+        if (errno != 0)
+                return -errno;
+        if (!x || x == s || *x)
+                return -EINVAL;
+        if (s[0] == '-')
+                return -ERANGE;
         if ((unsigned long) (uint8_t) l != l)
                 return -ERANGE;
 
@@ -401,12 +426,16 @@ int safe_atou16(const char *s, uint16_t *ret) {
         assert(s);
         assert(ret);
 
+        s += strspn(s, WHITESPACE);
+
         errno = 0;
         l = strtoul(s, &x, 0);
-
-        if (!x || x == s || *x || errno)
-                return errno > 0 ? -errno : -EINVAL;
-
+        if (errno != 0)
+                return -errno;
+        if (!x || x == s || *x)
+                return -EINVAL;
+        if (s[0] == '-')
+                return -ERANGE;
         if ((unsigned long) (uint16_t) l != l)
                 return -ERANGE;
 
@@ -423,10 +452,10 @@ int safe_atoi16(const char *s, int16_t *ret) {
 
         errno = 0;
         l = strtol(s, &x, 0);
-
-        if (!x || x == s || *x || errno)
-                return errno > 0 ? -errno : -EINVAL;
-
+        if (errno != 0)
+                return -errno;
+        if (!x || x == s || *x)
+                return -EINVAL;
         if ((long) (int16_t) l != l)
                 return -ERANGE;
 
@@ -448,10 +477,13 @@ int safe_atod(const char *s, double *ret_d) {
 
         errno = 0;
         d = strtod_l(s, &x, loc);
-
-        if (!x || x == s || *x || errno) {
+        if (errno != 0) {
                 freelocale(loc);
-                return errno ? -errno : -EINVAL;
+                return -errno;
+        }
+        if (!x || x == s || *x) {
+                freelocale(loc);
+                return -EINVAL;
         }
 
         freelocale(loc);