From 697ac63905cb5ca5389cd840462ee9868123b77f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 12 Apr 2013 11:40:57 -0700 Subject: [PATCH] utils: fix range checking for get_u32/get_u64 et all 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 --- lib/utils.c | 136 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 119 insertions(+), 17 deletions(-) diff --git a/lib/utils.c b/lib/utils.c index 5bcdbcfb5..bcd600233 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -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; -- 2.47.2