]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
utils: fix range checking for get_u32/get_u64 et all
authorStephen Hemminger <stephen@networkplumber.org>
Fri, 12 Apr 2013 18:40:57 +0000 (11:40 -0700)
committerStephen Hemminger <stephen@networkplumber.org>
Fri, 12 Apr 2013 18:40:57 +0000 (11:40 -0700)
Be more careful about overflow in strtoXX routines.
Checks are based on documented interface on man pages.
Based on suggestion from "Mr Dash Four".

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
lib/utils.c

index 5bcdbcfb5234f31d58b1fa770aa6ecb21e369fbe..bcd6002333df85f773021883fb2bed705e3c5173 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <math.h>
 #include <unistd.h>
 #include <syslog.h>
 #include <fcntl.h>
@@ -38,9 +39,28 @@ int get_integer(int *val, const char *arg, int base)
 
        if (!arg || !*arg)
                return -1;
+
        res = strtol(arg, &ptr, base);
-       if (!ptr || ptr == arg || *ptr || res > INT_MAX || res < INT_MIN)
+
+       /* If there were no digits at all, strtol()  stores
+         * the original value of nptr in *endptr (and returns 0).
+        * In particular, if *nptr is not '\0' but **endptr is '\0' on return,
+        * the entire string is valid.
+        */
+       if (!ptr || ptr == arg || *ptr)
+               return -1;
+
+       /* If an underflow occurs, strtol() returns LONG_MIN.
+        * If an overflow occurs,  strtol() returns LONG_MAX.
+        * In both cases, errno is set to ERANGE.
+        */
+       if ((res == LONG_MAX || res == LONG_MIN) && errno == ERANGE)
                return -1;
+
+       /* Outside range of int */
+       if (res < INT_MIN || res > INT_MAX)
+               return -1;
+
        *val = res;
        return 0;
 }
@@ -87,9 +107,21 @@ int get_unsigned(unsigned *val, const char *arg, int base)
 
        if (!arg || !*arg)
                return -1;
+
        res = strtoul(arg, &ptr, base);
-       if (!ptr || ptr == arg || *ptr || res > UINT_MAX)
+
+       /* empty string or trailing non-digits */
+       if (!ptr || ptr == arg || *ptr)
+               return -1;
+
+       /* overflow */
+       if (res == ULONG_MAX && errno == ERANGE)
                return -1;
+
+       /* out side range of unsigned */
+       if (res > UINT_MAX)
+               return -1;
+
        *val = res;
        return 0;
 }
@@ -107,17 +139,32 @@ int get_time_rtt(unsigned *val, const char *arg, int *raw)
        unsigned long res;
        char *p;
 
-       if (strchr(arg,'.') != NULL) {
-               t = strtod(arg,&p);
+       if (strchr(arg, '.') != NULL) {
+               t = strtod(arg, &p);
                if (t < 0.0)
                        return -1;
-       }
-       else {
+
+               /* extra non-digits */
+               if (!p || p == arg || *p)
+                       return -1;
+
+               /* over/underflow */
+               if ((t == HUGE_VALF || t == HUGE_VALL) && errno == ERANGE)
+                       return -1;
+       } else {
                res = strtoul(arg, &p, 0);
-               if (res > UINT_MAX)
+
+               /* empty string or trailing non-digits */
+               if (!p || p == arg || *p)
+                       return -1;
+
+               /* overflow */
+               if (res == ULONG_MAX && errno == ERANGE)
                        return -1;
+
                t = (double)res;
        }
+
        if (p == arg)
                return -1;
        *raw = 1;
@@ -151,9 +198,21 @@ int get_u64(__u64 *val, const char *arg, int base)
 
        if (!arg || !*arg)
                return -1;
+
        res = strtoull(arg, &ptr, base);
-       if (!ptr || ptr == arg || *ptr || res == 0xFFFFFFFFULL)
-               return -1;
+
+       /* empty string or trailing non-digits */
+       if (!ptr || ptr == arg || *ptr)
+               return -1;
+
+       /* overflow */
+       if (res == ULLONG_MAX && errno == ERANGE)
+               return -1;
+
+       /* in case ULL is 128 bits */
+       if (res > 0xFFFFFFFFFFFFFFFFULL)
+               return -1;
+
        *val = res;
        return 0;
 }
@@ -166,8 +225,19 @@ int get_u32(__u32 *val, const char *arg, int base)
        if (!arg || !*arg)
                return -1;
        res = strtoul(arg, &ptr, base);
-       if (!ptr || ptr == arg || *ptr || res > 0xFFFFFFFFUL)
+
+       /* empty string or trailing non-digits */
+       if (!ptr || ptr == arg || *ptr)
+               return -1;
+
+       /* overflow */
+       if (res == ULONG_MAX && errno == ERANGE)
+               return -1;
+
+       /* in case UL > 32 bits */
+       if (res > 0xFFFFFFFFUL)
                return -1;
+
        *val = res;
        return 0;
 }
@@ -180,8 +250,18 @@ int get_u16(__u16 *val, const char *arg, int base)
        if (!arg || !*arg)
                return -1;
        res = strtoul(arg, &ptr, base);
-       if (!ptr || ptr == arg || *ptr || res > 0xFFFF)
+
+       /* empty string or trailing non-digits */
+       if (!ptr || ptr == arg || *ptr)
+               return -1;
+
+       /* overflow */
+       if (res == ULONG_MAX && errno == ERANGE)
                return -1;
+
+       if (res > 0xFFFFUL)
+               return -1;
+
        *val = res;
        return 0;
 }
@@ -193,9 +273,19 @@ int get_u8(__u8 *val, const char *arg, int base)
 
        if (!arg || !*arg)
                return -1;
+
        res = strtoul(arg, &ptr, base);
-       if (!ptr || ptr == arg || *ptr || res > 0xFF)
+       /* empty string or trailing non-digits */
+       if (!ptr || ptr == arg || *ptr)
+               return -1;
+
+       /* overflow */
+       if (res == ULONG_MAX && errno == ERANGE)
                return -1;
+
+       if (res > 0xFFUL)
+               return -1;
+
        *val = res;
        return 0;
 }
@@ -210,10 +300,13 @@ int get_s32(__s32 *val, const char *arg, int base)
        if (!arg || !*arg)
                return -1;
        res = strtol(arg, &ptr, base);
-       if (ptr == arg || *ptr ||
-           ((res ==  LONG_MIN || res == LONG_MAX) && errno == ERANGE) ||
-           res > INT32_MAX || res < INT32_MIN)
+       if (!ptr || ptr == arg || *ptr)
+               return -1;
+       if ((res == LONG_MIN || res == LONG_MAX) && errno == ERANGE)
                return -1;
+       if (res > INT32_MAX || res < INT32_MIN)
+               return -1;
+
        *val = res;
        return 0;
 }
@@ -226,8 +319,13 @@ int get_s16(__s16 *val, const char *arg, int base)
        if (!arg || !*arg)
                return -1;
        res = strtol(arg, &ptr, base);
-       if (!ptr || ptr == arg || *ptr || res > 0x7FFF || res < -0x8000)
+       if (!ptr || ptr == arg || *ptr)
+               return -1;
+       if ((res == LONG_MIN || res == LONG_MAX) && errno == ERANGE)
+               return -1;
+       if (res > 0x7FFF || res < -0x8000)
                return -1;
+
        *val = res;
        return 0;
 }
@@ -240,7 +338,11 @@ int get_s8(__s8 *val, const char *arg, int base)
        if (!arg || !*arg)
                return -1;
        res = strtol(arg, &ptr, base);
-       if (!ptr || ptr == arg || *ptr || res > 0x7F || res < -0x80)
+       if (!ptr || ptr == arg || *ptr)
+               return -1;
+       if ((res == LONG_MIN || res == LONG_MAX) && errno == ERANGE)
+               return -1;
+       if (res > 0x7F || res < -0x80)
                return -1;
        *val = res;
        return 0;